How to call a microservice in .NET - c#

I've created a very simple REST microservice that receives information about an email and sends it. The microservice send method looks something like this:
//EmailController
[HttpPost]
public IHttpActionResult Send(Email email)
{
// send email via exchange
}
Now in my application, I call it using RestSharp like this:
var client = new RestClient("http://localhost:51467/api/");
var request = new RestRequest("email/send", Method.POST);
request.RequestFormat = DataFormat.Json;
dynamic obj = new ExpandoObject();
obj.FromAddress = from;
obj.ToAddress = to;
obj.Subject = subject;
obj.Body = body;
request.AddBody(obj);
client.Execute(request);
Questions I have:
Is this the best way to do the call? Obviously i'll later have to add error handling etc, but I'm talking more the way I'm using RestSharp to do the call.
I'm finding it a bit uncomfortable that my app needs to kind of know what object the microservice expects to receive - there's no sort of definition/interface/contract that it uses to know for sure. Is this generally accepted as being ok for REST or should I implement some sort of interface that my app has so it can call my microservice in a bit more of a defined way. Is that even something possible with REST?
Thanks for any help!

REST services do not have a schema or WSDL type of function to define the format of the service. This is what makes them more light weight compared to traditional web services.
There is something called WADL, or Web Application Description Language, but this is not really a standard, and isn't widely supported. It's also quite controversial as there are many that feel it's not needed.
http://en.wikipedia.org/wiki/Web_Application_Description_Language
Also see this discussion on Programmers
https://softwareengineering.stackexchange.com/a/133693/4368

I know this is super old but I couldnt help but answer for the sake of currency.
There are two ways of communicating an API contract with other .net services which I find particularly useful.
Ship a nuget package with the contracts (Interfaces describing responses) and possibly some call logic to methodise your api calls
Use swagger to describe your api (seems to have come out as the API description winner, Swashbuckle makes it seamless in .net) and then either hand code the bits you need at the caller or use a codegen
I quite often do both, swagger is also nice for documentation and other language compatibility, and its good practice to be formal about your contracts and backward compatibility.

I would use ASP.NET Web API client libraries. It works with any REST API, whether its coded using .NET or some other framework.
Look here for details: http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client
Nuget package: Microsoft.AspNet.WebApi.Client

I typically don't bother with extra client Libraries like RestSharp. I feel that the purpose of REST is to stay as close to gold old HTTP as possible, negating the need for anything other than HttpWebRequest/Response. Working with the request/responses directly gives great control and encourages you to think about what's actually going on instead of abstracting everything away like you would with a traditional WCF or ASMX service.
For microservices I've built in the past I've kept the request and response objects within separate libraries and I've the distributed the source to other Developers within my organisation to give them a leg up in calling the service but it probably wouldn't be practical for external consumers; again I guess the point of going for a microservice over a full scale WCF service is that by their nature the request/responses being passed around are small and simple. I also felt a little uncomfortable with this practice at the start; however when I started getting really responsive web apps calling microservices with javascript (usually jquery) just as easily as traditional .NET ones I started seeing the potential for some really good integration of our internal systems. Eventually our intranets were providing actions and views into business applications that weren't possible previously.
HttpWebRequest webRequest = WebRequest.Create("http://localhost:51467/api/email/send") as HttpWebRequest;
webRequest.Method = "POST";
webRequest.Credentials = CredentialCache.DefaultCredentials; //or account you wish to connect as
webRequest.PreAuthenticate = true;
webRequest.ContentType = "application/json"; // or xml if it's your preference
string jsonData = Newtonsoft.Json.JsonConvert.SerializeObject(requestObject);
using (StreamWriter streamWriter = new StreamWriter(webRequest.GetRequestStream()))
{
streamWriter.Write(jsonData);
streamWriter.Flush();
streamWriter.Close();
}
HttpWebResponse webResponse = webRequest.GetResponse() as HttpWebResponse;
if (webResponse.StatusCode != HttpStatusCode.Accepted)
throw new ApplicationException("Unexpected Response Code. - " + webResponse.StatusCode);
string response;
using (System.IO.StreamReader readResponse = new System.IO.StreamReader(webResponse.GetResponseStream()))
{
response = readResponse.ReadToEnd();
}
//swap out for regular xml serializer if you've used xml
dynamic responseObject = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(response);
Also another tip, if you're working with web api, I'd really suggest adding in the web api help pages and test client. You won't have the automatically generated wsdl you get with WCF and ASMX but you can get some really nice documentation about your microservice for other developers (even better in my opinion that auto generated proxy classes) and a test harness that lets to exercise the service from your browser
https://github.com/wuchang/WebApiTestClient
https://www.nuget.org/packages/Microsoft.AspNet.WebApi.HelpPage/

Related

How to Handle POST web request on server side?

