Create a RESTful web service in Sitecore with Web API

Posted 08/07/2014 by aharbert

A client I am working for, requested us to convert a web service we had already created into a REST web service.  Being fairly new to Sitecore, I thought I would go with the best out of box approach for creating a RESTful service and use Web API.  Web API uses a MVC-like controller that allows for quick REST services over JSON or XML.  When I tried to install Web API though I ran into a few issues, main issue was Sitecore likes to control all request routing.  In order to get Web API to run in Sitecore I had to make the following changes.



First thing I had to do is pull down Web API through NuGet Package manager / Manage NuGet Packages for Solutions.  Be sure to select Online on the left side, in the search on the top right enter “Microsoft asp.net web API”  You will see in the results panel, the item for Microsoft ASP.NET Web API 2.2.  Choose this and install.

NuGet

Next, we need to make sure we have control over the routing.  The version of Sitecore I’m using for this project is 7.1 which already has MVC enabled.  I read that this should allow for routing to work.  This wasn’t the case for me, so I still had to create a pipeline that allowed us control with the routing request.  This is done in two parts, need to create a class in SCExtension and add this to the web config.  With the pipeline code, I want to be able to add as many methods without having to add items in IgnoreUrlPrefexs setting in the config so I created this simple pipeline to tell Sitecore to abort the restriction of the routing request.



using Sitecore.Pipelines.HttpRequest;



using System;



using System.Collections.Generic;



using System.Linq;



using System.Text;



using System.Threading.Tasks;



using System.Web;



using System.Web.Routing;



namespace NAMESPACE.SCExtension.Pipelines.Request {



     class RequestRoute : HttpRequestProcessor {



        public override void Process(HttpRequestArgs args) {

            RouteData routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(args.Context));

           if (routeData != null) {

                HttpContext.Current.RemapHandler(routeData.RouteHandler.GetHttpHandler(HttpContext.Current.Request.RequestContext));

                args.AbortPipeline();

            }

        }

    }

}

As most of you know to plug the pipeline into the site, we have to add a handler in the web config.  Inside the <httpRequestBegin> node, we added the following node






The next part is to add the following code to the Global asax file. 



protected void Application_Start(object sender, EventArgs e) { 

            GlobalConfiguration.Configure(ConfigureRoutes); 

        }

        public static void ConfigureRoutes(HttpConfiguration config) {

            GlobalConfiguration.Configuration.MapHttpAttributeRoutes();

            GlobalConfiguration.Configuration.Formatters.Clear();

            GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());

        }

The last line in the Global asax file is something I used to force results to convert XML into JSON.  Web API checks the HTTP Accept headers of a request to determine what type of output should return by looking for content typed that it has formatters registered for.  If we didn’t add the JsonMediaTypeFormatter depending on the source this service could still return XML.  This service should only return JSON data, so clearing the formatters will assure XmlMediaTypeFormatter will not be used.  One thing is the first configuration added MapHttpAttributesRoutes, we needed to add this in the application start to allow the control of the Request routes as well.

This completes the setup, now you can create your Router / Controller to generate your Web API RESTful services.  This is arbitrary but I created a directory in Website folder called APIControllers.  This is where all my controllers will reside.  When creating these items you’ll want to follow this setup.  Your class with have your routing prefix and your methods will have your parameter routing.  Say you want to create a request from site http://www.testsite.com that returns a list of English language products.  You may want the call to look like this, http://www.testsite.com/api/Product/en.  You also want to make a query to return a specific product as well, http://www.testsite.com/api/Product/en/02100.  This is very easy to setup now.  Instead of creating a list of these in the config file, as stated earlier, you now can let your class create all of the calls. 



[RoutePrefix("api/Product")]

    public class IndustrialProductController : ApiController  {



        [Route("{lang}")]

        public Object Get(string lang) {

            ProductWSExport pwe = new ProductWSExport(IndustryType.Industrial);

            var jsonStr = JsonConvert.SerializeXmlNode(pwe.GetList(lang, "IndustrialProduct",  false));

            var response = this.Request.CreateResponse(HttpStatusCode.OK);

            response.Content = new StringContent(jsonStr, Encoding.UTF8, "application/json");



            return response;

        }

        [Route("{lang}/{style}")]

        public HttpResponseMessage Get(string lang, string style) {



            ProductWSExport pwe = new ProductWSExport(IndustryType.Industrial);

            var jsonStr = JsonConvert.SerializeXmlNode(pwe.GetDetail("IndustrialProduct", style, lang, false));

            var response = this.Request.CreateResponse(HttpStatusCode.OK);

            response.Content = new StringContent(jsonStr, Encoding.UTF8, "application/json");

            return response;

        }

    }

Your class has the routing prefix set for “api/Product” you can create any prefix here you like and as many as you like.  Next, all methods will have your return type for Get.  You can see the Get methods have the routing attribute saying what parameters can be used.  First Get method is for our list and the second is our detail method.  Also note, since we are converting an existing web service that was generating XML, we had to do some formatting of the results to assure it was properly formed JSON.  If we just made the call and used Newtonsoft.Json to format this, the results would be in JSON, but in a string format.  This response content was added to make sure this wasn’t a string.  If you are generating a new service that doesn’t require XML, this setup is much simpler. 



    [RoutePrefix("api/Product")]

    public class IndustrialProductController : ApiController {



        [Route("{lang}")]

        public IEnumerable<Product> Get(string lang) {

            ProductWSExport pwe = new ProductWSExport(IndustryType.Industrial);

            return pwe.GetList(lang);

        }

        [Route("{lang}/{style}")]

        public Product Get(string lang, string style) {

            ProductWSExport pwe = new ProductWSExport(IndustryType.Industrial);

            return pwe.GetDetail(lang, style);

        }

    }

Last part, in your Web.config file, be sure you have two dependentAssembly nodes added to your assemblyBinding node.  You'll need to add them for both MVC and Razor.  Just to note, I did not add the razor node and my site appeared to work fine, but later it was discovered that in sitecore content editor, when you clicked on "InsertLink" or "Browse" you would get an error.  So to avoid this issue, be sure to add the following lines in your Web.config file.





Config



Web API (http://www.asp.net/web-api) is Microsoft’s preferred method of creating REST services (Web API is replacing WCF for RESTful web services). 



Share:

Archive

Syndication