Why do I Need ASP.NET Web API When I Already Have ASP.NET MVC

Gleen Block explains why we need ASP.NET Web API when we already have ASP.NET MVC and what can we achieve with ASP.NET Web API
2012-08-30 11:05
Tugberk Ugurlu


As the ASP.NET Web API framework becomes more and more popular, this discussion also gets more and more popular and becomes one of the endless discussions that exists among the .NET community. The simple reaction when most of the people try to understand what ASP.NET Web API does is "I can already do those things with ASP.NET MVC". Well, that’s not correct in my opinion because you make ASP.NET MVC do those things, it doesn’t do that out of the box.

There are several more reasons why ASP.NET Web API is a great choice for HTTP APIs and why we need a new framework for that along with ASP.NET MVC. Gleen Block has done a great job on explaining those in the following video.

Couldn’t be explained better I think.

Other Resources

ASP.NET Web API Catch-All Route Parameter Binding

ASP.NET Web API has a concept of Catch-All routes but the frameowk doesn't automatically bind catch-all route values to a string array. Let's customize it with a custom HttpParameterBinding.
2012-08-29 13:14
Tugberk Ugurlu


I just realized that ASP.NET Web API doesn’t bind catch-all route values as ASP.NET MVC does. If you are not familiar with catch all routing, Stephen Walter has a great explanation on his article under the "Using Catch-All Routes" section.

In ASP.NET MVC, when you have a route as below, you can retrieve the values of the catch all parameter as string array.

RouteTable.Routes.MapRoute(
    "CatchAllRoute",
    "blog/tags/{*tags}",
    new { controller = "blog", action = "tags" }
);

The controller action would look like as below:

public class BlogController : Controller {

    public ActionResult Tags(string[] tags) { 

        //...
    }
}

In ASP.NET Web API, we don’t have that capability. If we have a catch-all route, we could retrieve it as string and parse it manually but that would be so lame to do it inside the controller, isn’t it? There must be a better way. Well, there is! We can create a custom HttpParameterBinding and register it globally for string arrays. If you are interested in learning more about parameter binding in ASP.NET Web API, you might wanna have a look at Mike Stall’s WebAPI Parameter binding under the hood blog post. In our case, the custom HttpParameterBinding we want to create looks like as below:

public class CatchAllRouteParameterBinding : HttpParameterBinding {

    private readonly string _parameterName;
    private readonly char _delimiter;

    public CatchAllRouteParameterBinding(
        HttpParameterDescriptor descriptor, char delimiter) : base(descriptor) {

        _parameterName = descriptor.ParameterName;
        _delimiter = delimiter;
    }

    public override Task ExecuteBindingAsync(
        System.Web.Http.Metadata.ModelMetadataProvider metadataProvider,
        HttpActionContext actionContext,
        CancellationToken cancellationToken) {

        var routeValues = actionContext.ControllerContext.RouteData.Values;
            
        if (routeValues[_parameterName] != null) {

            string[] catchAllValues = 
                routeValues[_parameterName].ToString().Split(_delimiter);

            actionContext.ActionArguments.Add(_parameterName, catchAllValues);
        }
        else {

            actionContext.ActionArguments.Add(_parameterName, new string[0]);
        }

        return Task.FromResult(0);
    }
}

All the necessary information has been provided to us inside the ExecuteBindingAsync method. From there, we simply grab the values from the RouteData and see if there is any route value whose route parameter name is the same as the action method parameter name. If there is one, we go ahead and split the values using the delimiter char provided to us. If there is no, we just attach an empty string array for the parameter. At the end, we let our caller know that we are done by returning a pre-completed Task object. I was using .NET 4.5, so I simply used FromResult method of Task class. If you are on .NET 4.0, you can return a completed task by using TaskCompletionSource class.

The following code is the our catch-all route.

protected void Application_Start() {

    var config = GlobalConfiguration.Configuration;

    config.Routes.MapHttpRoute(
        "BlogpostTagsHttpApiRoute",
        "api/blogposts/tags/{*tags}",
        new { controller = "blogposttags" }
    );
}

The last thing is that we need to register a rule telling that if there is an action method parameter which is a type of string array, go ahead and use our custom HttpParameterBinding.

protected void Application_Start() {

    var config = GlobalConfiguration.Configuration;

    //...

    config.ParameterBindingRules.Add(typeof(string[]),
        descriptor => new CatchAllRouteParameterBinding(descriptor, '/'));
}

