Sean

Integrating Kentico CMS with ASP.NET Web Api 2

Author: Sean Wright on 08/23/2016

Kentico CMS provides some great functionality out of the box and as a developer it can be extended to your heart's content. It even has a REST-like API you can program against. This API is a great solution when you need to access information stored in your CMS, possibly for some AJAX behavior in the browser or as an interface between server side systems. But it is a newer feature in the CMS and it doesn't offer a solution for every task as it seems to have been designed more for ease of access than extreme flexibility.

Fortunately there is another option! Kentico provides a mechanism for integrating both ASP.NET MVC and Web Api into its platform. Web Api provides a native .NET implementation for developing RESTful APIs which can be accessed both client side and server side via HTTP requests, but unlike the Kentico implementation you are in complete control (and completely responsible) for an Api built using this technology. We will be drawing on instructions from the above documentation in our integration but I have found that there are many gotchas and useful tools and configurations that are missing from any single reference. Continue reading if you would like to learn some great tips on how to make your Kentico and Web Api 2 integration as seamless as possible.

I will be using a WebSite style project of the Kentico CMS version 9.0.20 and integrating with Web Api 2.2.

Open up your Kentico project in Visual Studio and let's begin.

Add a new ASP.NET Web Application project to your solution.

I usually name this project the same as the namespace I'm using for the site (in this case WiredViews.WIR03) plus "Web.Api" as a suffix. So this would be something like WiredViews.WIR03.Web.Api. These namespaces are important when you start adding multiple projects that serve distinct roles in your application. When using a framework that is entirely separate from Kentico it's very possible you will develop additional layers to support it. In my experience solutions containing Web Api integrating with Kentico typically have at least 2-3 projects which means coming up with a namespace convention early will help you keep things straight later.

Select the Web Api project template.

Since we are doing a Web API integration we will not need most of the MVC functionality that comes with this project template. You can delete the following items. The App_Data folder was not included in the screenshot above but it can also be removed.

Now we need to add and remove some NuGet packages. Open up the NuGet package manager and look at the packages already installed. We only need to keep the following packages.

        Microsoft.AspNet.WebApi
        Microsoft.AspNet.WebApi.Client
        Microsoft.AspNet.WebApi.Core
        Microsoft.AspNet.WebApi.WebHost
        Microsoft.CodeDom.Providers.DotNetCompilerPlatform
        Microsoft.Net.Compilers
        Newtonsoft.Json

Now let's add the packages we will need

        Microsoft.AspNet.WebApi.Owin Microsoft.Owin.Host.SystemWeb
        Swashbuckle.Core

If you have any packages that have updates available, update those now. (If you have any issues with updating at this point, just save your project and restart Visual Studio).

Now you should have a project and a packages.config, which lists your NuGet packages, that looks something like this.

Select your Web.Api project and then open the Properties tab on the right side bar of Visual Studio. You should see an option Always Start When Debugging. Set that to false.

In the following steps you should be able to resolve all the namespaces for each of the classes that Visual Studio can't identify. Use one of my favorite Visual Studio features - select a class name which can't be identified and type ctrl+. to get the context menu of recommended namespaces and then select the one you want.

Create a root folder in the Web Api project named Configuration and add a class named BasePrefixRouteProvider to Configuration and replace the content with the following.

In the following files be sure to replace the namespaces that reference my project with the ones that would be appropriate for your project.

BasePrefixRouteProvider.cs

The Configuration folder is where we will place all classes that are used to configure the Web Api pipeline when any request is made that is associated with one of its endpoints. There will only be a couple of these but it's helpful to keep them in one place.

Add a folder named Results to the Web Api project root and add a class named ErrorResult to that folder. Replace its content with the following.

ErrorResult.cs

For now we will only have this one result class. A Result in Web Api is a helper class that can combine a message with a default response format or status code (think 200, 401, 500, ect...). Web Api provides us with several Result classes out of the box but I find it is useful to have a customizable one for errors. We will be using this class in the next step where we set up a global exception handler for the pipeline.

Add a folder named Exceptions to the Web Api project root and add a class named GlobalExceptionHandler to that folder. Replace its content with the following

GlobalExceptionHandler.cs

