Consume REST service in MVC 6 - c#

I need help. I am creating an MVC 6 application and stuck on the part where I should consume JSON from a REST service. I could not find the way I should connect my project to the service and then consume it.
There is no way to add service reference as in previous versions and I could not find it ASP.NET 5 documentation where the policy for using 3rd party services in MVC 6 is regulated. Did someone had the same issue?

To get the JSON from RESTful service in MVC you just make a http call to the service API and parse the response with model that contains the properties of the json. You can read more about that here:
http://bitoftech.net/2014/11/18/getting-started-asp-net-5-mvc-6-web-api-entity-framework-7/
An example would look like something like this:
public YourModel MakeRequest(string requestUrl)
{
try
{
HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception(String.Format("Server error (HTTP {0}: {1}).", response.StatusCode, response.StatusDescription));
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
var responseObject = serializer.Deserialize<YourModel>(response);
return responseObject;
}
}
catch (Exception e)
{
// catch exception and log it
return null;
}
}

There is no "add a service reference" feature for REST services in ASP.NET (like it is for WSDL described ones).
There never was. You consume the service as you would consume it directly from your browser using javascript.
The difference is that you need to write similar code in .NET using any http client (HttpClient or RestSharp are the most popular).
There are some efforts to make the REST services easier to consume. Swagger is the tool I use to describe my API. It also allows to generate client code for various languages.

Related

How to handle a WEB API that has different responses types for success and failure?

I'm working on a WEB API application made with .NET Framework. Right now i'm working alonside a supplier to help and integrate their WEB API with our system. One of their latest change broke my code. Since i'm using RestSharp library i'm expecting the response to always correspond to a specific type of object, independently if with was a success or failure from their side.
IRestResponse<T> response = await restClient.ExecuteAsync<T>(request);
If the response is successful they will send a json response like this
{message:"", jobNr:"2312312", status:"1"}
And then they changed the code, so that if any request input was wrong they will send a list of errors, so the response will be like this:
[{code:100, message:"contact phone is wrong"},{code:101, message:"the email is not provided"}]
I don't like this approach, since i think they should give a response for errors like this:
{errorMessages:[{code:100, message:"contact phone is wrong"},{code:101, message:"the email is not provided"}]}
But since it is not in my hands. How should i deal with it? Just parse the json response and assing to different types of objects? Thanks.
Yes, the response should be parsed manually.
Assuming RestSharp is still in charge and the original API returns errors entitled with BadRequest status code, below extension tries to deserialize the content as an array of errors (a type consists of a code and a message just like mentioned in question).
public static Error[] AsErrors(this IRestResponse response)
{
var empty = new Error[] { };
try
{
return response.StatusCode == System.Net.HttpStatusCode.BadRequest
? JsonSerializer.Deserialize<Error[]>(response.Content)
: empty;
}
catch (JsonException)
{
return empty;
}
}
Considering the NormalContent is what you truly expect as response, the usage will be:
// after creating client and request ...
var response = client.Execute<NormalContent>(request);
var errors = response.AsErrors();
if (errors.Any())
{
//Deal with errors
}
else
{
//response.Data gets populated with RealResult
}
NOTE: Using the procedure as an extension depends on how common is the response pattern in your case.

json with C# in a WCF service?

I am looking at adding SMS abilities to my WCF service. I found a cheap SMS service called Penny SMS.
Their interface supports json. But I have no idea how to call it in my WCF service.
Here is the interface/example:
Sample JSON-RPC Request
{ "method": "send",
"params": [
"YOUR_API_KEY",
"msg#mycompany.com",
"5551231234",
"Test Message from PENNY SMS"
]
}
How would I call that with C# from a WCF service? What I am looking for is a way to wrap this into a method call. Something like:
StaticSMSClass.SendSMS("1234567890", "My Message to send");
Note they also support an XML-RPC API if that is more doable from C#.
UPDATE: I made a stab at creating a call myself, but it did not work. I am going to post my attempt in a separate question and see if anyone has a way to do it.
You need to send a HTTP POST with the JSON message to the remote server. You can do this with HttpWebRequest. You either build the JSON manually (the messages seem simple), or define types for it and use a JSON serializer.
MSDN has an example, for your case it would look something like (untested):
string json = // Your JSON message
WebRequest request = WebRequest.Create ("http://api.pennysms.com/jsonrpc");
request.Method = "POST";
var postData = Encoding.UTF8.GetBytes(json);
request.ContentLength = postData.Length;
request.ContentType = "text/json";
using(var reqStream = request.GetRequestStream())
{
reqStream.Write(postData);
}
using(var response = request.GetResponse())
{
// Response status is in response.StatusCode
// Or you can read the response content using response.GetResponseStream();
}
See my answer to the question "Client configuration to consume WCF JSON web service" for how the create a JSON client with WCF.
The answers so far are good, but one additional thing you can take advantage of (since you are within a WCF service) is the use of DataContractJsonSerializer.
In particular, I refer to how you actually populate your JSON in the first line of driis's example.
string json = // Your JSON message
Now, one of the best ways to do this may be to create a new class with these members:
[DataContract]
class SomeType
{
[DataMember]
string method;
[DataMember]
string[] params;
}
Then, just create an instance of SomeType every time and serialize it to JSON using the DataContractJsonSerializer every time you want to send over a piece of data. See http://msdn.microsoft.com/en-us/library/bb412179.aspx for how to use the DataContractJsonSerializer stand-alone.
Hope this helps!
Check the WCF REST API. They serve JSON, maybe they also can send JSON (in intra WCF solution it works). Maybe you have to construct the contract in wsdl to get the service running but maybe it works out.

