2012 Microsoft ASP.NET/IIS MVP Award

Yesterday, I received an awesome e-mail telling me that I have been given the Microsoft MVP award on ASP.NET/IIS for 2012.
2012-10-02 18:08
Tugberk Ugurlu


mvp_logo

Yesterday, I received an awesome e-mail telling me that I have been given the Microsoft MVP award on ASP.NET/IIS. :) This was obviously a great news for me because this is my first time being an MVP. If you wonder what the heck is Microsoft MVP Award program is, here is the quote from the official MVP Overview page:

"The Microsoft Most Valuable Professional (MVP) Award is our way of saying thank you to exceptional, independent community leaders who share their passion, technical expertise, and real-world knowledge of Microsoft products with others.

Nearly two decades ago, we awarded 37 technical community leaders as MVPs. Today, there are more than 4,000 MVPs worldwide. They represent more than 90 countries, speak over 40 languages, answer more than 10 million questions a year, and are awarded in almost 90 Microsoft technologies—reflecting the breadth of our products and our global communities."

Microsoft developer community is beyond huge. So many brilliant developers share their knowledge through blogs, webcasts, podcasts, conference talks, user group meetings. Being part of this community has been always a fun but with this award, this fun is now doubled. However, I have never seen the MVP award as a target. I didn’t do anything special to get this award (well, except for filling the evaluation form). I just did what I love and that was enough. I love spending time on Stackoverflow, I love writing blog posts and I love helping others if I can.

Nearly for four years now, I have been trying to find my way with ASP.NET and its sub components, such as ASP.NET MVC, ASP.NET Web API, SignalR and I can see that the product has been evolved so much in a positive direction. Not to mention some huge steps that have been taken such as making nearly the 90% of the ASP.NET stack open source on Codeplex. Being able to see how the product grows commit by commit is simply awesome. This improvements made it possible for me to create better software solutions for the company I work for. Besides that, other Microsoft products such as Window Azure took me and my company to the next level.

I would like to especially thank all the developers at Microsoft, especially the ASP.NET, IIS and Windows Azure team members for the great products they build and the continuous support whenever we need it. I also want to thank all of the developers in this community for sharing their valuable knowledge, answering questions on forums and Q&A sites. I should admit that I am learning a lot by looking at other people’s code and if they weren’t sharing those, I wouldn’t be the developer as I am today.

Lastly, I would like to thank my lovely fiancé Nihan for her support in my life; especially for listening to me talking about tech stuff even if she has no idea about what I say 99% of the time. :)

I am hoping that I will never lose this award and I want to keep getting it every year :)

Complex Type Action Parameters and Controller Action Selection with ASP.NET Web API

How to use complex type action parameters in ASP.NET Web API and involve them inside the controller action selection logic
2012-09-30 19:04
Tugberk Ugurlu


If you are familiar with ASP.NET MVC and trying to find your way with ASP.NET Web API, you may have noticed that the default action selection logic with ASP.NET Web API is pretty different than the ASP.NET MVC's. First of all, the action parameters play a huge role on action selection in ASP.NET Web API. Consider the following controller and its two action methods:

public class CarsController : ApiController { 

    //GET /api/cars?categoryId=10
    public string[] GetCarsByCategoryId(int categoryId) { 
        
        return new[] { 
            "Car 1",
            "Car 2",
            "Car 3"
        };
    }
    
    //GET /api/cars?colorId=10
    public string[] GetCarsByColorId(int colorId) { 
        
        return new[] { 
            "Car 1",
            "Car 2"
        };
    }
}

This doesn’t going to cause the action ambiguity because the action parameter names are different. The default action selector (ApiControllerActionSelector) going to extract the action parameter names and try to match those with the URI parameters such as query string and route values. So if a GET request comes to /api/cars?categoryId=10, the GetCarsByCategoryId action method will be invoked. If a GET request comes to /api/cars?colorId=10 in this case, the GetCarsByColorId action method will be called.

It's possible to use complex types as action parameters for GET requests and bind the route and query string values by marking the complex type parameters with FromUriAttribute. However, the default action selection logic only considers simple types which are System.String, System.DateTime, System.Decimal, System.Guid, System.DateTimeOffset and System.TimeSpan. For example, if you have GetCars(Foo foo) and GetCars(Bar bar) methods inside your controller, you will get the ambiguous action error as the complex types are completely ignored by the ApiControllerActionSelector.

Let’s take the following as example here:

public class CarsByCategoryRequestCommand {

