Archive

Archive for the ‘Web API’ Category

Generate ASP .NET Web API Controllers using Templates

March 20, 2013 Leave a comment

 

In a precedent post we have shown how to build an ASP .NET WebAPI Controller to access the generated Business Object Model (BOM).
 
We saw how to implement manually a Web API Controller for one entity of our model.
 
Now, we are going to see how to build a Template in order to automatically generate a Web API Controller for each one of the entities in our model.
 
We are going to use the “CarRental” demo project included with CodeFluent Entities. It was the same sample project that we used when we created the Web API Controller.
 
The first thing we have to do is create our template file.

 

Templates location

Templates location

 

Our template must be prefixed by “[Template]”.

 
Before writing our template let’s create a producer for our template.
 

Template Producer

Template Producer


 
The “Source Directory” is the location of our template folder and the “Target Directory” is where our files will be generated, in my case I have a folder called “ApiControllers” in my MVC 4 Web Application project.
 
At the bottom of our template we fix some parameters.

[%@ template
enumerable="Producer.Project.Entities"
enumerableItemName="entity"
enumerableTargetPathFunc='Path.Combine(Path.GetDirectoryName(TargetPath), entity.Name) + "Controller.cs"' %]

 
That means that we are going to iterate through all the entities in our project (Producer.Project.Entities). Inside the template we can access the current enumerated entity by the name “entity”. And the name of the generated file (for each entity) will be “[EntityName]Controller.cs”.
 
Now we can write the content of our Api Controller. Let’s start by creating only the Controller class.

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the Template Producer.
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace [%=entity.Namespace%].Web.ApiControllers
{
	using System.Collections.Generic;
	using System;
	using System.Net;
	using System.Net.Http;
	using System.Web.Http;

    public class [%=entity.Name%]Controller : ApiController
    {
    }
}

 
If we build our CodeFluent Entities project we must see our Api Controllers appear.
 

Generated API Controllers

Generated API Controllers


 
Now let’s implement the Api Controller methods. We will use almost the same implementation as we did in the post “Using ASP .NET Web API with CodeFluent Entities”.

// GET api/[%=entity.Name%]
public IEnumerable<[%=entity.Name%]> Get()
{
    return [%=entity.SetFullTypeName%].LoadAll();
}

// POST api/[%=entity.Name%]
public HttpResponseMessage Post([FromBody][%=entity.Name%] value)
{
	if(value == null || !value.Save())
	{
		return Request.CreateResponse(HttpStatusCode.BadRequest);
	}
	return Request.CreateResponse(HttpStatusCode.OK, value);
}

// PUT api/[%=entity.Name%]
public HttpResponseMessage Put([FromBody][%=entity.Name%] value)
{
	if(value == null || !value.Save())
	{
		return Request.CreateResponse(HttpStatusCode.BadRequest);
	}
	return Request.CreateResponse(HttpStatusCode.OK, value);
}

 

For the Delete and Get (for a single element) methods we need to do some work to manage the entity keys. Indeed, it is possible that some entities have multiple keys.

// DELETE api/[%=entity.Name%]/*ids
public HttpResponseMessage Delete(string ids)
{
	ids = ids.Replace('/', '|');
    [%=entity.ClrFullTypeName%] value = [%=entity.ClrFullTypeName%].LoadByEntityKey(ids);
	if(value != null && value.Delete())
	{
		return Request.CreateResponse(HttpStatusCode.NoContent);
	}
	return Request.CreateResponse(HttpStatusCode.NotFound);
}

	// GET api/[%=entity.Name%]/*ids
public [%=entity.Name%] Get(string ids)
{
	ids = ids.Replace('/', '|');
    [%=entity.ClrFullTypeName%] value = [%=entity.ClrFullTypeName%].LoadByEntityKey(ids);
	if(value == null)
	{
		throw new HttpResponseException(HttpStatusCode.NotFound);
	}
	return value;
}

 
We use a feature in MVC (and Web API) routes that allows us to handle a variable number of segments in a URL pattern.
 