Is there a C# or .NET class to handle HTTP Content Negotiation?

Is there a C# or .NET class to handle HTTP Content Negotiation with a User Agent?
I would like to be able to supply a list of acceptable Content Types, and have those negotiated with the browser to find the best match.
I recently wrote a content negotiation library in F#.
I blogged about it here.
I think the word user agent is a bit off in your question but if you want to build request a certain source (lets say a restfull api). You can use the WCF Rest Starter kit (http://wcf.codeplex.com/) to specify the type of content you want or accept:
HttpClient client = new HttpClient(new Uri("http://restfull/api/"));
//this is XML but could be JSON or whatever the API can supply
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
var response = client.Get(path);
if (response != null)
{
response.EnsureSuccessStatusCode();
//this will be XML
string xml = response.Content.ReadAsString();
}

How can I make a SOAP call in C# with an old WSDL+XSD and current Web Service location?

My question is similar to this one: need to call soap ws without wsdl except that my application does not use Spring so the answer was not helpful.
Here's what I have:
A web service that only accepts SOAP requests
A current endpoint URL for the web service
An outdated wsdl and xsd file
An outdated sample SOAP request file
What I need to do is:
Successfully make a SOAP request using some combination of the above.
I've tried to approach this from two different angles, with no luck so far. My background is familiarity with web services with POST and GETs, but not SOAP. After googling 'C# SOAP', I wrote the following code:
void soap(String xmlfile)
{
Stream outputStream = null;
StreamReader reader = null;
WebResponse response = null;
try
{
string text = System.IO.File.ReadAllText(xmlfile);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://misapi.ercot.com/2007-08/Nodal/eEDS/EWS");
request.PreAuthenticate = true;
X509Certificate ercotCert = X509Certificate.CreateFromCertFile("D:\\Amigo\\WebSite1\\Nodal_Test_Cert.cer");
request.ClientCertificates.Clear();
request.ClientCertificates.Add(ercotCert);
ServicePointManager.ServerCertificateValidationCallback +=
new System.Net.Security.RemoteCertificateValidationCallback(customValidation);
request.Credentials = CredentialCache.DefaultNetworkCredentials;
// I don't actually have a SOAPAction, but have tried adding a fake one just to see
//request.Headers.Add("SOAPAction", "http://www.ercot.com/Nodal/Payload");
request.Method = "POST";
request.ContentType = "text/xml;charset=\"utf-8\"";
request.ContentLength = text.Length;
StreamWriter writer = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
writer.Write(text);
writer.Close();
response = request.GetResponse();
outputStream = response.GetResponseStream();
reader = new StreamReader(outputStream);
Response.Write(reader.ReadToEnd());
}
catch (WebException e)
{
// This is where it ends up, with Status="ProtocolError"
}
catch (System.Web.Services.Protocols.SoapException soapE)
{
// Never gets in here
}
catch (Exception e)
{
// Never gets in here
}
finally
{
if (outputStream != null)
outputStream.Close();
if(reader != null)
reader.Close();
if(response != null)
response.Close();
}
}
private static bool customValidation(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
return true;
}
This yields a 500 Internal Server Error. It throws a WebException which contains no other message or inner exception, but the Status is 'ProtocolError'. I have tried other permutations including using XmlDocument and other content types, but none have worked.
The other thing I've tried is using "Add Web Reference" in Visual Studio. Putting in the endpoint URL doesn't work and gives a soap fault. If, instead, I point to the local copy of my outdated wsdl, then it will add the WebReference but won't let me use it due to numerous errors that I cannot correct. My guess is that these errors are due to the wsdl being outdated, things like the namespace not matching or being unable to find things at the URLs included. If I replace those URLs with the current web service endpoint URL, it still does not work.
If anyone could pinpoint a problem in my code, or direct me on how to get the "Add Web Reference" working, I would be greatly greatly appreciated!
Thanks in advance!
SOAP is just the format for the payload that you POST to the service, that's all. There's a defined specification for fields and namespaces and such, and there are different SOAP versions, but there's really not that much to it. (Other than it being remarkably verbose for it's usage, but that's a different topic.)
You need to start with a current WSDL. If you know you're working WSDL is outdated, that means that something the webservice is expecting (required) or could work with (optional) is different from your definition. And the WSDL is your contractual gateway into the webservice. You need to get a current WSDL.
As luck would have it, when I navigate to https://misapi.ercot.com/2007-08/Nodal/eEDS/EWS/?WSDL (which I derived by appending "?WSDL" to the end of the url), after skipping past the certificate error, bingo -- there's the WSDL used by the service. You can either (a) save it locally, or (b) reference it directly from Visual Studio in building a web service client. Because of the cert error, I would recommend saving it locally and building from there.
This should get you started.

How do I test connectivity to an unknown web service in C#?

I'm busy writing a class that monitors the status of RAS connections. I need to test to make sure that the connection is not only connected, but also that it can communicate with my web service. Since this class will be used in many future projects, I'd like a way to test the connection to the webservice without knowing anything about it.
I was thinking of passing the URL to the class so that it at least knows where to find it. Pinging the server is not a sufficient test. It is possible for the server to be available, but the service to be offline.
How can I effectively test that I'm able to get a response from the web service?
You could try the following which tests the web site's existence:
public static bool ServiceExists(
string url,
bool throwExceptions,
out string errorMessage)
{
try
{
errorMessage = string.Empty;
// try accessing the web service directly via it's URL
HttpWebRequest request =
WebRequest.Create(url) as HttpWebRequest;
request.Timeout = 30000;
using (HttpWebResponse response =
request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception("Error locating web service");
}
// try getting the WSDL?
// asmx lets you put "?wsdl" to make sure the URL is a web service
// could parse and validate WSDL here
}
catch (WebException ex)
{
// decompose 400- codes here if you like
errorMessage =
string.Format("Error testing connection to web service at" +
" \"{0}\":\r\n{1}", url, ex);
Trace.TraceError(errorMessage);
if (throwExceptions)
throw new Exception(errorMessage, ex);
}
catch (Exception ex)
{
errorMessage =
string.Format("Error testing connection to web service at " +
"\"{0}\":\r\n{1}", url, ex);
Trace.TraceError(errorMessage);
if (throwExceptions)
throw new Exception(errorMessage, ex);
return false;
}
return true;
}
You are right that pinging the server isn't sufficient. The server can be up, but the web service unavailable due to a number of reasons.
To monitor our web service connections, I created a IMonitoredService interface that has a method CheckService(). The wrapper class for each web service implements this method to call an innocuous method on the web service and reports if the service is up or not. This allows any number of services to be monitored with out the code responsible for the monitoring knowing the details of the service.
If you know a bit about what the web service will return from accessing the URL directly, you could try just using the URL. For example, Microsoft's asmx file returns a summary of the web service. Other implementations may behave differently though.
The tip: create a interface/baseclass with method "InvokeWithSomeParameters". The meaning of "SomeParameters" should be a "parameters which 100% does not affect any important state".
I think, there are 2 cases:
Simple webservice, which does not affect any data on server. For example: GetCurrentTime(). This web service can be called without parameters.
Complex webservice, which can affect some daty on server. For example: Enlist pending tasks. You fill-up parameter with values which 100% throws a exception (resp. does not change affect pending tasks), if you got some exception like "ArgumentException", you know the service is alive.
I don't think, this is most clear solution, but it should works.
How about opening a TCP/IP connection to the port used by the webservice? If the connection works, the RAS connection, the rest of the network and the host are all working. The webservice is almost certainly running too.
If it is a Microsoft SOAP or WCF service and service discovery is allowed, you can request the web page serviceurl + "?disco" for discovery. If what is returned is a valid XML document , you know the service is alive and well. A non-Microsoft SOAP service that does not allow ?disco will probably return valid XML too.
Sample code:
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL + "?disco");
request.ClientCertificates.Add(
new X509Certificate2(#"c:\mycertpath\mycert.pfx", "<privatekeypassword>")); // If server requires client certificate
request.Timeout = 300000; // 5 minutes
using (WebResponse response = request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader sr = new StreamReader(stream, Encoding.UTF8))
{
XmlDocument xd = new XmlDocument();
xd.LoadXml(sr.ReadToEnd());
return xd.DocumentElement.ChildNodes.Count > 0;
}
If the web server is present, but the service does not exist, an exception will be raised quickly for the 404 error. The fairly long time-out in the example is to allow a slow WCF service to restart after a long period of inactivity or after iisreset. If the client needs to be responsive, you could poll with a shorter timeout until the service is available.

Categories

Resources