Implement dynamic service route for WCF, just like what you do in MVC

Implementing an MVC-style route for WCF

Let’s call this thing DynamicServiceRoute. The goal of it will be to achieve a working ServiceRoutewhich supports route data and which allows you to create service routes of the format “MyService/{mycustomdata}”, like you would do in ASP.NET MVC.

First of all, let’s inherit from RouteBase and IRouteHandler. No, not from ServiceRoute! The latter is so closed that it’s basically a no-go if you want to extend it. Instead, we’ll wrap it! Here’s the base code for our DynamicServiceRoute:

    public class DynamicServiceRoute
        : RouteBase, IRouteHandler
    {
        private string virtualPath = null;
        private ServiceRoute innerServiceRoute = null;
        private Route innerRoute = null;

        public static RouteData GetCurrentRouteData()
        {
            if (HttpContext.Current != null)
            {
                var wrapper = new HttpContextWrapper(HttpContext.Current);
                return wrapper.Request.RequestContext.RouteData;
            }
            return null;
        }

        public DynamicServiceRoute(string pathPrefix, object defaults, ServiceHostFactoryBase serviceHostFactory, Type serviceType)
        {
            if (pathPrefix.IndexOf("{*") >= 0)
            {
                throw new ArgumentException("Path prefix can not include catch-all route parameters.", "pathPrefix");
            }
            if (!pathPrefix.EndsWith("/"))
            {
                pathPrefix += "/";
            }
            pathPrefix += "{*servicePath}";

            virtualPath = serviceType.FullName + "-" + Guid.NewGuid().ToString() + "/";
            innerServiceRoute = new ServiceRoute(virtualPath, serviceHostFactory, serviceType);
            innerRoute = new Route(pathPrefix, new RouteValueDictionary(defaults), this);
        }

        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            return innerRoute.GetRouteData(httpContext);
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            return null;
        }

        public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            requestContext.HttpContext.RewritePath("~/" + virtualPath + requestContext.RouteData.Values["servicePath"], true);
            return innerServiceRoute.RouteHandler.GetHttpHandler(requestContext);
        }
    }

GetRouteData is used by the routing engine to check if a route matches. We just pass that call to the inner route which is able to handle this. GetVirtualPath will not be important here, so simply return null there. If you really really feel this is needed, it would require some logic that creates a URL from a set of route data. But since you’ll probably never have to do that, null is good here. The most important thing here is GetHttpHandler. It is called by the routing engine to get a HTTP handler for a specific request context if the route matches. In this method, I simply rewrite the requested URL to the internal, ugly “MyServiceNamespace.MyServiceType-guid” URL and ask the inner ServiceRoute to have fun with it and serve the request. There, the magic just happened.

Register it in your Global.asax file

            var factory = new DataServiceHostFactory();
            RouteTable.Routes.Add(new DynamicServiceRoute("nuget/{customername}", null, factory, typeof(Packages)));

Reference:  http://blog.maartenballiauw.be/post/2011/05/09/Using-dynamic-WCF-service-routes.aspx

Leave a comment