TOP

Configurable Service Routes

configurationOne of the things I don’t like about the default way of working with (URL) routes in ASP.NET MVC, is code in the Global.asax. While this is fine for simple MVC-routing, you don’t want to hard-code all your WCF endpoints inside that class, instead you want to configure using the web.config.

The first part of this code example is based upon code from one of my colleagues (thanks Roy Tore), it’s basically a custom configuration element for your web.config, which allows you to define a list of services and the route it should be registered on.

Second element of this sample, is how the types are defined in the serviceType proprety in the web.config, which does not require a specific type, but support the use of interfaces. There is additional code in the example, which extends the WebServiceHostFactory with support for dependency injection using Autofac.

Walkthrough

Here is a walkthrough on how you can do this from scratch.

  1. Create a new ASP.NET MVC 3 Web Application.
  2. Install the Autofac.MVC3 NuGet package.
  3. Add a reference to System.ServiceModel.dll, System.ServiceModel.Activation and System.ServiceModel.Web.dll
  4. Download the Routing.zip and unpack this into your web project.
  5. Modify the global.asax.cs, inside the Application_Start handler, add the following code in the beginning of the method:
    DependencyResolver.SetResolver(new AutofacDependencyResolver(CreateContainer()));

    And on the bottom of the method, after the ASP.NET MVC routes (RegisterRoutes):

    RouteTableManager.MapRoutes(DependencyResolver.Current.GetService<DynamicWebServiceHostFactory>());

  6. Modify the same file, but this time inside the RegisterRoutes method. We need to make sure the regular ASP.NET MVC routing will ignore our special services URI. See the full example below, and here is the modified default route:

    routes.MapRoute(
        "", 
        "{controller}/{action}/{id}",
       new { controller = "Home", action = "Index", id = UrlParameter.Optional },
       new { controller = "^(?!services).*" } // Important for WCF services to work.
        );
     
  7. Create a new method called CreateContainer inside global.asax.cs, which creates your inversion of control container. Preferbly this should be placed somewhere else in a separate class. The first 3 registrations is to enable Autofac-support for your regular ASP.NET MVC controllers. After the changes, your global.asax.cs should look similar to this:
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
     
        routes.MapRoute(
            "", // Route name
            "{controller}/{action}/{id}",
         new { controller = "Home", action = "Index", id = UrlParameter.Optional },
         new { controller = "^(?!services).*" }
            );
    }



    protected void Application_Start() { // Set the MVC IOC resolver to our Autofac resolver. DependencyResolver.SetResolver(
    new AutofacDependencyResolver(CreateContainer())); AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); // Map all the routes configured in web.config. RouteTableManager.MapRoutes(
    DependencyResolver.Current.GetService<DynamicWebServiceHostFactory>()); } private IContainer CreateContainer() { var builder = new ContainerBuilder(); builder.RegisterControllers(typeof(MvcApplication).Assembly); builder.RegisterModule(new AutofacWebTypesModule()); builder.RegisterModelBinderProvider(); builder.RegisterType<DynamicWebServiceHostFactory>(); // Register all the WCF (REST) services. builder.RegisterType<ItemService>().As<IItemService>(); var container = builder.Build(); return container; }

  8. Create your WCF (REST) Services (and modify the CreateContainer).
  9. Modify your web.config with the example below and you are done!

Add the following to your web.config, right after the configuration elemenet:

  <configSections>
    <section name="routingExtention" type="
ConfigurableServiceRoutes.Routing.RouteTableSection, ConfigurableServiceRoutes, 
Version=1.0.0.0, Culture=neutral" />
  </configSections>

  <routingExtention>
    <routes>
      <add route="services/items" serviceType="
ConfigurableServiceRoutes.Services.IItemService, ConfigurableServiceRoutes, 
Version=1.0.0.0, Culture=neutral" />
    </routes>
  </routingExtention>

If you need more services, just keep adding into the routes collection with more add elements.

Next part of the config change, is to enable the ASP.NET Compatability. This is important for the sample to work.

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  </system.serviceModel>

That’s it!

Benefits

There are multiple benefits from this sample.

  • Service Routing are configured, not compiled in code.
  • Services does no longer require an empty constructor.
  • Services supports dependency injection.
  • WCF Services works fine together with ASP.NET MVC.

And that’s basically it, I hope you enjoy this for your own projects.

Source Code

You can download a fully working sample here: ConfigurableServiceRoutes.zip

When you run the sample, you will get a 404 on the root as it’s based on an empty ASP.NET MVC 3 Web App. If you access the URL with /services/items, you should see the WCF REST Service initialize correctly.

Notes of caution

There is one place in the code, inside the DynamicWebServiceHostFactory where I override the CreateServiceHost method. The logic that replaces the base here, I don’t know what the original code was and there might be special instances where your service instance won’t work properly. It works on my machine!

1 comment. Leave a Reply

  1. Johan

    Hi,

    The source code is not available and I’m interested in seeing it to figure out how autofac +wcf(was) with rest works, or how you solved it.

    Best regards, Johan

Leave a Reply

Your email is never published nor shared.

You may use these HTML tags and attributes:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>