Kentico 12: Design Patterns Part 7 - Integrating Web API 2
Tags: aspnet, kentico, webapi, mvc
Published: 2019-07-01 13:24:13

---
title: Kentico 12: Design Patterns Part 7 - Integrating Web API 2
published: true
description: Learn some best practices and design patterns when integrating Web API 2 into your Kentico 12 MVC projects.
tags: aspnet, kentico, webapi, mvc
series: Kentico 12 - Design Patterns
---

![](https://thepracticaldev.s3.amazonaws.com/i/dcl0raddowtu0vncahpz.jpg)
<figcaption>Photo by <a href="https://unsplash.com/@alain_pham">Alain Pham</a> on <a href="https://unsplash.com">Unsplash</a></figcaption>

I recently read a [great post](https://www.bizstream.com/blog/may-2019/how-to-set-up-web-api-in-a-kentico-12-mvc-project) from [Mike Webb](https://www.bizstream.com/about/team/mike-webb) over at [BizStream](https://www.bizstream.com/) about how to quickly integrate API features into our Kentico 12 MVC applications. 👍

If you haven't worked with Web API 2, ASP.NET's API framework, I definitely recommend going and giving that post a read to get started. 👌🚀

What I'd like to do here is introduce some best practices and conventions I've discovered while working with Web API 2 in Kentico over the past several years ([WiredViews](https://www.wiredviews.com/) has been integrating Web API 2 into Kentico since Kentico 8!).

---

## Routing 🗺

### Attribute Routing

ASP.NET MVC allows developers to customize routing through the `RouteCollection.MapRoute()` method using a convention-over-configuration approach.

Web API 2 offers a similar approach, using [Convention Based Routing](https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api), with `HttpConfiguration.Routes.MapHttpRoute()`, but I'd recommend using [Attribute Routing](https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2).

Attribute Routing allows for more easily customized and hierarchical / resource-oriented URL structures.

Since APIs are usually discovered by URL patterns and not by following links, being able to identify what URL pattern matches each method of an `ApiController` is very helpful.

### Route Providers

If you want to centralize some route configuration, there are hook points within the framework that help with this.

A custom `DefaultDirectRouteProvider` class can be used to [insert a consistent route prefix](https://www.strathweb.com/2015/10/global-route-prefixes-with-attribute-routing-in-asp-net-web-api/) in one location.

An implementation might look like this:

```csharp
protected override string GetRoutePrefix(HttpControllerDescriptor controllerDescriptor)
{
    string controllerPrefix = base.GetRoutePrefix(controllerDescriptor);

    return controllerPrefix is null
        ? "api"
        : string.Format("{0}/{1}", "api", controllerPrefix);
}
```

This can be a nice alternative to adding `[RoutePrefix("api/...")]` on all of your `ApiController`s. 😁

I also recommend you prefix your API routes, to keep them separate from your MVC routes, since you'll be hosting both frameworks in the same application.

---

## API Documentation

### Swagger

While we're looking at URLs and discoverabilty, there's an important tool we can easily add to our application to expose those API endpoints (and even test them out!)

If you haven't heard of [Swagger](https://swagger.io/), it's a set of tools for displaying interactive dashboards backed by custom built APIs. Using Swagger in a project can be very helpful when the developers consuming an API (ex: front-end) are not the developers building the API (ex: back-end).

Users can view the entire API of an application and test it out by filling in some fields and clicking "Try it out".

> If you are still not sure what I'm talking about, check out this [live demo](https://petstore.swagger.io/)

### Swagger-Net

Swagger, however, is not specific to a language or framework, so we need a way to integrate it into our ASP.NET application.

This is where [Swagger-Net](https://github.com/heldersepu/Swagger-Net) comes in. Swagger-Net is a wrapper around Swagger that consumes XML comments on our `ApiController` classes and then auto-generates the correct Swagger UI for our API.

> There is another project called [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle) which I used for years and provides similar functionality, but the maintainer's focus has shifted to ASP.NET Core.

> I now recommend using Swagger-Net for your ASP.NET based Kentico 12 MVC applications.

Here are example `User` and `ApiController` classes with some XML doc comments:

```csharp
namespace Kentico12MVC
{
    /// <summary>
    /// A User in the application
    /// </summary>
    public class User
    {
        /// <summary>
        /// The User's id
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// The User's full name
        /// </summary>
        public string Name { get; set; }
    }

    /// <summary>
    /// Provides access to Kentico users
    /// </summary>
    [RoutePrefix("user")]
    public class UserApiController : ApiController
    {
        /// <summary>
        /// Returns all users
        /// </summary>
        [Route("")]
        [ResponseType(typeof(IEnumerable<User>))]
        public IHttpActionResult GetUsers()
        {
            var users = UserInfoProvider
                .GetUsers()
                .AsEnumerable()
                .Select(u => new User { Id = u.UserID, Name = u.UserName });

            return Ok(users);
        }

        /// <summary>
        /// Returns the user with the Id specified in the route parameter
        /// </summary>
        /// <param name="id"></param>
        [Route("{id:int}")]
        [ResponseType(typeof(User))]
        public IHttpActionResult GetUser(int id)
        {
            var user = UserInfoProvider.GetUserInfo(id);

            return Ok(new User { Id = user.UserID, Name = user.UserName });
        }
    }
}
```

The above will produce the following Swagger UI in your site:

![](https://thepracticaldev.s3.amazonaws.com/i/zfori7krbnynsj7x9rr6.png)

Pretty cool! 😎😎😎

> I created a [GitHub Gist](https://gist.github.com/seangwright/7699f89e3ce7a637bdd8e7e912a30e04) which details some of the custom configuration I've done to integrate Swagger-Net into Web API 2.

---

## Error Handling

### IExceptionHandler

When exceptions happen in ASP.NET MVC we have several ways to prevent those from bubbling up to the framework and crashing the application.

> No one wants their users to see the [ugly yellow screen of death](https://stackoverflow.com/questions/5443334/asp-net-hacking-the-yellow-screen-of-death). 😨

To handle errors globally, in ASP.NET, we typically add an event handler in our `Global.asax.cs` file as follows:

```csharp
public void Application_Error(object sender, EventArgs e)
{
    ApplicationErrorLogger.LogLastApplicationError();
}
```

In Web API 2, the best approach is to create and register a custom `IExceptionHandler`.

This type has one public method, `HandleAsync`, which is called whenever an unhandled exception is generated in the request/response pipeline.

You can use this method to assign different `IHttpActionResult` instances to the `ExceptionHandlerContext.Result` property. This result will then be sent back to the requester.

### Custom Exception Types

I always create custom exception types in my applications that represent un-recoverable errors (ex: `NotAuthenticatedException`, `NotFoundException`, `BadRequestException`).

Using some reflection we can determine if the exception caught by the `IExceptionHandler` was one of these custom types and then return the correct `HttpStatusCode` and error message:

```csharp
private (HttpStatusCode code, ApiError error) BuildError(Exception exception)
{
    var buildApiError = CaptureErrorId(Guid.NewGuid());

    switch (exception)
    {
        case HttpException httpEx:
            return ((HttpStatusCode)httpEx.GetHttpCode(), buildApiError("HTTP_EXCEPTION", "Server error"));
        case NotAuthenticatedException notAuthNEx:
            return (HttpStatusCode.Unauthorized, buildApiError("NOT_AUTHENTICATED", "This endpoint requires authentication"));
        case NotAuthorizedException notAuthZEx:
            return (HttpStatusCode.Forbidden, buildApiError("NOT_AUTHORIZED", "The request was not authorized to perform that action"));
        case BadRequestException badRequestEx:
            return (HttpStatusCode.BadRequest, buildApiError("BAD_REQUEST", "The request was malformed"));
        case NotFoundException notFoundEx:
            return (HttpStatusCode.NotFound, buildApiError("NOT_FOUND", "The requested data could not be found"));
        default:
            return (HttpStatusCode.InternalServerError, buildApiError("APPLICATION_EXCEPTION", "Server error"));
    }
}
```

This is also a great place to centralize logging, using Kentico's `EventLogProvider.LogException()` method or something like [Serilog](https://serilog.net/). 👍

> I have an example of the code I use for custom error handling in this [GitHub Gist](https://gist.github.com/seangwright/139868f800503c118be9675cc8aa02c3)

---

## Serialization

### Centrally Stored Serialization Configuration

When compared to MVC features in your application, API features tend to rely more on serialization. This is primarily due to the fact that all data going into and out of your API will likely be in a JSON format.

If you start making custom `IHttpActionResult` types you will need to create API responses using a `JsonMediaTypeFormatter` if you want your custom result to be more easily testable.

The easiest way to centralize `JsonMediaTypeFormatter` configuration is to add it to your IoC container and then inject it as a dependency where you need it.

> See the above Gist for custom error handling to see an example of this.

This means when I configure the formatting for my API, I resolve it from my container:

```csharp
// In my Web Api configuration class

var config = new HttpConfiguration();

// ...

config.Formatters.Add(container.Resolve<JsonMediaTypeFormatter>());
```

### Serialization and Database Date Precision

In addition to centrally configuring your serialization in your DI container, you'll want to double check that your serialization settings are configured to match the requirements for your database.

Mine usually look something like this:

```csharp
builder.Register(c => new JsonSerializerSettings
{
    Formatting = Formatting.None,

    // UTC Date serialization configuration
    DateFormatHandling = DateFormatHandling.IsoDateFormat,
    DateParseHandling = DateParseHandling.DateTimeOffset,
    DateTimeZoneHandling = DateTimeZoneHandling.Utc,

    // Use X digits of precision (fffffff) to match data store datetimeoffset(X)
    DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffK",

    ContractResolver = new CamelCasePropertyNamesContractResolver()
})
```

If you are using a specific `datetimeoffset` data type in your Page Type or Custom Module Class fields, you'll want to ensure your JSON serialization matches that precision, otherwise you could lose data during serialization/de-serialization. 😯

> This issue often comes into play if you are using a "last modified date" for [Optimistic Concurrency Control](https://en.wikipedia.org/wiki/Optimistic_concurrency_control) - you need that de-serialized date from the client to match what's in the database exactly.

You might also want to occasionally serialize/de-serialize JSON in your MVC code.

If that is a requirement and you want your `JsonSerializerSettings` to match what you have configured in your API pipeline, then use a custom `ValueProviderFactory` that handles `application/json` requests.

> An example of how to do this can be found in this [GitHub Gist](https://gist.github.com/seangwright/64b6fdbb0f7578517dbae8634733aae9)

---

## Define your API Contracts

### Request and Response Types

When writing `ApiControllers` to expose data from Kentico, our first inclination might be to diretly return the `*Info` and custom PageType objects we query from `*Provider` classes.

There are two problems I see with this approach.

1. ❌ It exposes system internals (much of which is related to data persistence in Kentico) to the outside world. This can lead to tight coupling and leaky abstractions.
1. ❌ The Kentico types coming from the database have _a lot_ of fields and values, most of which are not relevant to the consumers of an API. This leads to overly heavy payloads and confusing API responses.

In the same way that Kentico recommends creating View Model classes to transport data to our views, we should also use custom model types at the API presentation layer (our `ApiController` classes).

I follow the convention of naming these types `*Request` and `*Response` classes. It makes it easier to talk about them, identify their purpose, and avoid the two issues above.

### Request Validation ☑

There is a great library to help validate that the request class instances are valid.

I recommending using [FluentValidation](https://fluentvalidation.net/) to make flexible, readable, and testable validation requirements.

Here is an example request class and its associated validator class:

```csharp
public class CustomerCreateRequest
{
  public int Id { get; set; }
  public string FirstName { get; set; }
}

public class CustomerRequestValidator :
    AbstractValidator<CustomerCreateRequest> {

  public CustomerRequestValidator() {
    RuleFor(c => c.Id).GreaterThan(0);
    RuleFor(c => c.FirstName).NotEmpty();
  }

}
```

I prefer this type of validation to the attribute validation, mostly because this is much more powerful.

I also recommend making your endpoints granular in functionality. The more an endpoint does, the larger the opportunity for something to go wrong which means handling rolling back transactions to ensure consistency.

The less that needs to be validated per-request, the less that can be invalid.

If each endpoint is considered a transaction by a consumer (a reasonable expectation!) and that "request transaction" maps to at most one or two database / system transactions, your system state will be easier to manage and harder to put into an invalid or incomplete state. 😄

---

## Cross-Cutting concerns via Aspect Oriented Programming (AOP)

### Logging

In addition to adding logging to your custom `IExceptionHandler`, you will possibly want to add logging to other parts of your application - places where requests are being handled successfully.

My recommendation is, since you're going to be using an IoC container anyway, to apply logging through AOP - more specifically with [decoration](https://autofaccn.readthedocs.io/en/latest/advanced/adapters-decorators.html#decorators).

> Note: all these patterns apply just as well to your MVC code.

Assume you have a `IUserService` that returns users as follows:

```csharp
public interface IUserService
{
    UserInfo GetUser(int userId);
}
```

Let's also assume you have an implementation that looks as follows:

```csharp
public class KenticoUserService : IUserService
{
    public UserInfo GetUser(int userId) =>
        UserInfoProvider.GetUserInfo(userId);
}
```

Now, if you want to log each time a user is successfully found and also if a user isn't found, where would you put these log statements? 🤔

I would argue you would put them nowhere in the code we see above. 😦

Instead we should decorate the `IUserService` with another implementation that only does one thing - logging. It then delegates the process of retrieving the user to the `KenticoUserService`. 🧐

Here is an example implementation:

```csharp
public class LogUserServiceDecorator : IUserService
{
    private readonly IUserService original;

    public LogUserServiceDecorator(IUserService original)
    {
        Guard.Against.Null(original, nameof(original));

        this.original = original;
    }

    public UserInfo GetUser(int userId)
    {
        var user = original.GetUser(userId);

        if (user is null)
        {
            Log.Debug("User with {userId} not found", userId);
        }
        else
        {
            Log.Debug("User with {userId} found!", userId);
        }

        return user;
    }
}
```

The `original` class field above is the "decorated" type. The `LogUserServiceDecorator` type fulfills the `IUserService` contract and will be the type actually provided in our application whenever we ask for an `IUserService` to be injected in a constructor. 

`LogUserServiceDecorator` holds within it the "original" `KenticoUserService` (as `IUserService`), which is called the `userId` parameter to do the actual work of getting the user.

Our decorating service then logs information about result returned by the `original` service.

Finally, the decorating service returns the `user`, fulfilling the `IUserService` contract while the rest of the application, and the "original" implementation, are none-the-wiser. 🤯

Each class serves one purpose and cross-cutting concerns (like logging) don't increase the length or complexity of our business logic. 🙌

> FYI, I'm using `original` above as a demonstrative name - there's no convention when doing AOP to name this way.

### Caching 💸

You're probably using output caching for your MVC application, especially given how data heavy a complex Kentico site can be.

You should probably also use caching in your API layer.

Kentico provides the `CacheHelper.Cache()` method that calls the delegate you pass to it and caches the result of that delegate before returning the value to the caller.

All you need to do is set the cache keys that your cached item depends on (what data changes should invalidate the cache), and how long you want your data cached.

Here's a nice little helper class to make caching easier:

```csharp
public static class CacheSettingsExtensions
{
    /// <summary>
    /// Assigns an array of cache dependency keys to the given CacheSettings
    /// and a function which returns a result to be cached
    /// </summary>
    public static T SetCacheDependency<T>(
        this CacheSettings cs, 
        string[] cacheDependencyKeys, 
        Func<T> getResult)
    {
        cs.CacheDependency = cs.Cached
            ? CacheHelper.GetCacheDependency(cacheDependencyKeys)
            : cs.CacheDependency;

        return getResult();
    }
}
```

You would use the above class as follows:

```csharp
var cacheDependency = new string[] { "cms.user|all" };

IEnumerable<UserInfo> users = CacheHelper
    .Cache(cs => cs.SetCacheDependency(
            cacheDependency,
            () => UserInfoProvider.GetUsers().AsEnumerable()),
        new CacheSettings(120, "api.user.all");

return users;   
```

I bet you already know how I'd recommend integrating caching into your API layer! That's right - AOP! 😜

To mimic the previous `LogUserServiceDecorator` example, we could create a `CacheUsersServiceDecorator` and replace `UserInfoProvider.GetUsers().AsEnumerable()` with the call to your "original" service.

---

## Understand OWIN vs ASP.NET pipelines

If you are confused about why you have a `Startup.cs` class when you already have `Global.asax.cs`, what OWIN is, and why Web API 2 (if you squint real hard) looks like ASP.NET Core, then understanding how it's different from ASP.NET MVC can be helpful. 🤨

It can also be helpful to keep the following concepts in mind when designing or integrating code that works with either Web API 2 or MVC but not both.

### Startup.cs

The `Startup.cs` comes from a re-thinking of what it means for an ASP.NET app to run without IIS and the ever-growing `System.Web` library.

It's a new type of ASP.NET entry-point that defines a series of "middleware".

Middleware are pieces of code linked as a pipeline that can operate on the HTTP request, in the order they are defined, and a generated response, in the reverse order.

### OWIN and Katana

So what are OWIN and Katana and how do they tie into Web API 2?

Here's some definitions

- Web API 2: Microsoft's solution for an MVC-like pattern that returns XML/JSON natively, instead of server rendered HTML views, which works on the Project Katana infrastructure.

- Project Katana: Microsoft's implementation of the OWIN contract (a dictionary) stating where HTTP request and response data is stored as it travels through a processing pipeline (a bunch of delegates/middleware).

- OWIN: Open Web Interface for .NET was an attempt to define a way to separate .NET web services and the servers they run on. OWIN applications should be able to run outside of IIS, `System.Web`, and potentially on an operating system other than Windows. (Sounds a lot like ASP.NET Core!!)

> You can get a ton of great [historical information about OWIN and Katana](https://docs.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/an-overview-of-project-katana) in Microsoft's docs. I read this stuff for fun in the evening with a glass of cold beer.

Here's [a video presentation from Brock Allen](https://youtu.be/DRPVO3-W4Rs) (of Identity Server fame), detailing what makes OWIN different from the classic ASP.NET architecture, way back in early 2014.

## Knowledge

Let's review the many points we've covered:

- Routing
 - Use Attribute Routing to best align with how an API wants to be designed.
 - Centralize route configuration using the hooks the framework provides.
- API Documentation
 - Swagger is a great UI for documenting and exploring APIs.
 - Swagger-Net provides an easy way to integrate Swagger in our ASP.NET apps.
- Error Handling
 - Create your own custom error handler to catch and log unhandled exceptions.
 - Use custom exception types to return helpful HTTP status codes to clients.
- Serialization
 - Put your serialization configuration in an IoC container for serialization consistency.
 - Make sure your date serialization matches your database types.
- Define Your API Contracts
 - Use Request and Reponse models at the edge of your API to abstract away Kentico implementation details.
 - FluentValidation is a great way to declaratively validate your request models.
- Use Aspect Oriented Programming (AOP)
 - Logging is a cross-cutting concern and should be applied through decoration, not inline in your business logic.
 - Kentico provides helpful cache methods which can also be used with decoration.
- OWIN and ASP.NET
 - The `Startup.cs` is a new entry / integration point for ASP.NET.
 - OWIN and Katana are precursors to ASP.NET Core and are the foundation for Web API 2.

If you've stuck with me this far then you're a pretty dedicated developer [who values knowledge](https://youtu.be/Cv1RJTHf5fk?t=6) or maybe you're just a little bored. 🤣

Either way, I hope these thoughts of mine on how to use ASP.NET Web API 2 in your Kentico 12 MVC projects was helpful.

---

If you are looking for additional Kentico content, checkout the Kentico tag here on DEV:

{% tag kentico %}

or my [Kentico 12: Design Patterns](https://dev.to/search?q=Kentico%2012%20-%20Design%20Patterns) series.