The Problem Solver

Tell me and I will forget
Show me and I will remember
Involve me and I will understand
- Confucius -

Google Ads

This Blog

Syndication

Search

Tags

News





  • View Maurice De Beijer's profile on LinkedIn

Community

Email Notifications

Explore

Archives

March 2012 - Posts

In this podcast Dennis Vroegop speaks with Jeff Prosise about the future of software development for the .NET developer.

Links:

Thanks to out sponsor RedGate.

 

http://dotned.nl/PodCasts.aspx?id=27

 

Enjoy

TheProblemSolver
DotNetEvents

Posted by Maurice | with no comments

Having the ASP.NET Web API as a REST service returning data is kind of nice but to be efficient on the wire we don’t want to return more data that required only to discard it in the client.

 

As we have seen in a previous post just returning a collection data was real easy.

 

As it turns out changing the service so the client can filter data is almost just as easy. In the previous example we returned an IEnumerable<Product>. All we need to do is change this to return an IQueryable<Product> instead of an IEnumerable<Product> and most of the work is done.

   1: public class ProductsController : ApiController
   2: {
   3:     private NorthwindContext _db = new NorthwindContext();
   4:  
   5:     // GET /api/<controller>
   6:     public IQueryable<Product> Get()
   7:     {
   8:         return _db.Products;
   9:     }
  10:  
  11:     // GET /api/<controller>/5
  12:     public Product Get(int id)
  13:     {
  14:         return _db.Products.Single(p => p.ProductID == id);
  15:     }
  16: }

Loading the products with the original URL returns exactly the same result as before.

image

But now the client can also decide to order and filter data. This request “http://localhost:6876/api/Products?$orderby=ProductName&$skip=10&$top=5” returns only product 11 to 15 ordered by the product name.

image

You can also search for specific data using the $filter clause like this “http://localhost:6876/api/Products?$filter=ProductName eq 'Chocolade'

image

Or something like “http://localhost:6876/api/Products?$filter=startswith(ProductName, 'Cha')

image

 

Sweet right? And all of that by just changing IEnumerable<T> to IQueryable<T> Smile 

 

In fact the only thing I would like to see added to this was projections. After all we don’t do a “Select * from Table where …” either right?

 

Enjoy!

Posted by Maurice | 2 comment(s)
Filed under: , , , ,

We where just bitten by this one and the problem was not immediately obvious.

You will see some error like

The name 'model' does not exist in the current context

or

'System.Web.WebPages.Html.HtmlHelper' does not contain a definition for 'ActionLink' and no extension method 'ActionLink' accepting a first argument of type 'System.Web.WebPages.Html.HtmlHelper' could be found (are you missing a using directive or an assembly reference?)

 

image

 

Additionally when you check the IntelliSense of @Html you will not see some of the extension methods like Action() or ActionLink()

 

Fixing it is not hard one you know the problem.

Include the webpages:Version key with a value of 1.0.0.0 in the appSettings section of your web.config, fix the references for System.Web.WebPages and System.Web.Helpers and restart Visual Studio 2010 to fix the problem.

   1: <appSettings>
   2:   <add key="webpages:Version" value="1.0.0.0" />
   3:   <add key="ClientValidationEnabled" value="true" />
   4:   <add key="UnobtrusiveJavaScriptEnabled" value="true" />
   5: </appSettings>

 

See the Known Issues and Breaking Changes in the ASP.NET MVC 4 Release notes. And this only applies to projects created using ASP.NET MVC 3 RTM. The projects created by the ASP.NET MVC 3 Tools Update release are fine.

 

Enjoy!

 

TheProblemSolver
DotNetEvents

Posted by Maurice | 2 comment(s)
Filed under: , ,

With REST there is not a lot required on the client as far as sending requests goes. As long as you can send HTTP GET requests you are good to go and there are very few programming stacks that don’t allow for some form of doing that. Of course just doing an HTTP GET is going to give you some data back and you still have to understand that data but that is an application specific issue.

In order to make life even easier the ASP.NET Web API adds some client support in the form of the HttpClient class. But first lets see what happens if we just hit an ASP.NET Web API endpoint with a simple client.

