I am working on a self-hosted WCF service with some GET and POST methods,
For Example
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
public string HelloWorld(){
....
}
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped)]
public string GetMessage(string username){
....
}
when accessing those services on the client side which is hosted on different domain, I have got the following error
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:57805' is therefore not allowed
access. The response had HTTP status code 400.
After researching on the Internet, I figured that the error can be resolved by putting the following codes in each WCF function
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
{
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Header", "Content-Type, Accept, SOAPAction");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Credentials", "false");
}
Now this block of code is working great for a GET method, so I can see there is "Access-Control-Allow-Origin" added into the response header. However it does not work for a POST method somehow as the response header has no change at all.
Does anyone have an idea why it is not working for a POST method?
I have changed the GetMessage to be a GET method, the response header worked immediately but not when I changed it back to POST
The problem is resolved!!
The code works great for both GET and POST, however the web service throw the following error for my POST function, therefore it causes a failure.
The OperationFormatter could not deserialize any information from the
Message because the Message is empty (IsEmpty = true).
By changing the BodyStyle for the function to WrappedResponse, the error gone and the function can be accessed outside the domain
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedResponse)]
Booking CreateNewBooking(int divisionId);
Related
I am trying to access a WCF service from a browser. I am sending a GET request from my browser to a WCF service. For your reference, the detail is as follows of a WCF service is as follows.
The Service Contract definition is as follows:
[ServiceContract]
public interface IBZTsoftsensor_WcfService {
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, UriTemplate = "json/?inputModel={inputModel}")]
string ExecuteModelJson(string inputModel);
}
And the implementation of this interface is as follows:
public string ExecuteModelJson(string inputModel){
try
{
BZTsoftsensor_ModelInput input = JsonConvert.DeserializeObject<BZTsoftsensor_ModelInput>(inputModel);
var results = this.ExecuteModel(input);
return JsonConvert.SerializeObject(results);
}
catch (Exception ex)
{
return ex.Message;
}
}
When I am accessing this WCF Service from browser with the URL
http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary1/Service1/json/?inputModel={"Pyro":"30.0","O2":"20.0"}
My WCF service is responsing successfully.
However, Using the above URL, when I am configuring GeTHTTP Nifi processor, the processor is erroring illegal characters in GET request URL.
Could you please advise me - what changes I have to made in GET URL , while using GetHTTP processor?
You may need to encode your inputModel parameter, you can use the urlEncode method of NiFi Expression Language:
https://nifi.apache.org/docs/nifi-docs/html/expression-language-guide.html#urlencode
Try this as the URL property:
http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary1/Service1/json/?inputModel=${literal("{\"Pyro\":\"30.0\",\"O2\":\"20.0\"}"):urlEncode()}
Alternatively since your URL is fixed you can just encode it using an online encoding tool, which gives something like this:
http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary1/Service1/json/?inputModel=%7B%22Pyro%22%3A%2230.0%22%2C%22O2%22%3A%2220.0%22%7D%20
Suppose I implement a WCF REST service with the following contract.
[ServiceContract]
interface INotesService
{
[OperationContract]
[WebInvoke(Method = "GET",
UriTemplate = "notes/{id}")]
Note GetNote(string id);
[OperationContract]
[WebInvoke(Method = "GET",
UriTemplate = "notes")]
IEnumerable<Note> GetNotes();
}
Now, I have an HttpModule in the pipeline to do the authorization, but that code needs to know to which method the request will be dispatched. How do I find the signature of the method that will be invoked by WCF?
I think you should use IDispatchOperationSelector.
See also this article: WCF Extensibility – Operation Selectors
Even though the other answer put me on the right path, it did not really answer my question.
I later found this link which gave me a working solution:
http://tech.blog.oceg.org/2009/04/authorizing-rest-calls-in-wcf.html
However, I found it to be more complex than needed. In .NET 4.5 (which is what I'm on) you can do the following.
I registered my ServiceAuthorizationManager from the ServiceHost.ApplyConfiguration override.
this.Authorization.ServiceAuthorizationManager =
new MyServiceAuthorizationManager();
Then, in its CheckAccessCore method, I called the method below to give me the name of the method to which the request will be dispatched.
private string GetOperationName(OperationContext operationContext)
{
return messageProperties["HttpOperationName"] as string;
}
We have created a WCF webservice. We have created two operation contracts like this:
public interface IRestServiceImpl
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "getID/{id}")]
File getID(string id);
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "auth")]
ResponseData Auth(RequestData rData); }
As you can see I have a Get and Post method. This works fine, but if I want to set the response format of my GET service,I have to use XMLSERIALIZERFORMAT tag.If I add this and then try to hit POST service, I get Error:400 "Bad Request Error". How should I set the response of my GET method in the same service.
I have tried adding another service 'Service2.svc' in the project where I have kept only GET methods and 'Service1.svc' has only POST services. In the interface of Service2, i have used XMLSERIALIZERFORMAT but still not able to hit POST service. I think I have to use DATACONTRACTSERIALIZER. But I dont know how to set the attributes in that.
Can anyone please help me out with this?
Thanks
Charan
If you want your GET to send a Response in XML then below setting on your GET method should be enough.
ResponseFormat = WebMessageFormat.Xml
You dont need to use XmlSerializerFormat. Just try to browse to your service in IE and you should see the response from your GET Method would be in XML format.
Regarding getting a Bad Request on your POST try to see on how the request body is being sent to your method. To see your request body try using tools like Fiddler to inspect your request and response. To debug the cause of Bad Request try enabling tracing on your service.
How to enable tracing on your Service
I have a stock WCF Rest application (default Web.config, Web Routing). I am unable to get the WCF framework to auto de-serialize the request stream into typed objects. I have a service with a method sig in the form...
[WebInvoke(Method = "POST",
UriTemplate = "",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json)]
MethodA(FirstParam first, SecondParam second)
If I initiate a request from fiddler or jQuery using $.ajax I get a 400 Bad Request error. I've done plenty of searching and found that changing the method sig to use a System.IO.Stream allows the method to be executed, however it also adds the overhead of de-serializing the objects.
The raw request body is as follows
{
"first":"{\"p1\":\"p1 value\",\"p2\":\"p2 value\",\"p3\":100\"p4\":null}",
"second":"{\"p1\":\"p1 value\"}"
}
Yeh the application doesn't even break into the service itself unless the method has either a Stream, or no arguments. There is only 1 post method in this service, the other is a GET method which is working correctly.
I've used http://www.codeproject.com/KB/ajax/jQueryWCFRest.aspx as a reference implementation, but have been unable to get it to work on this solution.
Is there something that I'm missing here that hopefully someone else can see?
Leon
Bleh... the problem turned out to be the way the request was serializing values!
{
"first":"{\"p1\":\"p1 value\",\"p2\":\"p2 value\",\"p3\":100\"p4\":null}",
"second":"{\"p1\":\"p1 value\"}"
}
Should have been without the escaped quotes....
{
"first":"{"p1":"p1 value","p2":"p2 value","p3":100"p4":null}",
"second":"{"p1":"p1 value"}"
}
The reason this was happening was JSON.stringify was being called not only on the wrapped request parameters, but on each parameter as well.
I am writing a .NET app that will talk to JSON-based API to pull/push data. I saw similar question asked before:
Consuming a RESTful JSON API using WCF
but I need little more information on the same subject. Here is JSON that I have to send in request:
{"login":{"password":"PASSWORD","username":"USERNAME"}}
and response JSON will be something like:
{"response":{"status":"OK","token":"o9b0jrng273hn0"}}
Here is what I came up with:
[ServiceContract]
public interface ITestApi
{
[OperationContract]
[WebInvoke( Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/login"
)]
LoginResponse Login( LoginRequest login );
}
where LoginRequest has username and password properties and LoginResponse has token property.
When I call the api, request is successful and I get the response back as expected ( I verified this with Fiddler). But WCF is not able to create LoginResponse object for me. it is always null. I believe I am doing somethign wrong, can someone please point me out what I have to do to get this right?
Is this the right way to create a JSON-based REST service client? I am using RESTful api first time, so I do not have more knowledge about it.
Your LoginResponse class should look like something this:
[DataContract]
public class LoginResponse
{
[DataMember]
public string token { get; set; }
}
It needs to be decorated with the DataContract and DataMember attributes so the serializer (DataContractJsonSerializer in the case of JSON ) knows how to serialize it.
EDIT:
Also, your client should be configured to use webHttpBinding and the endpoint behavior should be configured to use webHttp, as in the following example.
Go get the Microsoft.Http client library from the lib folder in this project or from thw WCF REST Starter Kit. Using this you can do:
var client = new HttpClient();
var content = HttpContent.Create("{'login':{'password':'PASSWORD','username':'USERNAME'}}", "application/json");
var response = client.Post("http://service.com/login",content);
var jsonString = response.Content.ReadAsString();
If you don't want to read the Json as a string and parse using something like Json.Net, and you prefer to use DataContracts, you can do:
var loginResponse = response.Content.ReadAsJsonDataContract<LoginResponse>();
Using WCF Channels on the client to deal with REST services is just going cause you far more pain than you really want. You are much better to just stick with plain HTTP.