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.
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
I need the base-URI ( or of the resource) which actually triggers this Operation to include it in the response.
[WebInvoke(Method = "GET", UriTemplate = "users/user",BodyStyle=WebMessageBodyStyle.WrappedRequest)]
[OperationContract]
public bool ReadUserAccount(User user,int TaskID, **string baseURL**)
{
//do something - Include further subsequent Resource Urls with help of Base URL
return result;
}
Understood the operation Context of the WCF Framework.
OperationContext.Current.RequestContext.RequestMessage.Headers.To
reads the URL inside a Service Implementation.
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 created a simple function
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json)]
string Start();
Definition,
public String Start()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize("Check");
}
From browser using Javascript/Jquery,
http://localhost/service1.svc tells me I have created a service and all other info.. Looks fine.
I'm trying to call this using
http://localhost/service1.svc/Start
I get a 400 bad request for this call. I hope I'm not doing something totally wrong here. I should be able to access WCF service from browser right?
I tried looking a lot before I thought of posting. But I'm unable to get this basic thing working is frustrating me.
EDIT & UPDATE
Now I'm at this stage. The service page is telling me that the metadata service is disabled and is asking me to insert the following text
<serviceMetadata httpGetEnabled="true" />
I inserted the text - but still it shows the same text!! This is getting too confusing now..
Try to change POST with GET and restart the request
Works for me. I created WCF Rest Service.
I use URL which looks like http://localhost:8080/Service1/Start
Here is the code:
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Web.Script.Serialization;
namespace WcfRestService1
{
// Start the service and browse to http://<machine_name>:<port>/Service1/help to view the service's generated help page
// NOTE: By default, a new instance of the service is created for each call; change the InstanceContextMode to Single if you want
// a single instance of the service to process all calls.
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
// NOTE: If the service is renamed, remember to update the global.asax.cs file
public class Service1
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json)]
public string Start()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize("Check");
}
}
}