    public int CategoryId { get; set; }
    public int Page { get; set; }

    [Range(1, 50)]
    public int Take { get; set; }
}

public class CarsByColorRequestCommand {

    public int ColorId { get; set; }
    public int Page { get; set; }

    [Range(1, 50)]
    public int Take { get; set; }
}

public class CarsController : ApiController {

    public string[] GetCarsByCategoryId(
        [FromUri]CarsByCategoryRequestCommand cmd) {

        return new[] { 
            "Car 1",
            "Car 2",
            "Car 3"
        };
    }

    public string[] GetCarsByColorId(
        [FromUri]CarsByColorRequestCommand cmd) {

        return new[] { 
            "Car 1",
            "Car 2"
        };
    }
}

We are not performing any logic inside the action here but you can understand from the action parameter types that we are aiming to perform pagination here. So, we are receiving the inputs from the consumer. We can use simple types directy as action parameters but there is no built-in way to validate the simple types and I haven’t found an elegant way to hook something up for that. As a result, complex type action parameters comes in handy in such cases.

If we now send a GET request to /api/cars?colorId=23&page=2&take=12, we would get the ambiguity error message:

image

To workaround this issue, I created a new action selector which has the same implementation as the ApiControllerActionSelector and a few tweaks to make this feature work. It wasn’t easy at all. The ApiControllerActionSelector is not so extensible and I had to manually rewrite it (honestly, I didn’t directly copy-paste. I rewrote the every single line). I also thought that this could make it into the framework. So, I sent a pull request which got rejected:  3338. There is also an issue open to make the default action selector more extensible: #277. I encourage you to go and vote!

So, what can we do for now to make this work? Go and install the latest WebAPIDoodle package from the Official NuGet feed:

PM> Install-Package WebAPIDoodle

This package has a few useful components for ASP.NET Web API and one of them is the ComplexTypeAwareActionSelector. First of all, we need to replace the default action selector with our ComplexTypeAwareActionSelector as below. Note that ComplexTypeAwareActionSelector preserves all the features of the ApiControllerAction selector.

protected void Application_Start(object sender, EventArgs e) {

    var config = GlobalConfiguration.Configuration;
    config.Routes.MapHttpRoute(
        "DefaultApiRoute",
        "api/{controller}/{id}",
        new { id = RouteParameter.Optional }
    );

    // Replace the default action IHttpActionSelector with
    // WebAPIDoodle.Controllers.ComplexTypeAwareActionSelector
    config.Services.Replace(
        typeof(IHttpActionSelector),
        new ComplexTypeAwareActionSelector());
}

This package also contains an attribute named UriParametersAttribute which accepts a params string[] parameter. We can apply this attribute to action methods and pass the parameters that we want to be considered during the action selection. The below one shows the sample usage for our above case:

public class CarsController : ApiController {

    [UriParameters("CategoryId", "Page", "Take")]
    public string[] GetCarsByCategoryId(
        [FromUri]CarsByCategoryRequestCommand cmd) {

        return new[] { 
            "Car 1",
            "Car 2",
            "Car 3"
        };
    }

    [UriParameters("ColorId", "Page", "Take")]
    public string[] GetCarsByColorId(
        [FromUri]CarsByColorRequestCommand cmd) {

        return new[] { 
            "Car 1",
            "Car 2"
        };
    }
}

If we now send the proper GET requests as below, we should see it working:

image

image

You can also grab the sample to see this in action. I should also mention that I am not saying that this is the way to go. Clearly, this generates a lot of noise and we can do better here. The one solution would be to inspect the simple type properties of the complex type action parameter without needing the UriParametersAttribute.

Asynchronous .NET Client Libraries for Your HTTP API and Awareness of async/await's Bad Effects

Writing asynchronous .NET Client libraries for your HTTP API and using asynchronous language features (aka async/await) and some deadlock issue you might face.
2012-09-21 06:34
Tugberk Ugurlu


Haven’t you shot yourself in the foot yet with async/await? If not, you are about to if you are writing a client library for your newly created ASP.NET Web API application with .NET 4.5 using new asynchronous language features.

I wrote a blog post couple of months ago on the importance of Current SynchronizationContext and the new C# 5.0 asynchronous language Features (aka async/await). I wrote that post just after I watched the The zen of async: Best practices for best performance talk of Stephen Toub on //Build 2011 and that was one of the best sessions that I was and still am glad to watch. I learnt so many things from that session and some of them was amazingly important.

