ASP.NET C# MVC 5

Routing and AttributeRouting Web API 2 Controllers in MVC with Areas

The Acumen ASP.NET MVC development team started working with the new Web API 2 controllers released with Visual Studio 2013, and quickly hit some important issues that took some research to resolve.

Routing and AttributeRouting and using Web API 2 controllers inside an Area in an ASP.NET MVC5 project

Currently, this IS possible. It was not possible with Web API and it seems like it was also not possible in beta, but this can be done with Web API 2 and MVC 5. I used the following configurations:

 // File: ~/Areas/API/APIAreaRegistration.cs
    using System.Web.Http;
    using System.Web.Mvc;

    namespace MySolution.Areas.API {
        public class APIAreaRegistration : AreaRegistration {
            public override string AreaName {
                get {
                    return "API";
                }
            }

            public override void RegisterArea(AreaRegistrationContext context) {
                context.Routes.MapMvcAttributeRoutes();
                context.Routes.MapHttpRoute(
                    name: this.AreaName,
                    routeTemplate: this.AreaName + "/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
            }
        }
    }
 // File: ~/Global.asax.cs
    using System.Linq;
    using System.Web.Http;
    using System.Web.Mvc;
    using System.Web.Routing;
    using Newtonsoft.Json.Serialization;
    using WebMatrix.WebData;
    using AcumenSystem5.Models;
    using System.Threading;
    using System.Web.Optimization;

    namespace MySolution {
        public class MvcApplication : System.Web.HttpApplication {
            protected void Application_Start() {
                AreaRegistration.RegisterAllAreas();
                GlobalConfiguration.Configure(config => { // This HAS to be here. Having it last caused routing to not work.
                    config.MapHttpAttributeRoutes(); // This allows us to use AttributeRouting

                    // This sets JSON as the default return format and removes any circular references
                    var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
                    config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
                    var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
                    json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 
                });
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
                LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
            }
        }
    }

AttributeRouting and WebAPI Routing not working correctly and returning 404 Errors

After struggling with areas, I hit this issue when adding the Web API 2 controller to the root controllers folder. I discovered that the ordering of configuration mattered. So, like as shown in the Global.asax.cs above, the order needs to be as follows to work correctly:
protected void Application_Start() {

     // Full file code in example above
        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(config => { // This HAS to be here. Having it last caused routing to not work.
            config.MapHttpAttributeRoutes(); // This allows us to use AttributeRouting

            config.Routes.MapHttpRoute( // This allows us to use conventional HTTP routing
                    name: "Name",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                ); ;

            // This sets JSON as the default return format and removes any circular references
            var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
            config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
            var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
            json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 
        });
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
    }

Hope this helps!

Leave a Reply

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