I am using Entity Framework Code First here and the model and context look like this:

   1: public class Product
   2: {
   3:     public int ProductID { get; set; }
   4:     public string ProductName { get; set; }
   5:     public decimal UnitPrice { get; set; }
   6: }
   7:  
   8: public class NorthwindContext : DbContext
   9: {
  10:     public DbSet<Product> Products { get; set; }
  11: }
 
And the ASP.NET Web API controller looks like this:
   1: public class ProductsController : ApiController
   2: {
   3:     private NorthwindContext _db = new NorthwindContext();
   4:  
   5:     // GET /api/<controller>
   6:     public IEnumerable<Product> Get()
   7:     {
   8:         return _db.Products.ToList();
   9:     }
  10:  
  11:     // GET /api/<controller>/5
  12:     public Product Get(int id)
  13:     {
  14:         return _db.Products.Single(p => p.ProductID == id);
  15:     }
  16:  
  17:     protected override void Dispose(bool disposing)
  18:     {
  19:         if (disposing && _db != null)
  20:         {
  21:             _db.Dispose();
  22:             _db = null;
  23:         }
  24:         base.Dispose(disposing);
  25:     }
  26: }
 
 
Given that the Web API supports returning both XAML and JSON it would appear the following code would work just fine.
 
   1: static void Main(string[] args)
   2: {
   3:     var baseUrl = @"http://localhost.:6876/api/products";
   4:     var xml = XElement.Load(baseUrl);
   5:  
   6:     foreach (var product in xml.Descendants("Product"))
   7:     {
   8:         Console.WriteLine("Product '{0}' costs {1:C}", (string)product.Element("ProductName"), (decimal)product.Element("UnitPrice"));
   9:     }
  10: }

 

Unfortunately it doesn’t and we receive an XmlException with the message “Data at the root level is invalid”. The reason is that the XElement sends the request to the server without specifying an accept header. And where in the previous WCF Web API this would have worked because XML was the default type if nothing was specified this has changed. With the ASP.NET Web API the default is JSON. So this request returns a JSON data stream the XElement can’t handle. What we need to do is specify we want XML using the HTTP Accept header. There are different ways we can do this but here I am going to the the client side support in the form of the HttpClient.

 

Using the HttpClient

First we need to add a NuGet package named System.Net.HTTP that contains the required classes

image

With that in place we can start using the HttpClient instead. The code is a bit longer but that is mainly because we still need to set the HTTP Accept header to return XML instead of the default JSON

   1: static void Main(string[] args)
   2: {
   3:     var baseUrl = @"http://localhost.:6876/api/products";
   4:     var client = new HttpClient();
   5:     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
   6:     var stream = client.GetStreamAsync(baseUrl).Result;
   7:     var xml = XElement.Load(stream);
   8:  
   9:     foreach (var product in xml.Descendants("Product"))
  10:     {
  11:         Console.WriteLine("Product '{0}' costs {1:C}", (string)product.Element("ProductName"), (decimal)product.Element("UnitPrice"));
  12:     }
  13: }

And this works just fine Smile

image

Loading a single product is just as easy

   1: var baseUrl = @"http://localhost.:6876/api/products";
   2: var client = new HttpClient();
   3: client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
   4: var stream = client.GetStreamAsync(baseUrl + @"\42").Result;
   5: var product = XElement.Load(stream);
   6:  
   7: Console.WriteLine("Product '{0}' costs {1:C}", (string)product.Element("ProductName"), (decimal)product.Element("UnitPrice"));

image

 

Adding new data using the HttpClient

Adding a new product is almost just as easy. First we need to create a valid XML document containing a new product, then turn it into a steam and we can post it.

   1: var newProduct = new XElement("Product", new XElement("ProductName", "ASP.NET Web API"), new XElement("UnitPrice", 0));
   2: var stream = new MemoryStream();
   3: newProduct.Save(stream);
   4: stream.Position = 0;
   5:  
   6: var baseUrl = @"http://localhost.:6876/api/products";
   7: var client = new HttpClient();
   8: var content = new StreamContent(stream);
   9: content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
  10:  
  11: var response = client.PostAsync(baseUrl, content).Result;
  12: Console.WriteLine("StatusCode: {0}", response.StatusCode);

 

