mdsol/crichton-dotnet — pull request #15 by edandersen (2014-05-30 08:39:21+00:00)
Title: [NRTM] [Spike] Preliminary Crichton.WebApi module for .NET server support

As part of Innovation Time, I've spent some time cracking on with the ASP.NET Web API support in Crichton.NET. WebApi projects can now pretty easily add Hypermedia support with the new Crichton.WebApi module. This PR is a work in progress as I am seeking feedback. There is no test coverage as this is still some investigatory code. It contains:

* A new WebApiSample sample project in the /samples folder
* Crichton.WebApi project designed to be added to ASP.NET WebApi projects via NuGet
* Extension methods such as AddSelfLinkToCurrentUrl() and AddTransitionToRoute() which only apply within Web projects

@mdsol/hypermedia-team @fosdev @brutski @cabbott @BPONTES @chad-medi @sheavalentine-mdsol @jcarres-mdsol Feedback much appreciated. I will be tidying this up over the next week or so.

### Setting up WebApi support
* Add the Crichton.WebApi nuget package (this will bring in Crichton.Representors as a dependency) - no nuget package yet
* Add the following to your WebApiConfig.cs class:

```csharp
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// ...

// Allow Crichton to Serialize IRepresentorBuilder responses
config.Formatters.Add(new CrichtonMediaTypeFormatter());
}
}
```

### Method 1: Returning IRepresentorBuilders from WebApi Controllers
If you then create controller actions like the following:

```csharp
// GET api/test/5
public IRepresentorBuilder Get(int id)
{
var data = Data.Single(d => d.Id == id);

var builder = new RepresentorBuilder();
builder.SetAttributesFromObject(data);
builder.SetSelfLinkToCurrentUrl(RequestContext);

return builder;
}
```

By returning an IRepresentorBuilder, Crichton.WebApi will automatically respond with a Hypermedia response based on the ```Accept``` request header. For example, the above outputs:

![crichton1](https://cloud.githubusercontent.com/assets/548636/3128439/9461670c-e7d3-11e3-89e1-b4e79771e80f.PNG)

### Method 2: Using BuilderDescriptors
The constructor of ```CrichtonMediaTypeFormatter()``` accepts a list of IBuilderDescriptors (subject to name change). By using BuilderDescriptors, you don't need to pollute your Controller Actions with builder code. For example, the above controller could be:

```csharp
// GET api/friends/5
public FriendModel Get(int id)
{
return Data.Single(d => d.Id == id);
}
```

...with the following IRepresentorBuilder:

```csharp
public class FriendModelBuilderDescriptor : IBuilderDescriptor
{
public IRepresentorBuilder BuildForType(Type type, object value, HttpRequestContext context)
{
var builder = new RepresentorBuilder();
var model = (FriendModel)value;

builder.SetAttributesFromObject(model);
builder.SetSelfLinkToCurrentUrl(context);

return builder;
}

public bool SupportsType(Type type)
{
return type == typeof (FriendModel);
}
}
```
In the above case, Crichton.WebApi will then use an instance of this IRepresentorBuilder whenever it encounters an output of ```FriendModel``` in order to create the Representor via the RepresentorBuilder.

You can even create Descriptors for IEnumerables:

```csharp
public class FriendModelEnumerableBuilderDescriptor : IBuilderDescriptor
{
public IRepresentorBuilder BuildForType(Type type, object value, HttpRequestContext context)
{
var builder = new RepresentorBuilder();

var models = (IEnumerable)value;

builder.SetCollection(models, d => context.Url.Route("DefaultApi", new { controller = "friends", id = d.Id }));
builder.SetSelfLinkToCurrentUrl(context);

return builder;
}

public bool SupportsType(Type type)
{
return type == typeof (IEnumerable);
}
}
```
...which outputs like the following:

![crichton2](https://cloud.githubusercontent.com/assets/548636/3128522/3eeb6f0a-e7d5-11e3-9613-a562599c58f1.PNG)

To add Descriptor support, include them when adding the CrichtonMediaTypeFormatter in WebApiConfig.cs:

```csharp
// Allow Crichton to Serialize IRepresentorBuilder responses and all Descriptors
config.Formatters.Add(new CrichtonMediaTypeFormatter(new FriendModelBuilderDescriptor(), new FriendModelEnumerableBuilderDescriptor()));
```

I will update this PR over the next week as I tweak this.