So we will need to make some changes in our routing configuration. I have registered my routes for the Web API in a separate file called “WebApiConfig” (cf. Using ASP .NET Web API with CodeFluent Entities). The trick lies in the “*” before the parameter name (*ids).

config.Routes.MapHttpRoute(
                           name: "DefaultApi",
                           routeTemplate: "api/{controller}/{*ids}",
                           defaults: new { ids = RouteParameter.Optional }
                          );

 

For example, in order to retrieve a specific instance of the entity “InventoryDetail” we need three keys, so the URL to get an instance of “InventoryDetail” will be: http://server/api/InventroyDetail/1/2/3.

 
If we build our CodeFluent Entities project and take a look at the inside of a Controller we will see the complete implementation.
 
Now we only have to test our Controllers. We can use the same tests that we have done in the precedent post related to the ASP .NET Web API.

 
Regards.
 
Pablo Fernandez Duran

Using ASP .NET Web API with CodeFluent Entities

February 27, 2013 2 comments

This post will guide you in implementing a service layer over HTTP using ASP .NET Wet API and CodeFluent Entities.

WCF is great to expose SOAP based web services and even JSON services. However WCF does not capitalize all the possibilities that the HTTP protocol can provide.

Indeed, HTTP is a real application-level protocol, and while WCF uses HTTP only as a transport protocol (as could be TCP, UDP, named Pipes…) the ASP .NET Web API takes advantage of all the features that the HTTP protocol provides as:

  • Actions defined by verbs: GET, POST, PUT, DELETE.
  • Headers that can suggest extra information like caching, requested content, security.
  • A body that can be used for any kind of content (not only XML like for SOAP web services).
  • URIs that can be used for identify resources and actions.

For this post we will use the CodeFluent Entities demo project ‘CarRental’.

Car Rental Demo Project

Car Rental Demo Project

And we are going to add a Persistence producer (SQL Server 2012 for me), a Business Object Model (BOM) producer and a Service sub producer so we can use the WCF serialization.

Producers

Producers

We will host our services in an ASP .NET MVC 4 web site (ASP .NET Web API can also be hosted as a service), more information here.

MVC 4 Internet Application

MVC 4 Internet Application

The ASP .NET Web API provides a custom ‘Controller’ that handles the HTTP actions (GET, POST, PUT, and DELETE) as well as the content negotiation (XML, JSON, HTML…), this base controller is of type System.Web.Http.ApiController.

As the HTTP services are resource-oriented services we may want to create one Controller per Entity in our model. We will lead this post using only the Entity ‘CarGroup’ of our model. We can create some instances of type CarGroup to have some data to test.

So we first need to create a controller that extends from ‘ApiController’. We will call it ‘CarGroupController’.

CarGroupController

CarGroupController

We can see in the code of our new Controller that some methods have been created. These methods will be associated with the HTTP actions (verbs) GET, POST, PUT and DELETE.

CarGroupController Acitons

CarGroupController Acitons

Besides, adding an Api Controller made a route configuration specific to ASP .NET Web API (App_Start->WebApiConfig.cs), so the routes for our resources will be {base url}/api/{controller}/{id}. For example, we will have http://localhost:21020/api/cargroup.

ASP .NET Web API uses a ‘Convention over Configuration’ approach so the prefix of each method matches a specific HTTP action.

We are now going to implement the Actions.

To get all the instances of type CarGroup :

// GET api/cargroup
public IEnumerable<CarGroup> Get()
{
    return CarGroupCollection.LoadAll();
}

To get one CarGroup by Id:

