This is a high level overview of new stuff that appeared within VS2011 release. So, let’s briefly look inside. Today will take a look on changes appeared to Web API.
Web API
The biggest and most important change as for me is integration of Web API into ASP.NET. Web API is most known as WCF Web API - an attempt of .NET team build framework for creation of RESTfull services based on WCF infrastructure. There was several releases of WCF Web API made and general feedback from community was - “it’s good enough”. Since when, Microsoft did a strategic change, merged WCF Web API and ASP.NET teams together, so both products to be developed in sync. From now Web API is integral part of ASP.NET (and does not have any WCF prefix any more) and called ASP.NET Web API. It is not just re-branding, but it reflects changes both the programming model and processing architecture.
Simple Start
If we create a new ASP.NET MVC4 application, we see the following change into
global.asax
file.routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
MapHttpRoute
is new extension method for RouteCollection
. Similarly to ASP.NET MVC routing definition, it maps HTTP request with matching URL into corresponding API controller action. By default, the are all prefixed with “api” to do not “interfere” to ASP.NET MVC routing. It’s not a problem to change that prefix to anything you want, like “services”, “methods” etc./api/contacts/ <- Web API /api/contacts/1 <- Web API /contacts/1 <- ASP.NET MVC
The API controllers are really similar to ASP.NET MVC controllers. Instead of inherit from
Controller
class, they inherited from ApiController
class. Instead of returning ActionResult
from action, in API controllers you return either IEnumerable
or concrete instance, like Product
(there are some more dedicated scenarios with returning types, we will see later).
By just looking into example from project template it is very easy to understand, what’s going on. There are some small details you should know before API controller usage.
Action methods naming
API controllers are “Convention over configuration” based. The actual HTTP verb that action handles could be specified in method name.
public class ProductsController : ApiController { // Handles GET public IEnumerable<Product> Get() { } // Handles POST public Product Post(Product product) { } // Handles PUT public Product Put(Product product) { } // Handles DELETE public void Delete(int id) { } }
This convention applies only to GET, POST, PUT, and DELETE methods. You might be more specific in methods names, like
GetProducts
or DeleteProduct
, the important is the prefix (Get, Post, Put etc.) of method.
If you don’t want to rely of named based conventions, you can explicitly specify target HTTP verb by decorating methods with HttpGet, HttpPut, HttpPost, or HttpDelete attribute.
public class ProductsController : ApiController { [HttpGet] public IEnumerable<Product> AllProducts() { } [HttpPost] public Product CreateProduc(Product product) { } [HttpPut] public Product UpdateProduct(Product product) { } [HttpDelete] public void DeleteProduct(int id) { } }
One handler per one controller
API Controller are different from ASP.NET MVC controller. The main difference is that API controller handles exactly one HTTP request belongs to particular entity.
If you try to create the code like:
public class ProductsController : ApiController { public IEnumerable<Product> Get() { } public IEnumerable<Product> GetAnother() { } }
It would be build OK, but on a runtime if you try to access ‘/api/products’, you will get an exception:
"Multiple actions were found that match the request: \u000d\u000aSystem.Collections.Generic.IEnumerable`1[MvcApplication7.Api.Controllers.Product] Get() on type MvcApplication7.Api.Controllers.ProductsController\u000d\u000aSystem.Collections.Generic.IEnumerable`1[MvcApplication7.Api.Controllers.Product] GetAnother() on type MvcApplication7.Api.Controllers.ProductsController"
The less stuff is very similar to something we get used in ASP.NET MVC. And you might think - why do we need this Web API at all, I can do exactly the same stuff with good-n-old ASP.NET MVC controllers? Not exactly. Web API has several killer features that makes it favorite for data oriented API’s. Let’s go on.
Content Negotiation
Content Negotiation is the process for mutual agreement between client and server about the received/sent data formats. Good news here, Web API does a lot of job for you, leaving content negotiation internals behind the scene. Let’s take a brief look of how things happen.
When client sends HTTP request to server, besides the query string and payload it also provides different kind information. This information is being placed into HTTP header and provides server with specific details for better understanding each other. In particular, it contains
Accept
header field which specifies client preferences on response format. I’m going use Fiddler to check how Web API behaves on different conditions.
First, let’s do not specify the
Accept
field at all. So, the payload we going to send to server from our client (Fiddler) will be like:GET /api/products HTTP/1.1 User-Agent: Fiddler Host: localhost:5589
For that request, we will receive the response like:
HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Type: application/json; charset=utf-8 Expires: -1 Server: Microsoft-IIS/7.5 X-AspNet-Version: 4.0.30319 X-SourceFiles: =?UTF-8?B?RDpcRGV2ZWxvcG1lbnRcUHJvamVjdHNcZXhwZXJpbWVudHNcTXZjQXBwbGljYXRpb243XE12Y0FwcGxpY2F0aW9uN1xhcGlccHJvZHVjdHM=?= X-Powered-By: ASP.NET Date: Mon, 19 Mar 2012 17:31:23 GMT Content-Length: 88 [{"Description":"iPad","Id":1,"Price":1000},{"Description":"iPhone","Id":2,"Price":500}]
As you can see, the default Content-Type is “application/json; charset=utf-8”, there is a json string in HTTP response payload.
Let’s make our request a little more specific.
GET /api/products HTTP/1.1 User-Agent: Fiddler Host: localhost:5589 Accept: text/xml
The corresponsing response:
HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Type: text/xml; charset=utf-8 Expires: -1 Server: Microsoft-IIS/7.5 X-AspNet-Version: 4.0.30319 X-SourceFiles: =?UTF-8?B?RDpcRGV2ZWxvcG1lbnRcUHJvamVjdHNcZXhwZXJpbWVudHNcTXZjQXBwbGljYXRpb243XE12Y0FwcGxpY2F0aW9uN1xhcGlccHJvZHVjdHM=?= X-Powered-By: ASP.NET Date: Mon, 19 Mar 2012 17:33:34 GMT Content-Length: 329 <?xml version="1.0" encoding="utf-8"?><ArrayOfProduct xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Product><Id>1</Id><Description>iPad</Description><Price>1000</Price></Product><Product><Id>2</Id><Description>iPhone</Description><Price>500</Price></Product></ArrayOfProduct>
As you can see, without any code changes we made it “adapt” for particular client needs. This is a very decent feature of Web API and available for use, just from the box. You even don’t need to care about it at all. Leave the content negotiation for the infrastructure.
IQueryable<T> Support
Next cool feature is IQueryable<T> support. If you need to, instead of returning “plain” IEnumerable objects from the API action, you might return IQueryable<T>. Why?
Remember the times we implemented paging & sorting with ASP.NET MVC application. It was possible of cause, but it required a lot of manual job. Actions had to be extended with additional parameters, code have to respect those parameters and return exact portion of data we require to. The same story with sorting. In Web API it much simpler.
Change the signature and return type to IQueryable.
public IQueryable<Product> Get() { return _storage.AsQueryable(); }
Now, if Web API sees the method like that, it will allow to access with with Open Data Protocol (OData) query string parameters. OData provides support for following queries: $filter, $orderby, $skip, $top.
Now, if I do the request:
http://localhost:5589/api/products?$top=3
I will receive, 3 top products. Or something like,
http://localhost:5589/api/products?$skip=2&$top=3
I will skip 2 and take rest 3. In short, having IQueryable and 4 OData query parameters it’s much more easy to do the stuff required more time before.
Hosting
Hosting is a feature of Web API allow to run service inside the different hosts. What does it mean?
We are much get used to ASP.NET hosting as default. I saw no problem with that at all till working on one of my recent projects. The problem is for ASP.NET pipeline you need to have a web server (IIS), but web server always have some limitations (permissions and stuff). For simple things, that does not require any IIS benefits it is easier to host application just in .exe assembly. It’s now possible with Web API.
We have several hosting providers out of the box: self-hosting and web-hosting. Besides of that there are already some provided by community Louis DeJardin created a host on top of OWIN and Pedro FĂ©lix host for Azure.
Also, there is a great article by Pedro Felix about in-memory hosting. This is very useful type of hosting for unit testing of services.
IoC improvements
Since Web API now is inside ASP.NET MVC, it uses the same strategy of resolving types byIDependencyResolver. That means that Web API classes are now supporting same IoC style as ASP.NET MVC controller classes. Being setup once you can put different dependencies inside API class constructor.
public class ProductsController : ApiController { public ProductsController(IServiceProvider service, IRepository<Product> productRepository) { // .. }
Conclusions
This is not everything, but very light overview of new stuff coming within ASP.NET MVC4. ASP.NET Web API is very nice addition to framework. There are already some good feedback, so let’s hope it will be even more improved toward release.
No comments:
Post a Comment