I am using Soap API (asmx) as web service for my project and I need to send a POST request with JSON data. I saw a code snippet that shows how to send the POST request using HttpWebRequest. This is the code.
string url = "http://myserver.rocket.com.my/WebService1.asmx/AddCompany";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = JsonConvert.SerializeObject(company);
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
My problem is, I am not very sure how to handle the request on server side. Can get any example or guide on how to obtain the json content from the stream?
Well, this is a very big topic but to keep things simple, you could take shelter with one of the existing server-side frameworks.
This also means that you need to select the right kind of programming language. My favourite language is Python but you could very well go with Java, Scala, Ruby, Pearl, PHP, GoLang ... the list is quite big.
If you speak Python then I strongly suggest you start with a simple web framework/library like Python Flask.
Just to answer some other things which will follow, I would strongly recommend you to catch up on MVC/MVP (Model View Controller/Presenter) which is a design pattern used for creating and consuming views.

Adding service reference for Asp.Net webservice

EDIT:
I'm based on some comments that have been deleted, I guess I need to add a service reference and create a instance of the webservice object in the client application to pass the dataset. I haven't been able to add the service reference. When the service runs, it gives a 403 forbidden error, and has done so since I first created the project. I thought this was fine because the apicontroller methods can still be accessed with an HTTP GET, but I have no way of actually sending objects to the service, and can't create the service reference. The service and the client are in separate projects. At this point even a link to a decent tutorial would help. I've found a ton of stuff for creating a full site with a few functions accessed in jquery, and plenty of stuff that includes how to send a post in C#, but nothing that combines both sides.
I saw this question asking a how to do a similar thing. Is there any difference in the client side code I have in c# and the javascript in the question?
EDIT2:
I tried using a memory stream to look at the request content to see if the entire dataset was being transferred. Its only picking up 4000 or so bytes out of 350000 being transferred. I assume this is why the dataset isn't availalbe in teh webservice parameter. but I'm not sure how to continue.
Original:
I'm building a webservice to handle the database calls for my client application. This isn't publicly facing, so I'm fine with passing a dataset instead of a custom model. Heres the client code:
public static void TestSendToDatabase(DataSet Products)
{
string xml = ToXML(Products);
byte[] bytes;
bytes = System.Text.Encoding.ASCII.GetBytes(xml);
StringBuilder urlBuilder = new StringBuilder(string.Format("{0}{1}", BaseUrl, "WalmartProducts/Update"));
string url = urlBuilder.ToString();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/xml";
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = bytes.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(bytes,0,bytes.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
And the service code:
public class WalmartProductsController : ApiController
{
[HttpPost]
[ActionName("Update")]
public object UpdateWalmartProducts([FromBody] byte[] bytes)
{
string xml = System.Text.Encoding.ASCII.GetString(bytes);
DataSet productsFromClient = LoadFromXMLString(xml);
DataUpdater.UpdateWalmartData(productsFromClient.Tables[0]);
return DataUpdater.GetProducts();
}
The byte array is empty in the web service. I'm sure that I'm mixing methods that shouldn't be mixed, but I've gone through at least thirty articles trying to resolve this, and it feels like each one has a completely different method. The webservice is currently returning the dataset in an xml format, so I would prefer to stick with xml over json.
This is not a complete answer, but perhaps it is a starting point. .NET supports two main techniques for writing Web Services. The first is an older technique using .asmx files. This approach is generally called the SOAP approach, and Visual Studio generates signatures of your methods in a .wsdl file. Because the signatures are exposed, you can then ask Visual Studio to create a Web Reference file for you. This web reference exposes all the Web Services as simple classes and methods, hiding all the complexity of the communication across the web service. Any object that can be serialized, including the DataSet object, can be included as a parameter to these web methods, and .NET will take care of serializing and deserializing these objects as they pass across the HTTP boundary. I believe that MS then encapsulated a number of different communication technologies inside of a product they called WCF, which was supposed to allow you to use configuration to choose whether you wanted to use HTTP for communication or TCP/IP.
The downside to this approach is that if you use any MS class in your API's, you have effectively tied your product to MS, and it is then very difficult for any non-MS client to communicate with your web service. The DataSet object is an extremely complicated one, and I'm under the opinion that it would be quite impractical to attempt to write your own serialization/deserialization methods to send a DataSet.
The other Web Service approach that is gaining popularity is using REST API's. Recently, MS added support for these, and the ApiController is one of the starting points. If you google "ASP.NET REST API Tutorial" you should find all kinds of examples. However, with this approach I would discourage you from using the DataSet class. I've had some success with classes such as a Dictionary, provided the object classes you put into the dictionary all resolve down to fairly simple components. Attempting to use a complex MS class like DataSet is likely to lead to a lot of frustration, and will yield a Web Service that very few clients can use.

Testing a REST Logging Web Service using C#

I've created a pretty basic REST Web Service in VS2012 using C#. The approach I've taken is seen below in one example:
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "OpenSession/{key}/{source_userid}/{source_id}/{source_version}/{source_ip}")]
string OpenSession(string key, string source_userid, string source_id, string source_version, string source_ip);
The code works just fine and the service is up and running. I get responses, the tokens are handed out, etc. I figured wrapping the data in the URL was just fine as the service is built for logging, so in the end, calls would be (for example):
www.service.site/service.svc/2/5/12/HELLO
(BTW if there's a better way to do this while keeping it a REST service please let me know)
The problem I have is... how do I test this properly? I need to simulate 1,000 concurrent hits to this service and have built a custom C# Windows Application to do this, but I'm encountering a number of problems.
First, I have no idea how to use HttpWebRequest and the stream readers/writers to send/receive data properly in a manageable format. I see The requests have GET and PUT methods, etc. but I honestly can't seem to make heads or tails of separating the post data vs. the URL information. AFAIK I'm not really posting any data as all my data is embedded in the URL request itself; is this correct?
Also, I have no idea what "content type" to set the HttpWebRequest to in order to be compatible with my Operation Contract (I can see the enumeration of JSON but what's the "text" supposed to be?)
And on top of that, HttpWebRequest is monstrously slow. When I open a URL directly to the service (e.g. "http://localhost:51849/Scribe.svc"), it's fast, but the second I try to call a method (e.g. ""http://localhost:51849/Scribe.svc/GetStatus"), I get a 1.5-2 second delay (and I've done all the proxy fixes to ensure it's as fast as possible).
Any help would be greatly appreciated.
I don't know if you are aware of this utility:
SoapUI
You can use it to reference your service and generate the requests to test your service.
The installation is pretty straightforward. After installed, you have to click on file/new SoapUI Project.
Then, in the popup window, you fill in the "Initial WSDL/WADL:" field with your service's wsdl, like this:
http://localhost:51849/Scribe.svc?wsdl
It'll generate the client to correctly do the calls to your service.
Using soap ui you can even test doing a bunch of calls to stress up your service.
This is a good way to test your services.
AFAIK I'm not really posting any data as all my data is embedded in the URL request itself; is this correct?
Yes. That's how a GET request works. The data is passed on your url. You should only use GET requests when not changing the state of the data on the server, otherwise you should use post.
PUT methods you'll use when you want to create/update the data on the server.
I hope it helps.
Regards,
Rodrigo
Maybe you should consider using some performance tool.
There are plenty and them, should be easy to find one suitable for your pourpose.
Jmeter could be a good option.
This is a guide that show how to use Jmeter to test a REST Web Service.
Hope it can help.
Thanks for the responses! I actually have the testing system working now and can slam my service with thousands of timer-controlled sessions. The key to getting around the PUT request issue was to use empty settings:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "PUT";
req.ContentType = "application/json";
req.ContentLength = 0;
I did look at those tools, but for my specific needs, I found writing a custom timer-controlled app was the best approach.
I'm not sure if the delay is still problematic, or possibly even linked to the debug state. once I publish the service to Azure and test it remotely, I'll get a better idea if there's any latency issues with connectivity which are service based...

Consuming a web service using POST instead of the going the usual WSDL route

This is how I have currently managed to consume a particular Microsoft web service. Notice that it is located on an HTTPS server and that it requires a username, a password, and a .cer file to be installed in the operating system's "root certificate authorities".
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.NegotiateServiceCredential = true;
binding.Security.Message.AlgorithmSuite
= System.ServiceModel.Security.SecurityAlgorithmSuite.Default;
binding.Security.Message.EstablishSecurityContext = true;
EndpointAddress endpoint = new EndpointAddress("https://address.of.service");
//"GreatClient" was created for me automatically by running
//"svcutil.exe https://address.of.service?wsdl"
GreatClient client = new GreatClient(binding, endpoint);
//Username and password for the authentication. Notice that I have also installed
//the required .cer certificate into the system's "root certificate authorities".
client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "password";
//Now I can start using the client as I wish.
My question is this: How can I obtain all the information necessary so that I can consume the web service with a direct POST to https://address.of.service, and how do I actually perform the POST with C#? I only want to use POST, where I can supply raw XML data using POST directly to https://address.of.service and get back the result as raw XML data. The question is, what is that raw XML data and how exactly should I send it using POST?
(The purpose of this question: The reason I ask is that I wish to consume this service using something other than C# and .NET (such as Ruby, or Cocoa on Mac OS X). I have no way of knowing how on earth to do that, since I don't have any easy-to-use "svcutil.exe" on other platforms to generate the required code for me. This is why I figured that just being able to consume the service using regular POST would allow me to more easily to consume the service on other platforms.)
What you are attempting to do sounds painful to do now and painful to maintain going forwards if anything changes in the server. It's really re-inventing the wheel.
If you haven't considered it already, I would:
(a) Research whether you can use the metadata you have for the service and use a proxy generator native to your target plaform. There aren't many platforms that don't have at least some tooling that might get you part of the way if not all of it. Perhaps repost a question targetting Ruby folk asking what frameworks exist to consume an HTTPS service given it's WSDL?
(b) Failing that, if your scenario allows it I would consider using a proxy written in C# that acts as a facade for the service which translates it into something easier to consume (for example, you might use something like ASP.NET MVC WebAPI which is flexible and can easily serve up standards compliant responses over which you can maintain total control).
I suspect one of these may prove easier and more valuable than the road you are on at the moment.
I had to go through something similar when porting .NET WCF code to other platforms. The easiest approach I found was to enable message logging on the WCF client. This can be configured to save both envelope and body and once everything is working on the .NET side of the house, you can use the message log to have "known-good" XML request/response to port to other platforms.
I found this approach to be more elegant since I didn't have to add an additional behavior to log messages, and it can be easily enabled/disabled/tweaked in the config. The Service Trace Viewer Tool that ships with Visual Studio is also handy for reviewing the log files.
I think when you say that the service should be consumed from other platforms, which do not have proxy class generation logic, you can go with REST services. This will allow you to create input as simple string concatenation instead of complex XML. Though its applicability depends on the situation.
Check this discussion : http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/6907d765-7d4c-48e8-9e29-3ac5b4b9c405/
As far as the certificate is concerned, refer http://msdn.microsoft.com/en-us/library/ms733791.aspx on how to configure it.
I know this is not a very precise answer, but you will be the best person to evaluate above procedure, hence posted. Hope it helps.
What I'll do:
1- Create a small c# app that can post on this webservice (using svcutil). And modify it to show the XML send/received. To view the xml there are several ways: logging, wireshark etc. To add it directly to the small app there is another question here that give a good answer.
2- Once you know what you have to send, you can do it in c# like this:
// implement GetXmlString() to return the XML to post
string xml = GetXmlString();
// create the url
string url = new UriBuilder("http","address.of.service",80).ToString();
// create a client object
using(System.Net.WebClient client = new System.Net.WebClient()) {
// performs an HTTP POST
client.UploadString(url, xml);
}
I'm not a .NET programmer but I've had to interoperate with a few .NET services and have lots of SOAP/WSDL experience. Sounds like you've captured the XML for your service. The other problem you'll face is authentication. OOTB, .NET web services use NTLM for authentication. Open-source language support for NTLMv2 can be hit and miss (although a quick google search pulled up a few possibilities for ruby), and using NTLM auth over HTTP may be something that you have to wire together yourself. To answer a question above: where are the auth creds? If the service is using NTLM over the wire, authentication is happening at some layer below HTTP. If the service is using NTLM to authenticate HTTP, your NTLM creds are in the HTTP Authorization header. You should be able to tell with wireshark where they are. You'll also probably need a SOAPAction header; this can also be sniffed with wireshark. For the C# client, I'm sure there are docs explaining how to add headers to your request.

Very fast and light web call, which technology to use: legacy web service or HttpWebRequest

I need some insecure, fast, light and easy to implement web method. Something like this:
// Client side
// Parametrize client address which is dynamic and we don't know until run-time
myClient.Address = "http://example.com/method.aspx/?input=" + value;
string result = "";
if (myClient.TryCallWebMethod(out result))
// Web method succeed. Use returned value.
else
// Web method failed. No problem, go with plan B.
// Server side
Response.Write("Answer is: " + Request.QueryString[input]);
I know this is reconstructing the wheel, but what I need is as simple as above code. I can implement client with HttpWebRequest but maybe using a legacy Web Service is a better choice.
I have tried WCF but there are more choices which I don't need like sessions, security, etc. Also I did a localhost benchmarking and WCF came to it's knees at 200 concurrent requests, where I need a support of more than 1000 concurrent calls which is a normal load for an aspx page.
This web method is gonna be consumed from a asp.net page. I never used a legacy web service, is it OK for my scenario or like WCF it has a dozen of configurations and certificate installations... ?
After going through the operations provided by WebClient, it looks like it just wraps a HttpWebRequest functionality and provides extra utility operations. Hence I would suggest you to go for HttpWebRequest.
Also on the server side, try to go for a HttpHandler instead of aspx page (handlers are light weight)
If this is a standard ASPX page you could use a WebClient:
using (var client = new WebClient())
{
var url = "http://example.com/method.aspx?input=" + HttpUtility.UrlEncode(value);
string result = client.DownloadString(url);
}

Categories

Resources