For a project on the side I’m creating a Web API which has to parse XML requests in a POST. The first method I’ve written looks like this:

[HttpPost]
public HttpResponseMessage IndexPost(RequestModel requestMessage)
{
	return new HttpResponseMessage(HttpStatusCode.Accepted) { Content = new StringContent("This is the POST API response from BusinessPartner!") };
}

To test the new API I’m using the Postman Chrome plugin. With this plugin you are able to send requests to an endpoint and see what the response is. Of course you can also use Fiddler for this, but I like the user experience of Postman a bit more.

There were a few problems I encountered during the development of the Web API.

The first problem was this error:

{
    "message": "An error has occurred.",
    "exceptionMessage": "No MediaTypeFormatter is available to read an object of type 'RequestModel' from content with media type 'text/plain'.",
    "exceptionType": "System.InvalidOperationException",
    "stackTrace": "   at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger)\r\n   at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger)\r\n   at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger)\r\n   at System.Web.Http.ModelBinding.FormatterParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)\r\n   at System.Web.Http.Tracing.Tracers.FormatterParameterBindingTracer.<>c__DisplayClass3.b__1()\r\n   at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEndAsync(ITraceWriter traceWriter, HttpRequestMessage request, String category, TraceLevel level, String operatorName, String operationName, Action`1 beginTrace, Func`1 execute, Action`1 endTrace, Action`1 errorTrace)\r\n   at System.Web.Http.Tracing.Tracers.FormatterParameterBindingTracer.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)\r\n   at System.Web.Http.Controllers.HttpActionBinding.<>c__DisplayClass1.b__0(HttpParameterBinding parameterBinder)\r\n   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()\r\n   at System.Threading.Tasks.TaskHelpers.IterateImpl(IEnumerator`1 enumerator, CancellationToken cancellationToken)"
}

This was quite surprising as I thought I was sending a proper request which could be serialized. For reference, I was sending a POST request to http://localhost:11210/api/businesspartnerapi/ in this format:

<RequestModel><RequestMessage>1</RequestMessage></RequestModel>

image

As I couldn’t find anything on the internet explaining what I did wrong, I started looking through the options of Postman. Apparently you can add information to the header of the request, like a content type. After having added the contenttype text/xml to the message the API returned the response which I had expected.

image

Success!

Apparently you need to specify the correct content type in order for ASP.NET to know how to deserialize the object.

But there is more. The second problem I faced was the requestMessage being null.

image

Quite strange as the model is serializable. I’ve also added the [Serializable]-attribute to the model, but to no avail.

From the back in the WCF days I remembered you have to add the [DataContract]- and [DataMember]-attributes to a model if you to use them in services. Therefore I added them to my model.

The RequestModel now looks like this:

[DataContract(Namespace="")]
public class RequestModel
{
	[DataMember]
	public string RequestMessage { get; set; }
}

After POST-ing another request to the API I was able to see the result.

image

As you can see in the Watch window, the object is successfully created with the value I expected.

So, if you want to debug a Web API project, don’t forget to add the proper content type to your request and make sure you specify the attributes to your model so it can be (de)serialized.

Some time ago Microsoft has introduced the ASP.NET Web API framework. It’s a framework you can use to create your own RESTful services. It’s much like WCF Data Services or WCF RIA Services, but a lot easier to use (IMO). I’ve never liked the WCF-stack much, probably because configuring it always posed to be a hassle.

Using the Web API framework is much easier and you have to configure a lot less, or at least I haven’t found all of the configurable options yet. Then again, it’s created for entirely different purposes of course.
To create a service you select the ASP.NET MVC4 project template and can create new controllers which inherit from the ApiController. It’s also possible to do some awesome queries on your client nowadays, because Web API is capable of supporting OData! Install the latest stable NuGet package and you are ready to go!

Because I was put on a new project, I was finally able to do some real work with ASP.NET Web API. We had to develop a solution containing a so called self-hosted Web API service which also supported OData queries. This sounds like a lot of work, but it’s actually rather easy to do so nowadays.

During this new project we had some time to investigate and learn a bit about the platform. Therefore we chose to use the latest version of everything we could find, just to keep us up-to-date. To get OData working we used the beta2 version which works great for the simple stuff we were doing.
Now, all you have to do to get OData working is return IQueryable<T> from your controller actions. For example:

[Queryable]
public IQueryable GetEverything()
{
    using (var ctx = new HMOEvents("TheRepositoryConnectionStringName"))
    {
		return ctx.TableContainingEverything.OrderByDescending(e => e.TimeCreated).ToList().AsQueryable();
    }
}

Hit F5 and you are ready to do some OData queries on this action. Awesome, huh?

After we had figured this out, we still had to make this Web API service self-hosted. The reason for this requirement was because the webserver wasn’t in our control and the administrators had the tendency of resetting IIS quite a lot of times during the day (don’t ask….). I was already pulling my hair on figuring out how we had to do this, but as it turns out this is quite easy to do also.

There’s a reference you can add called System.Web.Http.SelfHost. You just have to create a new Console Application, add the reference and paste this piece of code over your Main method

static void Main(string[] args)
{
    HttpSelfHostServer server = null;
    try
    {
        // Set up server configuration 
	var config = new HttpSelfHostConfiguration(new Uri("http://localhost:2132"));
        config.EnableQuerySupport();
	config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
	config.Routes.MapHttpRoute(
				name: "ActionApi",
				routeTemplate: "api/{controller}/{action}",
				defaults: new { action = "Get" }
	);
	config.Routes.MapHttpRoute(
		            name: "DefaultApi",
		            routeTemplate: "api/{controller}/{id}",
       			    defaults: new { id = RouteParameter.Optional }
        );

	config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
	config.ReceiveTimeout = new TimeSpan(0, 0, 3, 0);
	config.SendTimeout = new TimeSpan(0, 0, 3, 0);
	// Create server 
	server = new HttpSelfHostServer(config);

        // Start listening 
        server.OpenAsync().Wait();
        Console.WriteLine("Listening on http://localhost:2132");
        Console.ReadLine();
    }
    catch (Exception e)
    {
        Console.WriteLine("Could not start server: {0}", e.GetBaseException().Message);
        Console.WriteLine("Hit ENTER to exit...");
        Console.ReadLine();
    }
    finally
    {
        if (server != null)
        {
            // Stop listening 
            server.CloseAsync().Wait();
        }
    } 
}

After doing so you can add your Web API controllers to this Console Application and start the application. Once the application is started you are able to do your queries on http://localhost:2132.
Note: You might need to check the firewall and run this application as an Administrator, otherwise it might cause some problems. Something about Windows security and setting up new ‘webservers’. It’s possible to do this without Administrator priviliges, to do this isexplained on Stack Overflow.

Again, pretty awesome, huh? This saves up a lot of development time!

You might have noticed I’ve used the following line to enable CORS on the service:

config.EnableCors(new EnableCorsAttribute("*", "*", "*"));

This isn’t some extension method and class that I’ve written myself. There’s something called Microsoft.AspNet.WebApi.Cors which is a NuGet package you can implement. At the time of the project, beta2 was the most recent version of these bits. Once you’ve included this in your project, you are able to enable CORS with just this extra line in the configuration.
For self-hosted services you have use this, because it’s rather hard (impossible?) to add the ‘Acces-Control-Allow-Origin’ headers.