This code might seem a bit verbose but that is mainly because the client is real simple and uses POX and therefore a StreamContent. There are also richer ways of doing so with declared types and the ObjectContent<T>. The result is a predictable OK status with the new product being added to the database.

image

Of course this should really have been a 201 Created with the URL pointing to the location of the new resource but we still need to look at how to control the response message from the ApiController.

 

Enjoy!

 

TheProblemSolver
DotNetEvents

Posted by Maurice | with no comments
Filed under: , , , ,

 

In the previous blog post I demonstrated how to get started with the ASP.NET Web API and retrieve some products data from the Northwind database. Something that was really easy to do Smile But quite often we want to update data just as much as we want to retrieve it.

 

A quick recap of REST and HTTP methods used.

The convention for REST service as defined by Roy Fielding is to use different HTTP methods to signify our intent with the HTTP request. The HTTP GET method, by far the most commonly used one on the internet, is used to retrieve data. This should be a completely save action and have no side effects whatsoever for the client to worry about. When we start changing data we start using other HTTP methods. The following table are the most commonly used HTTP methods and the database CRUD actions they to.

HTTP Method CRUD Action
Get Select
Post Insert
Put Update a complete entity
Patch Update a partial entity
Delete Delete an entity

 

Quite simple right? And even the Patch method isn’t used that often, in most cases just 4 methods are used.

 

Implementing update methods in the ASP.NET Web API

As I explained in my last post the ASP.NET Web API uses convention over configuration and by convention is to create an ApiController with functions where the name starts with the HTTP method to support. We can do things differently with attributes if we want to but for now lets just stick to the convention.

 

Adding new products to the database.

As we have just seen creating new data is done with a POST method so we need to implement a Post() function in our ProductsController. Doing so is quite easy:

   1: public class ProductsController : ApiController
   2: {
   3:     private NorthwindEntities _db = new NorthwindEntities();
   4:  
   5:     // GET /api/<controller>
   6:     public IEnumerable<Product> Get()
   7:     {
   8:         return _db.Products.ToList();
   9:     }
  10:  
  11:     // GET /api/<controller>/5
  12:     public Product Get(int id)
  13:     {
  14:         return _db.Products.Single(p => p.ProductID == id);
  15:     }
  16:  
  17:     // POST /api/<controller>
  18:     public void Post(Product product)
  19:     {
  20:         _db.AddToProducts(product);
  21:         _db.SaveChanges();
  22:     }
  23:  
  24:     protected override void Dispose(bool disposing)
  25:     {
  26:         if (disposing && _db != null)
  27:         {
  28:             _db.Dispose();
  29:             _db = null;
  30:         }
  31:         base.Dispose(disposing);
  32:     }
  33: }

 

Of course in reality a Post action would be somewhat more complicated. For starters we would need some error handling in case the data was invalid. Another issue is that, if everything goes well, we are just returning a 200 Ok status where we should be returning a 201 Created status with the location of the newly created resource. But for now this is good enough.

We still need a way to test this and the perfect tool to monitor and test HTTP related traffic if Fiddler. Using Fiddler we can POST a new product, in this case the ASP.NET Web API itself, to the server.

image

And as we can see when we check the database or use the GET method in the correct URL the new record is inserted.

image

 

There are two interesting things to note here.

  1. All I had to do is have a function were the name starts with Post and it is automatically called when an HTTP POST is received.
  2. The function parameter is of type Product and the ASP.NET Web API does the proper deserialization for us.

How easy can they make things? Smile

 

And implementing PUT and DELETE would work in the same way.