// GET api/cargroup/5
public CarGroup Get(int id)
{
    CarGroup carGroup = CarGroup.Load(id);
    if (carGroup == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    return carGroup;
}

To create a new CarGroup :

// POST api/cargroup
public HttpResponseMessage Post([FromBody]CarGroup carGroup)
{
    if (carGroup == null || !carGroup.Save())
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
    return Request.CreateResponse(HttpStatusCode.OK, carGroup);
}

To update a CarGroup :

// PUT api/cargroup
public HttpResponseMessage Put([FromBody]CarGroup carGroup)
{
    if (carGroup == null || !carGroup.Save())
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
    return Request.CreateResponse(HttpStatusCode.OK, carGroup);
}

And finally to delete a CarGroup :

// DELETE api/cargroup/5
public HttpResponseMessage Delete(int id)
{
    CarGroup carGroup = CarGroup.Load(id);
    if (carGroup != null && carGroup.Delete())
    {
        return Request.CreateResponse(HttpStatusCode.NoContent);
    }
    return Request.CreateResponse(HttpStatusCode.NotFound);
}

As you can see, we have easily created a Controller able to support CRUD operations. The ASP .NET Web API will manage all the aspects like content negotiation and HTTP verbs (GET, POST, PUT and DELETE).

As we have added a Service Sub Producer to our model, we can use the data contract serialization (System.Runtime.Serialization.DataContractSerializer).

Let us test our Web API Controller, we will use a simple Console Application.

For example to retrieve all our Car Groups:

string uri = "http://localhost:21020/api/cargroup";
HttpWebRequest request = HttpWebRequest.CreateHttp(uri);
request.Accept = "text/xml";//we only accept XML
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
    Console.WriteLine(response.StatusCode);
    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    {
        string result = reader.ReadToEnd();
        Console.WriteLine(result);
    }
}

And what we get (do not forget to add some instances to your model or you will not have any data):

Web API call test

Web API call test

If you want to get a specific CarGroup (id=1 for example) we only need to modify the URL (GET method):

string uri = "http://localhost:21020/api/cargroup/1";

If we want to test our other methods we only need to set the right HTTP method (verb), the right parameters (if needed) and the body data (if needed).

For example to update a CarGroup (PUT HTTP method):

CarGroup carGroup = //retrieve a CarGroup instance
carGroup.DailyRate++;//update the instance

string uri = "http://localhost:21020/api/cargroup";
HttpWebRequest request = HttpWebRequest.CreateHttp(uri);
request.Accept = "text/xml"; //we only accept XML
request.Method = "PUT";
request.ContentType = "text/xml; charset=UTF-8";//we will send XML
string bodyData = "";

//----- serializing data --------------
DataContractSerializer serializer = new DataContractSerializer(typeof(CarGroup));
using (MemoryStream stream = new MemoryStream())
{
    serializer.WriteObject(stream, carGroup);
    stream.Seek(0, SeekOrigin.Begin);
    using (StreamReader reader = new StreamReader(stream))
    {
        bodyData = reader.ReadToEnd();
    }
}
//----- writing data in to the request --------------
request.ContentLength = bodyData.Length;
using (StreamWriter requestWritter = new StreamWriter(request.GetRequestStream()))
{
    requestWritter.Write(bodyData);
}

//----- reading the response
string result = "";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
    Console.WriteLine(response.StatusCode);
    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    {
        result = reader.ReadToEnd();
    }
}

//----- deserializing the response
CarGroup updatedObject = null;
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(result)))
{
    updatedObject = (CarGroup)serializer.ReadObject(stream);
}

This works great with XML, and if we want to use JSON we only need to specify it in our request.

request.Accept = "text/json"; //we only accept JSON
request.ContentType = "text/json; charset=UTF-8";//we will send JSON

We can even send XML and ask for JSON or send JSON and ask for XML.

We need to tell ASP .NET Web API to use the WCF JSON serializer.

In the App_Start->WebApiConfig.cs file:

JsonMediaTypeFormatter jsonFormatter = (JsonMediaTypeFormatter)config.Formatters.FirstOrDefault(f => f is JsonMediaTypeFormatter);
if (jsonFormatter != null)
{
    jsonFormatter.UseDataContractJsonSerializer = true; // use WCF serializer
}

More about serialization for ASP .NET Web API here.

Well, we have manually built an Api Controller for one entity in our model. It will be great to create automatically an Api Controller for each one of our entities.

We can achieve this by making a Template, but this will be your “homeworkSmile.

You can find some information in building templates here or here.

Regards.

Pablo Fernandez Duran