Now, if we send a request to /api/blogposts/tags/asp-net/asp-net-web-api, we would see that our action method parameter is bound.

image

So far so good but we might not want to register our HttpParameterBinding rule globally. Instead, we might want to specify it manually when we require it. Well, we can do that as well. We just need to create a ParameterBindingAttribute to get our custom HttpParameterBinding so that it will be used to bind the action method parameter.

public class BindCatchAllRouteAttribute : ParameterBindingAttribute {

    private readonly char _delimiter;

    public BindCatchAllRouteAttribute(char delimiter) {

        _delimiter = delimiter;
    }

    public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter) {

        return new CatchAllRouteParameterBinding(parameter, _delimiter);
    }
}

As you can see, it is dead simple. The only thing we need to do now is to apply this attribute to our action parameter:

public class BlogPostTagsController : ApiController {

    //GET /api/blogposts/tags/asp-net/asp-net-web-api
    public HttpResponseMessage Get([BindCatchAllRoute('/')]string[] tags) {

        //TODO: Do your thing here...

        return new HttpResponseMessage(HttpStatusCode.OK);
    }
}

When we send a request to /api/blogposts/tags/asp-net/asp-net-web-api, we shouldn’t see any difference.

image

I am still discovering how parameter and model binding works inside the ASP.NET Web API. So, there is a good chance that I did something wrong here :) If you spot it, please let me know :)

Get the Start Navigation Sound Back on Windows 8

The usual "chlick" sound is not there when you navigate through inside the Windows Explorer and we will see how to get the Start Navigation sound back on Windows 8
2012-08-18 02:15
Tugberk Ugurlu


I assume that you have probably started using Windows 8 RTM version as you are here checking out this blog post. If the answer is yes, you may have noticed that the usual "chlick" sound is not there when you navigate through inside the Windows Explorer (I am not sure if the preview versions of Windows 8 had this characteristic but if they do, they apparently didn’t bug me that much).

If you are a weird person just like me, it will eat you alive! Fortunately, it is not something hard to get it back. Just press Windows + W and type "system sounds". From the search results, click "Change system sounds" option as shown below.

Screenshot (3)

Then, the Sound configuration window will pop up and from the Sounds tab, find the File Explorer > Start Navigation event inside the Program Events list. Finally, you will see that it has no sound attached to it. Just find the Navigation Start.waw from the Sounds dropdown list and select it as shown below.

StartNavSound

When you apply the changes, you will get back the lovely sound back. I am not sure why they felt the need of leaving that out by default but the fix is easy as you have just seen.

Enjoy!

Streaming with New .NET HttpClient and HttpCompletionOption.ResponseHeadersRead

How to consume a streaming endpoint with new .NET System.Net.Http.HttpClient and the role of HttpCompletionOption.ResponseHeadersRead
2012-08-01 06:27
Tugberk Ugurlu


For a while now, I have been playing with a new application I created for fun: TweetMapR and I am not sure where it is going :) The application itself consumes Twitter Streaming API and broadcasts the retrieved data to the connected clients through SignalR. I used new HttpClient to connect to Twitter Streaming API and I used OAuth as authentication protocol. In fact, I created my own OAuth Twitter client to connect to Twitter which is so raw right now but works well.

But how to send a request to Twitter Streaming API and keep it open infinitely was my main question for the whole time. So, I brought up the ILSpy and decompiled the System.Net.Http.dll to see what is really going on and I realized that it was going to be so easy. First of all, if your request is a GET request, you are covered by the framework. The GetStreamAsync method of the HttpClient sends a GET request and returns back the stream as soon as it completes reading the response headers. The following example code shows the usage.

using (HttpClient httpClient = new HttpClient()) {

    httpClient.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
    var requestUri = "http://localhost:6797";
    var stream = httpClient.GetStreamAsync(requestUri).Result;

    using (var reader = new StreamReader(stream)) {

        while (!reader.EndOfStream) { 

            //We are ready to read the stream
            var currentLine = reader.ReadLine();
        }
    }
}

First of all, don’t use Result on Task :) It blocks but I used it here for the sake of simplicity to stick with the main point of this post :) Assuming that the localhost:6797 is a streaming endpoint here, the above code should work perfectly fine and shouldn’t be timed out as we set the Timeout to System.Threading.Timeout.Infinite. But what if the request we need to send is a POST request? In that case, we have a little more work to do here.

