I have a simple REST web service in WCF that is declared as follows:
[WebInvoke(Method = "PUT",UriTemplate = "comptatge/add",RequestFormat = WebMessageFormat.Json,ResponseFormat = WebMessageFormat.Json)]
public void GravaComptatge(MyDataContract contract)
{
...
}
where MyDataContract is a class with simple properties.
Now I send a put Request using fiddler to see if it works OK. In the body I send JSON with the same properties as MyDataContract but it's not working. I get a 400 Bad Request HTTP error. What am I doing wrong here? The service is hosted in a MVC app using ServiceRoute. Other GET services work OK.
This happened to me before, and adding Content-Type: application/json in the request headers was the solution.
Related
Maybe i am mixing up some things but i can not find any questions or documentation on overloading actions for a wcf service recieving SOAP messages.
The goal: I have 3 SOAP messages coming in to my wcf service with the same actionname on the same endpoint. This is fixed and i can not change this.
I would excpect the following wcf interface would work:
[OperationContract(Action = "urn:oasis:names:tc:SPML:2:0:req/active", Name = "addRequest")]
void Add(data data);
[OperationContract(Action = "urn:oasis:names:tc:SPML:2:0:req/active", Name = "modifyRequest")]
void Modify(psoID psoID, modification modification);
[OperationContract(Action = "urn:oasis:names:tc:SPML:2:0:req/active", Name = "deleteRequest")]
void Delete(psoID psoID);
The problem: If i only have one operationalcontract like this my service works but if i have multiple operationalcontracts the following error will popup: `
500System.ServiceModel.ServiceActivationException
I believe it can not have multiple operational contracts with the same actionname. I also believe this should be possible because i am replacing a soap service that does handle all 3 messages with the same actionname. (wcf and soap shouldn't be that far appart?)
I added the operational names in order to fix the problem but without luck.
Any help would be appriciated. Thanks!
The Action property indicates the address the client request, which will be sent to the server and determines the method to be called on the server-side.
Here is a client request captured by the Fiddler.
POST http://10.157.13.69:21011/ HTTP/1.1
Content-Type: text/xml;charset=utf-8
SOAPAction: "urn:oasis:names:tc:SPML:2:0:req/active"
Host: 10.157.13.69:21011
Content-Length: 162
Expect: 100-continue
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
The SOAPAction HTTP header is the Action name of the operation.
The Name property determined the name of the practical method on the client-side.
ServiceReference1.ServiceClient client = new ServiceClient();
client.addRequest(23);
Thereby, unless we change the WCF web service from SOAP web service to Rest API, otherwise, this feature cannot be achieved because the SOAP web service addressing style depends on the Action field.
Namely, we need to change the service to Restful API by using Webhttpbinding.
[OperationContract(Action = "urn:oasis:names:tc:SPML:2:0:req/active", Name = "addRequest")]
[WebGet]
void Add(int data);
Feel free to let me know if there is anything I can help with.
I am using the 2010 SharePoint Lists web service to return a Content Type and it's fields through a c# application. The Library is in a web whose language is set to welsh, but with an alternate language of english set. This means if the internet options in the browser are set to english, the library displays in English.
I have been able to set the Accepts-Language header for requests made using the client object but have not been able to do so for the web service.
Is it possible to see a header on requests made through the SharePoint Web Services, and if so, how?
In case of ASMX web services you could consider the following approach. SoapHttpClientProtocol Class contains GetWebRequest Method that could be used for specifying a custom headers.
Once the proxy class is generated, create a class that derives from it and set custom header as shown below:
public class ListsEx : Lists
{
protected override WebRequest GetWebRequest(Uri uri)
{
var request = base.GetWebRequest(uri);
//Add the Accept-Language header (for Danish) in the request.
request.Headers.Add("Accept-Language:da");
return request;
}
}
where Lists is the name of generated proxy class.
Usage
using (var client = new ListsEx())
{
client.Url = webUri + "/_vti_bin/Lists.asmx";
var reult = client.GetList("Pages");
//...
}
Result
I don't know what type of web services you use. In case of WCF services, you can use: How to add a custom HTTP header to every WCF call?
In case of ASMX web services: Adding SOAP headers to ASMX service requests .
In both cases use Accept-Language header like "Accept-Language:en"
I have a web application using MVC and AngularJS, which connects to a Web API 2 api, that I have set up in a separate project.
Currently I am able to retrieve information from the Api with no problems.
However when I try to do a HTTP Post I am getting no response, originally I was getting a problem with the pre-flight request failing, I have now handled this in my controller, however it does not send the proper request after it has got an OK message back.
I have included my code for the Angular Factory and the C# Controller in the API.
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class RegisterController : ApiController
{
public string Post()
{
return "success";
}
public HttpResponseMessage Options()
{
return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
}
}
var RegistrationFactory = function($http, $q, ApiAddress) {
return function(model) {
// $http.post(ApiAddress.getApiAddress() + '/Register/Post', model.ToString());
$http({
method: "POST",
url: ApiAddress.getApiAddress() + '/Register/Post',
data: model,
headers: { 'Content-Type': 'application/json; charset=utf-8' }
}).success(function(data) {
$location.path("/");
});
}
};
RegistrationFactory.$inject = ['$http', '$q', 'ApiAddress'];
Edit:
I am still not having any joy with this, however I tested in Internet Explorer and it works with no problems at all.
I have got it working in chrome by starting with web security disabled, however obviously this is not ideal as it will not work on a user PC with security enabled.
I see that you have done adaptation for CORS on the server side. But I cannot see any client side (javascript) adaptation. May be you should add the code below before calling the service.
$http.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
Let me know if this fixes the issue. Worked for me in all scenarios :)
It's strange that your GETs work, but your POSTs don't.
I would recommend running the code in Google Chrome with web security enabled (so we can watch it go wrong) and with the F12 Developer Options shown.
Select the Network tab, run your code, and watch what happens when the POST is called.
Does your service return a "200 OK" status, or some other value ?
Does any kind of Response get returned ?
It might be worth trying this, and appending a screenshot of the results in your original question. It might help to identify the cause.
I am still not having any joy with this, however I tested in Internet
Explorer and it works with no problems at all.
Btw, you don't have any single sign-on stuff setup in your company, do you ? We've had issues where IE works fine, but other browsers don't allow single sign-on. Just a thought...
CORS requires a OPTIONS-preflight which has HTTP headers in its response that tell the browser whether it is allowed to access the resource.
E.g. HTTP Response Headers:
Access-Control-Allow-Headers: authorization
Access-Control-Allow-Origin: *
Because you have a custom Options handler in your C# controller, it seems those HTTP headers are not returned, stopping the browser to make the call after the preflight.
Avoid the Options method, and you should be good.
Really struggling with something I hope people here can help with. I'm writing a RESTful API in Web API 2. Whenever I send a request to this service, the response is consistently being sent with a Content-Type of text/plain. Obviously this is no good, my response needs to be Content-Type of application/json. I've tried a few suggestions that I found from Google but I don't think I'm understanding the whole picture.
Is there something special I need to do in order to have my web service respond with application/json content? Note that I want this to work globally across the whole app, so I'm not after a way to modify a given response and set its content type - I want this to be a default behaviour for the whole web service: If a request contains an Accept header for application/json I want my web service to return that Content-Type instead of text/plain.
Edit to clarify:
My response contains an object called "responseData" that should be serialized into JSON and included in the body. I'm currently putting together my response like this:
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, responseData);
return response;
responseData is a POCO. This get's correctly serialized as JSON and returned in the response - the only missing part is the Content-Type which is incorrectly set to "text/plain". I could manually change this on every single response I compose, but I'm wanting to configure this on a global level.
OK, assuming that your responseData is a string, the Content-type header will be text/plain when you create the HttpResponseMessage. Doesn't matter what the contents of the string are, since no attempt is made to determine this.
The solution is to create the appropriate Content object for your message, initialized with the media type you're returning:
HttpResponseMessage response = new HttpResponseMessage()
{
Content = new StringContent(
responseData,
Encoding.UTF8,
"application/json"
)
};
There are other methods that amount to returning a particular object type and letting the API libraries serialize to JSON or XML for you as required. I prefer to let the framework do the work for me where possible, but this is how you'd achieve it with a string you've created yourself.
For a strict JSON-only result, remove the XML formatter from the WebAPI configuration and return your POCO.
In App_Start\WebApiConfig.cs, add the following to the WebApiConfig.Register method:
config.Formatters.Remove(config.Formatters.XmlFormatter);
And for your API:
public class MyObject
{
public bool result;
public string reason;
}
public class TestController : ApiController
{
public MyObject GetData()
{
MyObject result = new MyObject { result = "true", reason = "Testing POCO return" };
return result;
}
}
I ran this up and requested /api/Test from Chrome, which doesn't even mention application/json in the Accept header. Here are the response headers up until it hits Content-Type:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
And the body:
{"result":true,"reason":"Testing POCO return"}
Since I disabled XML it defaulted to JSON.
Add the following to Global.asax file.
protected void Application_Start()
{
JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new IsoDateTimeConverter());
var jsonFormatter = new JsonNetFormatter(serializerSettings);
jsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
GlobalConfiguration.Configuration.Formatters.Insert(0, jsonFormatter);
}
Another possible source of the issue described is that there may be an authorization redirect in play as was the case for us when one of the engineers thought to re-use user authentication for an api.
This means incoming requests were being redirected to a login page which was the text/html response that couldn't be parsed by ReadAsync<>. A silly mistake to be sure, but not an easy one to spot.
The solution in that case was to remove the user authentication and implement HMAC based authentication for the api.
I have a REST service that gets a GET request, and I want it to be able to redirect to one of three urls, without having to send an http 302 error and the new url.
[OperationContract(Name = "MyService")]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "/myservice/{option}")]
public System.IO.Stream MyService(String option)
This is how I have it defined, but when I look at WebOperationContext.Current.OutgoingResponse I don't have a method for redirect.
Is there any way to do this automatically? The reason I am hoping to do this is that this webservice may be called by a program, and it would be simpler on the program to not have to catch the 302 error and then do the redirect manually.
It appears the correct way is to follow this:
http://christopherdeweese.com/blog2/post/redirecting-from-a-wcf-rest-service
and do this:
WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Redirect;
WebOperationContext.Current.OutgoingResponse.Location = "/someOtherPage.aspx";
return null;
I just hope to find another solution.
Redirect is always client side feature. The server just informs client that the resource is elsewhere. There is nothing like server side redirect except completely hiding this redirection into separate service call from your current operation.
Btw. REST is about uniform interface and redirects (3xx) are part of this interface so if you create REST service and you want such feature you should use it in common way. REST client is responsible for handling the uniform interface correctly.