Filip Ekberg also has a very nice and useful blog post which has an identical title as my previous post on the topic: Avoid shooting yourself in the foot with Tasks and Async.

The post was pointing out that it is extremely easy to end up with a deadlock if you are not careful enough. The post explains every details but if want to recap shortly, here it is:

When you are awaiting on a method with await keyword, compiler generates bunch of code in behalf of you. One of the purposes of this action is to handle synchronization with the UI thread. The key component of this feature is theSynchronizationContext.Current which gets the synchronization context for the current thread. SynchronizationContext.Current is populated depending on the environment you are in. The GetAwaiter method of Task looks up for SynchronizationContext.Current. If current synchronization context is not null, the continuation that gets passed to that awaiter will get posted back to that synchronization context.

When consuming a method, which uses the new asynchronous language features, in a blocking fashion, you will end up with a deadlock if you have an available SynchronizationContext. When you are consuming such methods in a blocking fashion (waiting on the Task with Wait method or taking the result directly from the Result property of the Task), you will block the main thread at the same time. When eventually the Task completes inside that method in the threadpool, it is going to invoke the continuation to post back to the main thread because SynchronizationContext.Current is available and captured. But there is a problem here: the UI thread is blocked and you have a deadlock!

The post also has a sample but I want dig deep into this. As you all know, ASP.NET Web API RTW version has been shipped couple of weeks ago and we may have started to take advantage of this framework to build our HTTP-based lightweight APIs. You might be using another framework to create your APIs or you might be maintaining an existing one. No matter which category you put yourself in, you are likely to build platform specific client libraries for your API. If you are going to target .NET framework, I am 90% sure that you want your client library to be asynchronous and new HttpClient will just give you that option.

I have started writing a simple blog engine for myself called MvcBloggy nearly a year ago and after the RTW release of the ASP.NET MVC 4 and ASP.NET Web API, I decided to try something different and expose the data through HTTP. So, my ASP.NET MVC application won’t know anything about where my data is store or how I retrieve it. It is just going to consume the HTTP APIs. The application is shaping up nicely and I even started to build my .NET client for the API as well.