The “complete” ApiController looks like this:

   1: public class ProductsController : ApiController
   2: {
   3:     private NorthwindEntities _db = new NorthwindEntities();
   4:  
   5:     // GET /api/<controller>
   6:     public IEnumerable<Product> Get()
   7:     {
   8:         return _db.Products.ToList();
   9:     }
  10:  
  11:     // GET /api/<controller>/5
  12:     public Product Get(int id)
  13:     {
  14:         return _db.Products.Single(p => p.ProductID == id);
  15:     }
  16:  
  17:     // POST /api/<controller>
  18:     public void Post(Product product)
  19:     {
  20:         if (ModelState.IsValid)
  21:         {
  22:             _db.AddToProducts(product);
  23:             _db.SaveChanges();
  24:         }
  25:     }
  26:  
  27:     // PUT /api/<controller>/5
  28:     public void Put(int id, Product product)
  29:     {
  30:         var orgProduct = _db.Products.Single(p => p.ProductID == id);
  31:         // Copy properties from product to orgProduct
  32:         _db.SaveChanges();
  33:     }
  34:  
  35:     // DELETE /api/<controller>/5
  36:     public void Delete(int id)
  37:     {
  38:         var product = _db.Products.Single(p => p.ProductID == id);
  39:         _db.Products.DeleteObject(product);
  40:         _db.SaveChanges();
  41:     }
  42:  
  43:     protected override void Dispose(bool disposing)
  44:     {
  45:         if (disposing && _db != null)
  46:         {
  47:             _db.Dispose();
  48:             _db = null;
  49:         }
  50:         base.Dispose(disposing);
  51:     }
  52: }

Enjoy!

 

TheProblemSolver
DotNetEvents

Posted by Maurice | with no comments
Filed under: , , , ,

Some time ago I did a number of blog posts about the beta versions of the WCF Web API. As it turns out the WCF Web API team has moved into the ASP.NET team, a good thing as far as I am concerned, and as a result it is now called ASP.NET Web API. Now this is much more that just a name change. For starters there is very little of the WCF bits still involved, in fact when you use ASP.NET as a host none at all. As a result it takes on quite a few characteristics of ASP.NET MVC with convention over configuration. Quite a difference from WCF which is all about taking configuration to the max.

In this blog post I am going to show how to get started with the ASP.NET Web API.

 

What is the ASP.NET Web API all about?

The ASP.NET Web API is a framework build on top of the core ASP.NET engine for creating REST services. And REST services have become relatively popular as a result of the popularity of web and mobile applications where the traditional SOAP service are a bit to rigid and cumbersome to work with. Now this certainly doesn’t mean that SOAP services are going to disappear but we will see an increasing number of REST services as an addition.

On .NET there are a number of different options for REST services. There are some pretty good open source alternatives like OpenRasta. And the WCF team has made a number of attempts at providing a REST framework in the past which where usable but less successful. The WCF Web API was a big improvement as that was much more inline with HTTP, as a RESTful service should be, but the tie to WCF was a bit a problem as the whole WCF stack was architected and build with SOAP in mind.

The ASP.NET Web API should provide a far more flexible framework for building RESTful services.

The ASP.NET Web API bits ship as part of ASP.NET MVC4 beta right now but that doesn’t mean you are tied to using an MVC application. Personally I like MVC but if you prefer ASP.NET WebForms that will work fine, in fact you can use any ASP.NET as a host. For that matter if you don’t want an ASP.NET host it is perfectly fine to self host the ASP.NET Web API in whatever host application you want. Console, Windows Service you name it and it should just work. But I am going to leave self hosting for another post as I suspect most people will host their Web API as part of an ASP.NET web site. So in this demo I am going to use ASP.NET MVC 4.

 

Creating a ASP.NET MVC 4 new application

When you create a new MVC 4 application you get the option of creating a Web API project. There is nothing wrong with that but in this case I am not going to do that and I am just going to create a standard Internet Application and add a Web API to that.

image

I have a copy of the Northwind database on my machine and I am going to create a Web API service to return the products data from that database. So first I need to create a Entity Framework model with the table definition.

image

 

Next we need a controller to return the product data. Instead of a normal MVC controller we should be using an ApiController here. An ApiController is a special type of controller all geared towards creating a REST service. The convention is to store these in an API folder. The same convention as with regular MVC applies so we have to create a controller named ProductsController.
image