If we just try to send a POST request with the PostAsync method or any of its variants, the response will never come back unless the server ends the request because it will try to read the response till the end. In order to omit this problem, we can pass a HttpCompletionOption enumuration value to specify the completion option. The HttpCompletionOption enumeration type has two members and one of them is ResponseHeadersRead which tells the HttpClient to only read the headers and then return back the result immediately. The following code shows a sample example where we need to send a form-urlencoded POST request to a streaming endpoint.

using (HttpClient httpClient = new HttpClient()) {

    httpClient.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
    var requestUri = "http://localhost:6797";

    var formUrlEncodedContent = new FormUrlEncodedContent(
        new List<KeyValuePair<string, string>>() { 
            new KeyValuePair<string, string>("userId", "1000") });

    formUrlEncodedContent.Headers.ContentType = 
        new MediaTypeHeaderValue("application/x-www-form-urlencoded");

    var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
    request.Content = formUrlEncodedContent;

    var response = httpClient.SendAsync(
        request, HttpCompletionOption.ResponseHeadersRead).Result;
    var stream = response.Content.ReadAsStreamAsync().Result;

    using (var reader = new StreamReader(stream)) {

        while (!reader.EndOfStream) { 

            //We are ready to read the stream
            var currentLine = reader.ReadLine();
        }
    }
}

Again, don’t use Result as I do here :) We have obviously more noise this time but if this is something that you will use often, there is nothing stopping you to write an extension method.

Disposing Resources At the End of the Request Lifecycle in ASP.NET Web API

How to disposing resources at the end of the request lifecycle in ASP.NET Web API with the RegisterForDispose extension method for the HttpRequestMessage class
2012-07-27 05:26
Tugberk Ugurlu


When we are working with ASP.NET Web API, we always deal with disposable resources and if we are using an IoC container, it deals with disposals in behalf of us.

However, when we are inside the extensibility points and we just want to create a resource there and dispose it as soon as we are done with it, it can be easily overwhelming because the asynchronous structure of the ASP.NET Web API. We should be very careful where to dispose our resources.

However, ASP.NET team has come up with this great idea that they allow us to register resources to be disposed by a host once the request is disposed. The RegisterForDispose extension method for the HttpRequestMessage class enables this feature. In fact, all it does is to keep track of all the registered resources inside a List<IDisposable> object. They stick this collection into the Properties property of the HttpRequestMessage (under the key of MS_DisposableRequestResources). Then, at the end of the request, these resources will be disposed along with the request.

The usage is also so simple. For example, the below code is for a message handler which serves as a timeout watcher.

public class TimeoutHandler : DelegatingHandler {

    private readonly int _milliseconds;
    private static readonly TimerCallback s_timerCallback = 
        new TimerCallback(TimerCallbackLogic);

    public TimeoutHandler(int milliseconds) {

        if (milliseconds < -1) {

            throw new ArgumentOutOfRangeException("milliseconds");
        }

        _milliseconds = milliseconds;
    }

    public int Timeout {

        get {
            return _milliseconds;
        }
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken) {

        var cts = new CancellationTokenSource();
        var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
            cts.Token, cancellationToken
        );
        var linkedToken = linkedTokenSource.Token;
        var timer = new Timer(s_timerCallback, cts, -1, -1);

        request.RegisterForDispose(timer);
        request.RegisterForDispose(cts);
        request.RegisterForDispose(linkedTokenSource);

        timer.Change(_milliseconds, -1);

        return base.SendAsync(request, linkedToken).ContinueWith(task => {

            if (task.Status == TaskStatus.Canceled) {

                return request.CreateResponse(HttpStatusCode.RequestTimeout);
            }

            //TODO: Handle faulted task as well

            return task.Result;

        }, TaskContinuationOptions.ExecuteSynchronously);
    }

    private static void TimerCallbackLogic(object obj) {

        CancellationTokenSource cancellationTokenSource = 
            (CancellationTokenSource)obj;
            
        cancellationTokenSource.Cancel();
    }
}

You may see that there are still TODO notes inside the code which means I am still not done with the code, so don't use it in production!:) but it is a good example to illustrate the usage of RegisterForDispose extension method. Notice that I used two CancellationTokenSource objects and one Timer object (I need a Timer object here to request a cancellation because CancellationTokenSource does not have CancelAfter method in .NET v4.0 and I couldn’t find any other easier way to do this). All of these objects need to be disposed once they are no longer in use. However, it is really hard to keep track to figure out which one of them needs to be disposed where inside this handler. So, I just registered them to disposed at the end of the request lifetime.