To do this, we had to define a route in the Route Table as follows
config.Routes.MapHttpRoute(
name: “AuthorsForBook”,
routeTemplate: “api/books/{id}/authors”,
defaults: new { controller = “books”, action=“GetBookAuthors” }
);
Now this works but if we wanted another one, say for a list of Authors, select an author and then the books they have authored, the URL would be http://myapp/api/authors/{id}/books
However if we could declare the routes as attributes on top of the Api Controller’s action methods themselves, this disconnect would go away. Thanks to an active Community Member Tim McCall (of http://attributerouting.net fame), we got Attribute based routing, that among other things, allowed us to define routes as Attributes instead of adding them to a routing table manually in a config file. Since Web API is open Source, the Microsoft team reached out to Tim and it was mutually agreed to include it as a part of Core Web API and that’s how Web API 2.0 got it’s Attribute Routing feature.
Thanks to Sumit Maitra for implementing the code for this article
Hands on with a Web API 2.0 (Beta) sample
With the premise and history of Attribute Routing out of the way, let’s jump into some code.Today we are using Visual Studio 2013 Preview (Ultimate) because it also gives a glimpse of the upcoming features of Visual Studio and the bigger One ASP.NET philosophy that the ASP.NET team has been driving towards for a while.
Step 1: Fire up Visual Studio and from the New Project dialog, select ‘Web’ templates on the Left hand navigation and pick ASP.NET Web Application. Notice the lack of ASP.NET WebForms/ASP.NET MVC/Dynamic Data etc. etc. templates, only One ‘ASP.NET Web Application’ template. We provide a name and continue.
Step 2: Here we are greeted with a dialog new in Visual Studio 2013’s web tooling. It allows us to pick Web API, Web Forms, MVC, SPA, Facebook, Mobile etc.
Note the intent of One ASP.NET, there is a mix match capability, for example in the above scenario, we have selected Web API and MVC is checked by default, but we can have Web Forms in the Mix too. Similarly we can pick Web Forms by default and then add MVC to the mix. For MVC and Web Forms, the Configure Authentication button is enabled and provides further options for setting up Authentication. Without diverging too much at this point, let’s click Create Project and go ahead.
The Solution Explorer is not much different from the current Web API template
Step 3: We add two entities Author and Book
public class Author
{
public int AuthorId { get; set; }
public string Name { get; set; }
}
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public List<Author> Authors { get; set; }
}
Step 4: Ideally I wanted to add these to the DB to create a realistic Demo but unfortunately my Visual Studio 2013 Preview refused to Scaffold the entities using Entity Framework, so instead I scaffolded a controller with read/write actions only.
Step 5: I updated the Get methods and added GetAuthorBooks and GetBookAuthors methods. These were then decorated with route attributes as follows
public IEnumerable<Author> Get()
{
return new List<Author> { new Author { AuthorId = 1, Name = "Suprotim" }, new Author { AuthorId = 2, Name = "Sumit" } };
}
// GET api/authors/5
public Author Get(int id)
{
if (id == 1)
{
return new Author { AuthorId = 1, Name = "Suprotim" };
}
else
{
return new Author { AuthorId = 2, Name = "Sumit" };
}
}
[HttpGet("api/authors/{authorId}/books")]
public IEnumerable<Book> GetAuthorBooks(int authorId)
{
Book newBook = null;
if (authorId == 1)
{
newBook = new Book { BookId = 1, Title = "51 Recipes in jQuery" };
}
else
{
newBook = new Book { BookId = 2, Title = "Windows 8 Apps" };
}
return new List<Book> { newBook };
}
[HttpGet("api/books/{bookId}/authors")]
public IEnumerable<Author> GetBookAuthors(int bookId)
{
return new List<Author>();
}
Step 6: Setting up Test Harness. By default Web API projects come with HelpPage harness that auto generates API documentation. Now if we add the following Nuget Package, this drops another component that generates UI for posting data to Web API services.
PM> install-package WebApiTestClient
The WebApiTestClient needs Knockout and jQuery UI as well. These were not installed in my version of Visual Studio 2013 Preview, so I installed them separately using the following commands in the Nuget Package Management Console
PM> install-package knockoutjs
PM> install-package jquery.ui.combined
Once installed, open Areas\HelpPage\Views\Help\Api.cshtml and add this towards the bottom of the page
@Html.DisplayForModel("TestClientDialogs")
Inside the Scripts Section, add the following
@Html.DisplayForModel("TestClientReferences")
Now we are all set to test our Attribute Routing.
Step 7: Run the application! Voila BootStrap styles out of the box.
Click on API (in the header) to navigate to the Help Pages (yes, they look gross because BootStrap styling haven’t made it in there yet).
As we can see, APIs for our new ApiController documentation is ready for us.
Step 8: Click on the API link for the GetAuthorBooks
Note the depth of details including response body formats in JSON (and XML if you scroll down).
Step 9: Click on the ‘Test API’ button. This will give you a jQuery dialog with space to input URI parameters
Step 10: Put 1 as {authorId}. Hit Send.
At the backend, if we have a breakpoint, we’ll see that we received the parameter correctly:
When we continue, we get the following response in our UI
As we can see the Status is a 200, and the Body has the array of books that this author has written (which as we saw is hardcoded).
We can tryout the GetBookAuthors API similarly as well.
Essentially we were able to manipulate the Routes via Attributes instead of manually adding routes in Route Tables. Thing to note is Attribute routes are not magic and they do get added to the Route table, it’s just that applying routes via Attributes makes things more coherent and compact from an API declaration point of view.
Other Route Attribute Features
Apart from above routing feature, Route Attributes can enforce the followingDefault parameters: The following route implies default authorId is 99
[HttpGet("api/authors/{authorId=99} ")]
public Author Get(int authorId)
Optional Route Parameters: Similarly the following syntax implies optional parameters
[HttpGet("api/authors/{authorId?} ")]
public Author Get(int authorId)
Constraining Route Types: Route constraints can also be specified and we can set constraints based on data type/length/min/max etc. The following sample shows Integer data type constraint.
[HttpGet("api/authors/{authorId:int} ")]
public Author Get(int authorId)
Conclusion
The ASP.NET Web Tooling team is hard at work bringing the new One ASP.NET vision to reality. In the meantime, Web API 2.0 is coming with some cool new features. Today we saw only one of these i.e. AttributeRouting. As the releases stabilizes, we will see more of the new stuff in Web API 2.0.Note: If you want AttributeRouting NOW (in MVC and WebAPI), use the Nuget Package created by Tim McCall, for details refer to his site http://attributerouting.net/
Download the source code of this article (Github)
No comments:
Post a Comment