Couple of days ago, Ben Foster (a brilliant developer) raised a question on Twitter about consuming asynchronous methods on ASP.NET Web Pages application and I also wondered about that. Then, we looked around a bit and also contacted with Erik Porter (@HumanCompiler), Program Manager on the ASP.NET team, and he confirmed that it is not possible today. He encouraged us to file an issue and we did (#418). This got me thinking about my little project’s .NET client, though. What if I wanted to create a blog web site with ASP.NET Web Pages by consuming the .NET client of my blog engine? I have no option rather than consuming the methods in a blocking fashion but with my current implementation, I am not able to do that because I will end up with deadlocks. Let me prove that to you with a little example which you can also find up on GitHub: AsyncAwaitForLibraryAuthors.

Assuming we have a little API which returns back a list of cars and we want to build a .NET client to consume the HTTP API and abstracts all the lower level HTTP stuff away. The one that I created is as below (it is a simple one for the demo purposes):

public class Car {

    public int Id { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
    public int Year { get; set; }
    public float Price { get; set; }
}

public class SampleAPIClient {

    private const string ApiUri = "http://localhost:17257/api/cars";

    public async Task<IEnumerable<Car>> GetCarsAsync() {

        using (HttpClient client = new HttpClient()) {

            var response = await client.GetAsync(ApiUri);

            // Not the best way to handle it but will do the work for demo purposes
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsAsync<IEnumerable<Car>>();
        }
    }
}

We leveraged the new asynchronous language features and we were able to write a small amount of code to get the job done. More importantly, we are making the network call and the deserialization asynchronously. As we know from the earlier sentences that if there is a SynchronizationContext available for us, the code that the compiler is generating for us will capture that and post the continuation back to that context to be executed. Keep this part in mind. I put this little class inside a separate project called SampleAPI.Client and reference this from my web clients. I have created two clients: one ASP.NET MVC and one ASP.NET Web Pages applications.

In my ASP.NET MVC 4 application, I have a controller which has two actions. One of these actions will call the API asynchronously and one of will do the same by blocking:

public class HomeController : Controller {

    public async Task<ViewResult> CarsAsync() {

        SampleAPIClient client = new SampleAPIClient();
        var cars = await client.GetCarsAsync();

        return View("Index", model: cars);
    }

    public ViewResult CarsSync() {

        SampleAPIClient client = new SampleAPIClient();
        var cars = client.GetCarsAsync().Result;

        return View("Index", model: cars);
    }
}

Our view is also so simple as follows:

@model IEnumerable<SampleAPI.Client.Car>
@{
    ViewBag.Title = "Home Page";
}

<h3>Cars List</h3>

<ul>
    @foreach (var car in Model) {
        <li>
            @car.Make, @car.Model (@car.Year) - @car.Price.ToString("C")
        </li>    
    }
</ul>

When we navigate to /home/CarsAsync, we will get back the result.

image

However, when we navigate to /home/CarsSync to invoke the CarsSync method, we will see that the page will never come back because we just introduced a deadlock due to the reasons we have explained earlier. Let’s have a look at the Web Pages sample:

@{
    Layout = "~/_SiteLayout.cshtml";
    Page.Title = "Home Page";

    SampleAPI.Client.SampleAPIClient client = new SampleAPI.Client.SampleAPIClient();
    var cars = client.GetCarsAsync().Result;
}

<h3>Cars List</h3>

<ul>
    @foreach (var car in cars) {
        <li>
            @car.Make, @car.Model (@car.Year) - @car.Price.ToString("C")
        </li>    
    }
</ul>

This page is also not going to respond because Web Pages runs under ASP.NET and ASP.NET has a SynchronizationContext available.

When we take a look at our GetCarsAsync method implementation, we will see that it is completely unnecessary for us to get back to current SynchronizationContext because we don’t need anything from the current context. This is good because it is not our (I mean our .NET client’s) concern to do anything under the current SynchronizationContext. It is, on the other hand, our consumer’s responsibility. Stephen Toub said something in his talk on //Build 2011 and the words not the same but it expresses the meaning of the below sentences:

If you are a library developer, the default behavior which await gives you is nearly never what you want. However, if you are a application developer, the default behavior will nearly always what you want.

I, again, encourage you to check that video out.

The solution here is simple. When we are creating our libraries, we just need to be more careful and think about the usage scenarios. In our case here, we need to suppress the default SynchronizationContext behavior that the compiler is generating for us. We can achieve this with ConfigureAwait method of the Task class which was introduced with .NET 4.5. The ConfigureAwait method accepts a Boolean parameter named as continueOnCapturedContext. We can pass false into this method not to marshal the continuation back to the original context captured and our problem would be solved. Here is the new look of our .NET client for our HTTP API.

public class SampleAPIClient {

    private const string ApiUri = "http://localhost:17257/api/cars";

    public async Task<IEnumerable<Car>> GetCarsAsync() {

        using (HttpClient client = new HttpClient()) {

            var response = await client.GetAsync(ApiUri)
                .ConfigureAwait(continueOnCapturedContext: false);

            // Not the best way to handle it but will do the work for demo purposes
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsAsync<IEnumerable<Car>>()
                .ConfigureAwait(continueOnCapturedContext: false);
        }
    }
}

When we now run our Web Pages application, we will see the web site working nicely (same is also applicable for the CarsSync action method of our ASP.NET MVC application).

image

If you are going to write a .NET client for your company’s big HTTP API using new asynchronous language features, you might want to consider these facts before moving on. Otherwise, your consumers will have hard time understanding what is really going wrong.

Script Out Everything - Initialize Your Windows Azure VM for Your Web Server with IIS, Web Deploy and Other Stuff

Script Out Everything - Initialize Your Windows Azure VM for Your Web Server with IIS, Web Deploy and Other Stuff
2012-09-17 20:17
Tugberk Ugurlu


Today, I am officially sick and tired of initializing a new Web Server every time so I decided to script it all out as much as I can. I created a new Windows Azure VM running Windows Server 2012 and installed Web Platform Installer v4 Command Line tool (aka WebPICMD.exe).

Next thing I need to do is to install the IIS Web Server Role inside my VM. To do that, I opened up the Server Manager and closed it instantly because I didn't wanna do that through a GUI either. It turned out that it is fairly easy to manage your server roles and features through PowerShell thanks to ServerManager PowerShell module. This module has couple of handy Cmdlets which enable you to manage your server’s roles and features.

image

To install the IIS Web Server, I run the following PowerShell command. It installs IIS Web Server (along with the necessary dependencies and management tools) and logs the output under the TEMP folder.

$logLabel = $((get-date).ToString("yyyyMMddHHmmss"))
Import-Module -Name ServerManager
Install-WindowsFeature -Name Web-Server -IncludeManagementTools -LogPath "$env:TEMP\init-webservervm_webserver_install_log_$logLabel.txt"

image

When we look at the installed features, we should see that IIS Web Server is now listed there:

image

At this stage, we have a few more necessary features to install such as ASP.NET 4.5 and Management Service. Optionally, I always want to install Dynamic Content Compression and IIS Management Scripts and Tools features. To install those features, we will run the following script:

#add additional windows features
$additionalFeatures = @('Web-Mgmt-Service', 'Web-Asp-Net45', 'Web-Dyn-Compression', 'Web-Scripting-Tools')
foreach($feature in $additionalFeatures) { 
    
    if(!(Get-WindowsFeature | where { $_.Name -eq $feature }).Installed) { 

        Install-WindowsFeature -Name $feature -LogPath "$env:TEMP\init-webservervm_feature_$($feature)_install_log_$((get-date).ToString("yyyyMMddHHmmss")).txt"   
    }
}
#Set WMSvc to Automatic Startup
Set-Service -Name WMSvc -StartupType Automatic

#Check if WMSvc (Web Management Service) is running
if((Get-Service WMSvc).Status -ne 'Running') { 
    Start-Service WMSvc
}

As you can see at the end of the script, we are also setting the Management Service's startup type to automatic and finally, we are starting the service.

Now the IIS Web Server is ready, we need to get a few more bits through the Web Platform Installer v4 Command Line tool. With all of my web servers, there are two concrete tools I would like to have: Web Deploy and URL Rewrite Module. We can certainly install those manually but we can also script out their installation. WebPICMD.exe allows us to install products through command line and the following command will work for us:

$webPiProducts = @('WDeployPS', 'UrlRewrite2')
.\WebPICMD.exe /Install /Products:"$($webPiProducts -join ',')" /AcceptEULA /Log:"$env:TEMP\webpi_products_install_log_$((get-date).ToString("yyyyMMddHHmmss")).txt"

I assume that WebPICMD.exe is under your path here (if you have installed the 64x version of the product, you can find the executable file under C:\Program Files\Microsoft\Web Platform Installer). When the installation is complete, we should see the success message:

image

Well, we have completed most of the work but there are still couple of things to do. First of all, we need to allow incoming connections through TCP port 8172 because this is the port that Web Deploy will talk through. To enable that, we can go to Windows Firewall with Advanced Security window but that would be lame. Are we gonna use netsh? Certainly not :) With PowerShell 3.0, we can now control the Windows Firewall with Advanced Security Administration. This functionality is provided through NetSecurity PowerShell module but with the new dynamic module loading feature of PowerShell 3.0, we don’t need to separately import this. The following command will add the proper firewall rule to our server.

New-NetFirewallRule -DisplayName "Allow IIS Management Service In" -Direction Inbound -LocalPort 8172 -Protocol TCP -Action Allow

Lastly, we need to inform windows azure about this firewall rule as well because all the requests, which come from outside, will go through the load balancer and it doesn’t open up any ports by default (except for Remote Desktop ports). You can the endpoints through Windows Azure Portal but Windows Azure PowerShell Cmdlets to add this as well. The following command will add the proper rule. Just change the $serviceName and $vmName according to your credentials:

Get-AzureVM -ServiceName $serviceName -Name $vmName | Add-AzureEndpoint -Name "WebDeploy" -Protocol TCP -LocalPort 8172 -PublicPort 8172 | Update-AzureVM

When we look at the portal, we should see that our endpoint was created.

AzureEndpoint

Now, everything should be working perfectly. Of course you also need to add TCP port 80 to your Endpoint lists for your VM in order for your web sites to be reachable through HTTP (assuming you will only use PORT 80 for your web applications). To test everything out, I created a web application under IIS. Then, I right clicked on it and navigate to Deploy > Configure Web Deploy Publishing.

image

This will bring up another dialog. This is the place where we can configure web deploy settings. There are other ways to do this as well.

image

Just change the VM name with your VIP address and this will generate a publish profile. We can now use this publish profile file to push our web application to the server.

WebDeployPublishVS

When the publish is completed, we will see the complete result inside the Output window.

WebDeployPublishVS_2

We jumped through lots of hoops to get this done but how is this better than doing it manually? Imagine that you bring all these scripts together and run them through multiple VMs. It’s going to save a lot of time for you. I am not an IT pro. So, this is enough to make me happy because I just proved that nearly everything that a web developer needs can be automated through PowerShell or various command line tools.

Update:

I put these together inside one script file. Follow the instructions inside the script and you will be good to go.

https://gist.github.com/3742921#file_init_web_server_vm.ps1

This doesn't add the endpoints for your VM. For this, you have another script as well:

https://gist.github.com/3742921#file_init_web_server_azure_vm_endpoints.ps1

ASP.NET Web API and Handling ModelState Validation

How to handle ModelState Validation errors in ASP.NET Web API with an Action Filter and HttpError object
2012-09-11 10:39
Tugberk Ugurlu


@amirrajan, who thinks that Web API sucks :), wanted to see how model validation works in ASP.NET Web API. Instead of responding him directly, I decided to blog about it. In his post, he indicated that we shouldn’t use ASP.NET Web API because it has usability issues but I am sure that he hasn’t taken the time to really understand the whole framework. It is really obvious that the blog post is written by someone who doesn’t know much about the framework. This is not a bad thing. You don’t have to know about every single technology but if *you* express that the technology bad, you better know about it. Anyway, this is not the topic.