The resulting code is quite simple but it shows us how to get started with an ASP.NET Web API controller.

   1: public class ProductsController : ApiController
   2: {
   3:     // GET /api/<controller>
   4:     public IEnumerable<string> Get()
   5:     {
   6:         return new string[] { "value1", "value2" };
   7:     }
   8:  
   9:     // GET /api/<controller>/5
  10:     public string Get(int id)
  11:     {
  12:         return "value";
  13:     }
  14:  
  15:     // POST /api/<controller>
  16:     public void Post(string value)
  17:     {
  18:     }
  19:  
  20:     // PUT /api/<controller>/5
  21:     public void Put(int id, string value)
  22:     {
  23:     }
  24:  
  25:     // DELETE /api/<controller>/5
  26:     public void Delete(int id)
  27:     {
  28:     }
  29: }

In fact if we run the application as is and navigate to the URL for this controller, in my case http://localhost:3438/api/products but your port number is going to be different, we can see it already returns some data.

image

So why does this URL work? Well out of the box an ASP.NET MVC4 project has 2 routes configured. One for the normal controller and the other for Web API controllers. You can find the relevant code in the global.asax.

   1: public static void RegisterRoutes(RouteCollection routes)
   2: {
   3:     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
   4:  
   5:     routes.MapHttpRoute(
   6:         name: "DefaultApi",
   7:         routeTemplate: "api/{controller}/{id}",
   8:         defaults: new { id = RouteParameter.Optional }
   9:     );
  10:  
  11:     routes.MapRoute(
  12:         name: "Default",
  13:         url: "{controller}/{action}/{id}",
  14:         defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
  15:     );
  16: }

Of course you are free to change the path but for now I am going to leave it as is as the default convention of putting Web API request in an API URL makes sense to me.

 

There are a couple of things to note in the code for the ProductsController. First of all there are no attributes used. WCF was all about attributes, MVC is all about conventions. So the the convention is if the function name starts with Get it will respond to an HTTP GET method, if it starts with Post it responds to an HTTP POST method and so on. You can change this with attributed but it sounds perfectly fine and good enough for me. What matters is the start of the function name. So changing it to GetProducts() will work just fine but using LoadProducts() will result in the following error:

The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.String Get(Int32)' in 'WebAPIDemo.Api.Controllers.ProductsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.

Not quite a clear an error message as I would have liked Sad smile But then it is only a beta so there is hope.


Returning some actual product data from our Web API service

Doing that is actually quite easy. All we need to do is redefine the Get() function to return an IEnumerable<Product>, instantiate a NorthwindEntities context and return the Products collection.

   1: public class ProductsController : ApiController
   2: {
   3:     private NorthwindEntities _db = new NorthwindEntities();
   4:  
   5:     // GET /api/<controller>
   6:     public IEnumerable<Product> Get()
   7:     {
   8:         return _db.Products.ToList();
   9:     }
  10:  
  11:     protected override void Dispose(bool disposing)
  12:     {
  13:         if (disposing && _db != null)
  14:         {
  15:             _db.Dispose();
  16:             _db = null;
  17:         }
  18:         base.Dispose(disposing);
  19:     }
  20: }

Refreshing the page in the browser now returns the products data as expected:

image

Returning the a single product is just as easy. Just implement the Get(int id) function to return the correct Product as follows.

   1: // GET /api/<controller>/5
   2: public Product Get(int id)
   3: {
   4:     return _db.Products.Single(p => p.ProductID == id);
   5: }

 

Not surprisingly just the single product is returned when we add a product id to the URL.

image


That is enough for a first post. Next time I am going to take a look at what it takes to add new or update existing product data using the ASP.NET Web API.

 

Enjoy!

 

TheProblemSolver
DotNetEvents

Posted by Maurice | 1 comment(s)
Filed under: , , , , ,

In deze podcast spreekt Hassan Fadili Gert Drapers over zijn carrière bij Microsoft en zijn sessies data georiënteerde sessies tijdens de laatste TechDays. Gert vertelt onder meer hoe hij bij Microsoft begonnen is en hoe hij de eerste SQL server tools voor developers, ook wel Data-Dude genoemd ontwikkelt heeft.

Links:

http://www.dotned.nl/PodCasts.aspx?id=26

 

Enjoy!

 

TheProblemSolver
DotNetEvents

Posted by Maurice | with no comments
Filed under: , ,