How to achieve high-performance REST API on Azure with .NET? How to achieve high-performance REST API on Azure with .NET? azure azure

How to achieve high-performance REST API on Azure with .NET?


Is your XML being serialized via reflection (ie. using attributes and so forth)? If so, then protobuf-net stands to be much, much faster.

In fact, though, even if your XML serialization is customized using explicit getter and setter Func<>s, you can still see some significant gain with protobuf-net. In our case, depending on the size and content of the objects being serialized, we saw 5-15% speed increases in serialization times.

Using protobuf-net will also provide a bump to available bandwidth, though that will depend on your content to a large extent.

Our system sounds pretty different from yours, but FWIW we find that WCF itself has an almost imperceptibly low overhead compared to the rest of the flow. A profiler like dotTrace might help identify just where you can save once you've switched to protobufs.


Is the size of the messages your service is receiving so big because there is a large amount of data in the message or because they contain files?

If it is the first case, then ProtoBuf does indeed seem like a very good option.

If the message size is big because it embeds files, then one strategy I have been using with success is creating two different architectures for your service methods: one for methods that upload and download files and another one for methods that only send and receive messages.

The file related methods will simply transmit the files inside the body of the HTTP requests, in binary form without any transformation or encoding. The rest of the parameters will be send using the request URL.

For file uploads, in WCF REST services, in the service method you will have to declare the parameter representing the file of being of type Stream. For example:

[OperationContract][WebInvoke(Method = "POST", UriTemplate = "uploadProjectDocument?projectId={projectId}")]void UploadProjectDocument(Guid projectId, Stream document);

When encountering Stream parameters, WCF will simply take their content directly from the body of the request without doing any processing on it. You can only have one parameter of type Stream on a service method (which makes sense because each HTTP request has only one body).

The downside to the above approach is that besides the parameter representing the file, all the other ones need to be of basic types (like strings, number, GUIDs). You cannot pass any complex object. If you need to do that you will have to create a separate method for it, so you might end up having two methods (which will translate in two calls at runtime) where at the moment you have only one. However, uploading files directly in the body of the request should be much more efficient than serializing them, so even with the extra call things should be improved.

For downloading files from the service you will need to declare the WCF methods as returning Stream and simply write the file in returned object. As with the Stream paramters, WCF will output the content of the Stream directly into the body of the result without any transformations on it.


This article http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 covers performance issues with Azure.

Azure roles by default only run in a single thread, which is very inefficient on the servers. There are some very nice design patterns out there that shows you how to implement multithreaded Azure roles, I personally follow this one http://www.31a2ba2a-b718-11dc-8314-0800200c9a66.com/2010/12/running-multiple-threads-on-windows.html . With this your roles can serialize objects in parallel.

I use JSON as an interchange format instead of XML, it has a much smaller bytesize and is well supported with .NET 4. I currently use DataContractJsonSerializer but you could also look into JavaScriptSerializer or JSON.NET, if it is serialization performance you are after I would suggest you compare these.

WCF services are single threaded by default ( source: http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(SYSTEM.SERVICEMODEL.SERVICEBEHAVIORATTRIBUTE.CONCURRENCYMODE);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22);k(DevLang-CSHARP)&rd=true ) . Here is a code sample that will make your RESTfull API multi-threaded:

ExampleService.svc.cs

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall,         IncludeExceptionDetailInFaults = false, MaxItemsInObjectGraph = Int32.MaxValue)]    public class ExampleService : IExample

web.config

 <system.serviceModel>    <protocolMapping>      <add scheme="http" binding="webHttpBinding" bindingConfiguration="" />    </protocolMapping>    <behaviors>      <endpointBehaviors>        <behavior name="">          <webHttp defaultOutgoingResponseFormat="Json" />        </behavior>      </endpointBehaviors>      <serviceBehaviors>        <behavior name="">          <serviceMetadata httpGetEnabled="true" />          <serviceDebug includeExceptionDetailInFaults="false" />        </behavior>      </serviceBehaviors>    </behaviors>    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />  </system.serviceModel>  

ExampleService.svc

<%@ ServiceHost Language="C#" Debug="true" Service="WebPages.Interfaces.ExampleService" CodeBehind="ExampleService.svc.cs" %>

Also, ASP.NET by default only allow for two concurrent HTTP connections (source See http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 ) . These settings will allow for up to 48 concurrent HTTP connections:

web.config

  <system.net>    <connectionManagement>      <!-- See http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 -->      <add address="*" maxconnection="48" />    </connectionManagement>  </system.net>  

If your HTTP POST body messages are usually smaller than 1460 bytes you should turn of nagling to improve performance ( source http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 ) . Here is some settings that does this:

web.config

  <system.net>    <settings>      <!-- See http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 -->      <servicePointManager expect100Continue="false" />    </settings>  </system.net>  

Define your JSON APIs something like this:

using System.ServiceModel;using System.ServiceModel.Web;using Interchange;namespace WebPages.Interfaces{    [ServiceContract]     public interface IExample    {        [OperationContract]        [WebInvoke(Method = "POST",            BodyStyle = WebMessageBodyStyle.Bare,            RequestFormat = WebMessageFormat.Json,            ResponseFormat = WebMessageFormat.Json)]        string GetUpdates(RequestUpdates name);        [OperationContract]        [WebInvoke(Method = "POST",            BodyStyle = WebMessageBodyStyle.Bare,            RequestFormat = WebMessageFormat.Json,            ResponseFormat = WebMessageFormat.Json)]        string PostMessage(PostMessage message);    }}

You can serialize to JSON in .NET 4 like this:

string SerializeData(object data){    var serializer = new DataContractJsonSerializer(data.GetType());    var memoryStream = new MemoryStream();    serializer.WriteObject(memoryStream, data);    return Encoding.Default.GetString(memoryStream.ToArray());            }

A typical interchange entity you can define as normal:

using System.Collections.Generic;using System.Runtime.Serialization;namespace Interchange{    [DataContract]    public class PostMessage    {        [DataMember]        public string Text { get; set; }        [DataMember]        public List<string> Tags { get; set; }        [DataMember]        public string AspNetSessionId { get; set; }    }}

You could write your own HTTPModule for upstream GZip compression, but I would try the stuff above first.

Finally, make sure that your table storage is at the same location as the services that consume them.