ASP.NET Web API supports validation attributes from .NET Data Annotations out of the box and same ModelState concept which is present all across the ASP.NET is applicable here as well. You can inspect the ModelState property to see the errors inside your controller action but I bet that you want to just terminate the request and return back a error response if the ModelState is invalid. To do that, you just need to create and register an action filer as below:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class InvalidModelStateFilterAttribute : ActionFilterAttribute {

    public override void OnActionExecuting(HttpActionContext actionContext) {

        if (!actionContext.ModelState.IsValid) {

            actionContext.Response = actionContext.Request.CreateErrorResponse(
                HttpStatusCode.BadRequest, actionContext.ModelState);
        }
    }
}

This is one time code and you don’t need to write this over and over again. CreateErrorResponse extension method for HttpRequestMessage uses HttpError class under the covers to create a consistent looking error response. The key point here is that the content negotiation will be handled here as well. the conneg will be handled according to the content negotiator service that you registered. If you don’t register one, the default one (DefaultContentNegotiator) will kick in which will be fine for 90% of the time.

I created a tiny controller which simply exposes two GET and one POST endpoint:

public class CarsController : ApiController {

    private readonly CarsContext _carsCtx = new CarsContext();

    public IEnumerable<Car> GetCars() {

        return _carsCtx.All;
    }

