Skip to main content

Microsoft

Sitecore and Web API – Set Custom ContractResolver

In a standard Web API implementation, if you want to change the ContractResolver that is used by the Web API framework to serialize your models into JSON, it’s as easy as changing the JsonFormatter settings in the GlobalConfiguration.

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    var jsonFormatter = config.Formatters.JsonFormatter;
    jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  }
}

In this example, I’m swapping out the ContractResolver so that Web API will return JSON with camel case property names, which it doesn’t do by default.
In Sitecore, it’s a little more work than just changing the ContractResolver of the JsonFormatter in the GlobalConfiguration. First, Sitecore adds a second JsonFormatter into Web API’s set of formatters so that JSON is returned instead of XML for browser requests (side note: Sitecore makes a lot of small changes to Web API behind the scenes, which Andreas Gehrke covers nicely here). Second, Sitecore runs its own Web API services that are best not interfered with.

Override the ContractResolver Per Controller

Web API makes it really simple to override the ContractResolver at the controller level. Create a ControllerConfiguration Attribute as follows:

[AttributeUsage(AttributeTargets.Class)]
public class UseCamelCasePropertyNamesContractResolverAttribute : Attribute, IControllerConfiguration
{
  public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
  {
    var formatters = controllerSettings.Formatters;
    foreach (var jsonFormatter in formatters.OfType<JsonMediaTypeFormatter>().ToArray())
    {
      var newFormatter = (JsonMediaTypeFormatter)Activator.CreateInstance(jsonFormatter.GetType());
      newFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
      var jsonFormatterIndex = formatters.IndexOf(jsonFormatter);
      formatters[jsonFormatterIndex] = newFormatter;
    }
  }
}

This will replace all of the JsonMediaTypeFormatters in the controllerSettings.Formatters collection with a new instance that has a CamelCasePropertyNamesContractResolver. Do not modify the JsonMediaTypeFormatters in the controllerSettings.Formatters collection directly as any changes you make will affect the Global Configuration as well.
Now add the attribute to the controllers that you want to use this ContractResolver:

[UseCamelCasePropertyNamesContractResolver]
public class ContentController : ServicesApiController
{
  public IHttpActionResult Get()
  {
    return Ok(new { Content = "Hello world!" });
  }
}

Override All Controllers

You can override the ContractResolver for all controllers in your project by applying an IControllerConfig Attribute to a base ApiController class that your controllers inherit from.
Add the IControllerConfig Attribute to your base controller:

[UseCamelCasePropertyNamesContractResolver]
public class BaseServicesApiController : ServicesApiController
{
}

And inherit from your base controller:

public class ContentController : BaseServicesApiController
{
  public IHttpActionResult Get()
  {
    return Ok(new { Content = "Hello world!" });
  }
}

Voila, all controllers in your project that inherit from your base controller will use the new ContractResolver.

Override ContractResolver Globally

It’s possible to override ContractResolvers globally, and I include this method for completeness sake, but I do not advocate using it within a Sitecore install. Although I’ve observed that Sitecore’s Item Service API seems to be resilient to global ContractResolver changes (through some black magic), there’s always the possibility of modifying Sitecore’s API implementation(s) that could lead to unintended consequences elsewhere; don’t do this unless you really know what you’re doing.
To override the ContractResolver globally, create a new pipeline processor:

public class UseCamelCasePropertyNamesContractResolver
{
  public void Process(PipelineArgs args)
  {
    var config = GlobalConfiguration.Configuration;
    foreach (var jsonFormatter in config.Formatters.OfType<JsonMediaTypeFormatter>())
    {
      jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    }
  }
}

Patch the processor into the Sitecore pipeline (take care to put it after Sitecore’s ServicesWebApiInitializer, as Martin English points out on his blog):

 <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
   <pipelines>
    <initialize>
     <processor type="SitecoreDemo.UseCamelCasePropertyNamesContractResolver, SitecoreDemo"
                patch:after="processor[@type='Sitecore.Services.Infrastructure.Sitecore.Pipelines.ServicesWebApiInitializer, Sitecore.Services.Infrastructure.Sitecore']" />
    </initialize>
   </pipelines>
  </sitecore>
 </configuration>

Now requests to your all of your Web API controllers (and possibly Sitecore’s Web API controllers) will use your ContractResolver when serializing response to JSON.
Let me know your thoughts in the comments.

Thoughts on “Sitecore and Web API – Set Custom ContractResolver”

  1. Hello, this is a good blog, but I still have some question.
    My WebApi controllers return custom and sometimes 3-Party defined models for example List or Movie and not IHttpActionResult . How can I change my controllers to do that?
    How does it work with async controllers. for example I have controllers that are public async Task<List>
    Thanks for your interesting post by the way!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Corey Smith, Sitecore MVP & Lead Technical Consultant

I'm a Sitecore MVP and Lead Technical Consultant at Perficient focusing on Sitecore and custom .NET development.

More from this Author

Categories
Follow Us