This exception handler will later be registered in our WebApiConfig.cs configuration file. It will be used whenever the framework or our own code throws an exception so that we can ensure the requester receives the correct response type and format. Exceptions are used liberally throughout Web Api to trigger responses like 401, 400, 404 and 500, especially when processing might be occurring down in our business logic which doesn't know anything about Web Api but does know some piece of data shouldn't be accessible to the current requester.
You can add additional exception types to your project and then add if statements to determine if the exception that has been thrown is one of those types. Then depending on which type of exception it is you can modify the response and/or log the exception appropriately.

Now move the WebApiConfig.cs file that is in the App_Start folder into the Configuration folder. Add configuration as a suffix to the existing namespace for the WebApiConfig class and update the content to the following.

WebApiConfig.cs

We want to be able to test our Api and a great solution for that is Swagger (http://swagger.io/). Swagger provides a webpage, usually generated dynamically, that describes our Api. This includes routes, HTTP verbs, parameters and responses. It also allows you to make requests to your Api directly through the webpage and displays the results after they return. It's a great tool for visualizing your Api but it's a lifesaver when you have backend developers working on the Api and frontend developers working on javascript that makes requests to and consumes responses from that Api. You can have a fully documented Api, accessible and readable for everyone even before the data access or business logic is in place.

Unfortunately swagger doesn't integrate into Web.Api projects natively (sad face), but fortunately there is an awesome open source project out there called Swashbuckle (https://github.com/domaindrivendev/Swashbuckle) which is a .NET wrapper around Swagger (happy face) and is available via NuGet (which we installed when we were configuring our NuGet packages initially).

We need to configure Swashbuckle during our app startup so that it can configure our Swagger UI. Create a class named SwashbuckleConfiguration in the Configuration folder and replace its content with the following.

SwashbuckleConfiguration.cs

You will notice the variable _generatedXMLPath which is the relative path to the file that swashbuckle will load to generate the swagger UI. This file has all the comments you add to public classes and methods in your assembly. Swagger uses this information, specifically from controller classes and action methods of your api, and uses those to decorate the swagger UI automatically. This way your testing page is always up to date with your build. You will see how this comes together at the end.

To enable the XML file generation, right click your Web Api project, go to the Build section and check the box next to Output->Output Path->XML Documentation File. The path that gets automatically populated is fine, you will just want to make sure the _generatedXMLPath in SwashbuckleConfiguration.cs matches this path. Save your properties dialog and get ready for the final Web Api configuration step.

We need an entrypoint for our application after deleting the Global.ascx.cs. Create a class named Startup in the App_Start folder and replace its content with the following.

Startup.cs

This file serves as the entrypoint for the OWIN pipeline and where we perform the configuration for everything we are tying into that pipeline. ASP.NET Web Api is itself a single piece of middleware in that pipeline.

In the upcoming ASP.NET Core 1.0 (previously ASP.NET vNext and then ASP.NET 5) the Web Api framework is completely integrated with the MVC framework which will again be a single pluggable piece in the request pipeline. Other optional pieces include static file server, integration with IIS (on the Windows platform only), authentication (like Identity Server which will be the defacto authentication middleware) and any custom middleware you build or add through a NuGet package.

Some of the configuration that is either happening or being called from this entrypoint includes setting under which base url our api lives (BaseApiRoute) in our site, attaching WebApi configuration (OWIN apps can exist without Web Api - the Web Api framework is just a middleware aka module), initializing Swashbuckle and also integrating Session State (which Kentico relies on) with Web Api (which is designed to be stateless).

The last one is key. If you want to be able to use all of your favorite global contexts like SiteContext, ECommerceContext and especially MembershipContext (without which there is no authenticating against Kentico) then we need to somehow get Web Api to see and use cookies, specifically the ASP.NET_SessionId cookie. Please note that the method RequireAspNetSession is a hack. This is not how Web Api was designed to work but it is a hack we must live with in order for a traditional IIS hosted Web Forms application to work with this newer Web Api framework.

Now for the Kentico integration with the WebApi project!

Add the following libraries from your Kentico site's Lib\ directory to your Web.Api project.

        CMS.Base
        CMS.Core
        CMS.DataEngine

Add a folder named Kentico to the root of your Web Api project and add two new classes to it.

        WebApiModule.cs
        WebApiModuleMetadata.cs

Normally in a Web Api application the OWIN entrypoint is called by another process like IIS or Katana (the moduler webserver of the OWIN world) but we are going to letting Kentico call and start it as another Module within Kentico. These files provide that connection. Replace WebApiModule.cs with the following content.

WebApiModule.cs

Replace WebApiModuleMetadata.cs with the following content.

WebApiModuleMetadata.cs

Open up your Properties/AssemblyInfo.cs in your Web Api project and add the following lines.

        // Kentico related attributes
        [assembly: AssemblyDiscoverable]
        [assembly: RegisterModule(typeof(WebApiModule))]

This is what allows your Kentico site to learn that this assembly has some fun stuff in it that you would like it to use (your awesome Api!).

Add the following block of code to your App_Code (or Old_App_Code) Global.ascx.cs for your Kentico site, where /api/ could be replace with your BaseApiRoute if you set that to something other than /api.

    /*
     * Ensures that requests to the API are not affected by Forms Authentication
     * which will turn a 401 response into a 302 to the login page as defined in
     * the web.config
    */
    protected void Application_BeginRequest()
    {
        HttpRequestBase request = new HttpRequestWrapper(Context.Request);
        if (request.Path.StartsWith("/api/"))
        {
            Context.Response.SuppressFormsAuthenticationRedirect = true;
        }
    }

The libraries we added to the Web Api project might conflict with versions already included in our Kentico site, so we need to add some binding redirects to our web.config for the Kentico site. Based on my packages.config these are the versions I want to redirect to.

These are my binding redirects for this specific combination of a fresh install of Kentico 9.0 and ASP.NET Web Api 2.2 as of 2015/04/22. If you already have other NuGet packages or libraries with dependencies referenced in your Kentico site this part could become a little more complicated.

web.config binding redirects

We're going to take a quick detour into your running Kentico site. We need to tell Kentico to ignore the paths that both Swagger and our Api are going to use - we want our Web Api application code to answer those requests. To do this go into your Kentico dashboard, go to the Settings application and select the URLs and SEO option from the left menu. Add /api;/swagger to the Excluded Urls option text box and save.

Finally (yes, just one more thing)... add a project reference to your Web Api project in your Kentico site /bin which will pull in the .dll, .pdb and .xml files for your Web Api project.

Now you should be able to run your site successfully. If you navigate to /swagger you should see the Swagger UI, which isn't very exciting because we haven't defined an API yet. :( So let's add some functionality to get some sweet payoff for all this hard work.

Right click on the Controllers folder in your Web Api project and select Add->Controller. When the next menu opens select Web Api 2 Controller with read/write actions.

This UI is one of the nice features we get for adding a Web Api ASP.NET application project and not a simple class library project. Name your controller ValueController and save it. Replace the code in ValueController.cs with the following content.

ValueController.cs

You can see I have a [RoutePrefix("value")] defined as an attribute for my controller class. Since we are using attribute routing we are not going to be using the convention based routing that is popular in ASP.NET MVC and was originally the perferred routing in Web Api projects. We have to have Route attributes on our Controllers and Action methods if we want them to be exposed through our api. This controller [RoutePrefix] attribute will make all actions in this controller accessible as variations of the url /api/value.

You can see the first Action method Get has an attribute [Route("")] which means all GET requests to the controller's route (/api/value) will result in this action method getting called.

The [ResponseType] attribute helps Swagger know what to expect as the response to requests for this endpoint.

The IHttpActionResult return type for the method lets me wrap my data in a variety of helper method result classes provided by Web Api. Here you can see the result classes which are made available by the framework.

Now rebuild your project, run the Kentico site and enter the Swagger url (/swagger) into your web browser again. This time you should see something a little more interesting. Go ahead and add more controller action methods, controllers and response types and see how the Swagger UI is updated with each change and rebuild.

Next time we will look at integrating Kentico ObjectQuery calls, Security and DTOs. After that expect a detailed post going over some more advanced topics like Dependency Injection in Web Api and how to implement it using the Simple Injector library.

comments powered by Disqus