    public Car GetCar(int id) {

        Tuple<bool, Car> carResult = _carsCtx.GetSingle(id);
        if (!carResult.Item1) {

            throw new HttpResponseException(HttpStatusCode.NotFound);
        }

        return carResult.Item2;
    }

    public HttpResponseMessage PostCar(Car car) {

        var addedCar = _carsCtx.Add(car);
        var response = Request.CreateResponse(HttpStatusCode.Created, car);
        response.Headers.Location = new Uri(
            Url.Link("DefaultApiRoute", new { id = addedCar.Id }));

        return response;
    }
}

Here is what our Car object looks like with the validation attributes:

public class Car {

    public int Id { get; set; }

    [Required]
    public string Make { get; set; }

    [Required]
    public string Model { get; set; }
    public int Year { get; set; }

    [Range(0, 200000)]
    public float Price { get; set; }
}

And I registered the filter globally inside the Application_Start method:

protected void Application_Start(object sender, EventArgs e) {

    var config = GlobalConfiguration.Configuration;
    config.Routes.MapHttpRoute(
        "DefaultApiRoute",
        "api/{controller}/{id}",
        new { id = RouteParameter.Optional }
    );

    config.Filters.Add(new InvalidModelStateFilterAttribute());
}

Let’s retrieve the list of cars first:

image

Let’s add a new car:

image

When we make a new request, it is now on the list:

image

Now, let’s try to add a new car again but this time, our object won’t fit the requirements and we should see the error response:

image

Here is the better look of the error message that we got:

image

Here is the plain text version of this message:

{
    "Message": "The request is invalid.",
    "ModelState": { 
        "car": [
            "Required property 'Make' not found in JSON. Path '', line 1, position 57."
        ],
        "car.Make" : [
            "The Make field is required."
        ], 
        "car.Price": [
            "The field Price must be between 0 and 200000."
        ]
    }
}

This doesn’t have to be in this format. You can play with the ModelState and iterate over the error messages to simply create your own error message format.

To be honest, this is no magic and this, by itself, doesn’t make ASP.NET Web API super awesome but please don’t make accusations on a technology without playing with it first at least enough amount of time to grasp the big picture. Otherwise, IMO, it would be a huge disrespect for the people who made the technology happen.