Skip to content

Key features Superscribe comes with a host of features to help you get the most out of your routing

Simplify your Asp.Net Web API Routes

Please note that Superscribe only supports Asp.Net Web Api 2.1 and above

Routing in Web API is based on legacy MVC logic, and although Attribute Routing improves things greatly it's still not a catch-all fix. Many route combinations are very difficult to implement, such as multiple actions, with the same parameters, mapped to the same http verbs. Superscribe solves all these problems by allowing you to be more descriptive with much less code.

Here's a comparison of Web API verus Superscribe for an app that serves the following urls:


    // /sites/{siteId}/portfolio/projects
    // /sites/{siteId}/portfolio/projects/{projectId}
    // /sites/{siteId}/portfolio/projects/{projectId}/media
    // /sites/{siteId}/portfolio/projects/{projectId}/media/{id}
    // /sites/{siteId}/portfolio/tags
    // /sites/{siteId}/portfolio/categories
    // /sites/{siteId}/portfolio/categories/{id}
    // /sites/{siteId}/blog/posts/
    // /sites/{siteId}/blog/posts/{postId}
    // /sites/{siteId}/blog/posts/{postId}/media
    // /sites/{siteId}/blog/posts/{postId}/media/{id}
    // /sites/{siteId}/blog/tags
    // /sites/{siteId}/blog/posts/archives
    // /sites/{siteId}/blog/posts/archives/{year}/{month}
        

Traditional Web API:

     
    config.Routes.MapHttpRoute(
        name: "PortfolioTagsRoute",
        routeTemplate: "sites/{siteId}/portfolio/tags",
        defaults: new { controller = "portfoliotags" }
    );
     
    config.Routes.MapHttpRoute(
        name: "PortfolioProjectsRoute",
        routeTemplate: "sites/{siteId}/portfolio/projects/{id}",
        defaults: new { controller = "portfolioprojects", id = RouteParameter.Optional }
    );

    config.Routes.MapHttpRoute(
        name: "PortfolioProjectMediaRoute",
        routeTemplate: "sites/{siteId}/portfolio/projects/{projectId}/media/{id}",
        defaults: new { controller = "portfolioprojectmedia", id = RouteParameter.Optional }
    );
     
    config.Routes.MapHttpRoute(
        name: "PortfolioCategoriesRoute",
        routeTemplate: "sites/{siteId}/portfolio/categories/{id}",
        defaults: new { controller = "portfoliocategories", id = RouteParameter.Optional }
    );
     
    config.Routes.MapHttpRoute(
        name: "BlogPostMediaRoute",
        routeTemplate: "sites/{siteId}/blog/posts/{postId}/media/{id}",
        defaults: new { controller = "blogpostmedia", id = RouteParameter.Optional }
    );
     
    config.Routes.MapHttpRoute(
        name: "BlogTagsRoute",
        routeTemplate: "sites/{siteId}/blog/tags",
        defaults: new { controller = "blogtags" }
    );
     
    config.Routes.MapHttpRoute(
        name: "BlogPostArchiveRoute",
        routeTemplate: "sites/{siteId}/blog/posts/archives/{year}/{month}",
        defaults: new { controller = "blogpostarchives" }
    );
     
    config.Routes.MapHttpRoute(
        name: "BlogPostArchivesRoute",
        routeTemplate: "sites/{siteId}/blog/posts/archives",
        defaults: new { controller = "blogpostarchives" }
    );
     
    config.Routes.MapHttpRoute(
        name: "BlogPostsRoute",
        routeTemplate: "sites/{siteId}/blog/posts/{id}",
        defaults: new { controller = "blogposts", id = RouteParameter.Optional }
    );
        

Superscribe:


    var blog        = engine.Route(r => r / "sites" / (Int)"siteId" / "blog");
    var portfolio   = engine.Route(r => r / "sites" / (Int)"siteId" / "portfolio");
    var blogposts   = engine.Route(blog / "posts".Controller("blogposts"));

    engine.Route(portfolio / "tags".Controller("portfoliotags"));
    engine.Route(portfolio / "categories".Controller("portfoliocategories") / (Int)"id");
    engine.Route(portfolio / "projects".Controller("portfolioprojects") 
        / (Int)"projectId" / "media".Controller("portfolioprojectmedia") / (Int)"id");

    engine.Route(blog / "tags".Controller("blogtags"));

    engine.Route(blogposts / (Int)"postId" / "media".Controller("blogpostmedia") 
        / (Int)"id");

    engine.Route(blogposts / "archives".Controller("blogpostarchives") / (Int)"year" 
        / (Int)"month");

        

Test your route handlers in isolation

The Superscribe engine is built in a way which means it's easy to parse urls without invoking the rest of your application using the Route Walker. Provided you have implemented your handlers in a decoupled fashion, you can add route definitions, perform tests on your matching, then reset back to scratch for the next iteration with minimal fuss


    [TestClass]
    public class SuperscribeUnitTests
    {
        private IRouteEngine define;
            
        [TestInitialize]
        public void Setup()
        {
            define = RouteEngineFactory.Create();

            define.Get("Hello/World", o => "Hello World!");
            define.Get("Hello" / (String)"Name", o => "Hello " + o.Parameters.Name);
        }
        
        [TestMethod]
        public void Test_Hello_World_Get()
        {
            var routeWalker = define.Walker();
            var data = routeWalker.WalkRoute("/Hello/World", "Get", new RouteData());

            Assert.AreEqual("Hello World!", data.Response);
        }

        [TestMethod]
        public void Test_Hello_Name_Get()
        {
            var routeWalker = define.Walker();
            var data = routeWalker.WalkRoute("/Hello/Kathryn", "Get", new RouteData());

            Assert.AreEqual("Kathryn", data.Parameters.Name);
            Assert.AreEqual("Hello Kathryn", data.Response);
        }
    }
        

Module style route handlers in Asp.Net Web Api

Attribute routing in Asp.Net is pretty useful, but it still constrains you to the traditional construct of Controller\Action. With very little effort you can now break the mold and use Nancy\Sinatra style modules, complete with model binding and dependency injection.

If you like to define your routes close to where they're handled then this is the solution for you, and of course you still get all the benefits of both Web Api and Graph Based Routing.

Setup


    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            SuperscribeConfig.RegisterModules(config);
        }
    }
        

Add a module


    public class HelloWorldModule : SuperscribeModule
    {
        public HelloWorldModule()
        {
            this.Get["/"] = o => "Hello World!";

            this.Get["Hello" / (String)"Name"] = 
                o => string.Format("Hello {0}", o.Parameters.Name);

            this.Post["Save"] = o =>
            {
                var wrapper = o.Bind<MessageWrapper>();
                return new { Message = "You entered - " + wrapper.Message };
            };
        }
    }
        

Don't do any more route parsing than neccesary

Modern web applications are composed of multiple components, sometimes even multiple frameworks and many of these need to perform routing of some kind. With Superscribe, you can perform your routing once at the start of your pipeline and then re-use the results in your application wherever you need them.


    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var define = OwinRouteEngineFactory.Create();
            var httpconfig = new HttpConfiguration();

            SuperscribeConfig.Register(httpconfig, define);

            define.Route("Values".Controller());
            define.Route("Admin" / "Users".Controller());
            define.Route("Admin" / "Teams".Controller());
            
            // Use Superscribe to perform routing at the start of the pipeline...
            app.UseSuperscribeRouter(define)
                .UseWebApi(httpconfig)
                .WithSuperscribe(httpconfig, define);
            // ...then tell web api or other middleware to reuse the results
        }
    }
        

Combine your routing and Owin pipelines

With the Superscribe.Owin package, your routing routing pipeline and your Owin pipeline become one. Superscribe provides Superscribe Router for middleware routing and branching.

Superscribe Router


    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var httpconfig = new HttpConfiguration();
            httpconfig.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/webapi/",
                defaults: new { controller = "Hello" }
            );

            var define = OwinRouteEngineFactory.Create();

            // Set up a route that will forward requests to either web api or nancy
            define.Pipeline("api/webapi").UseWebApi(httpconfig);
            define.Pipeline("api/nancy").UseNancy();
            
            app.UseSuperscribeRouter(define);
        }
    }
        

Handle requests directly in Owin

For those situations when simplicity and raw speed are key, Superscribe Handler allows you to respond to requests without the need for a bulky web framework.

Superscribe Handler


    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var define = OwinRouteEngineFactory.Create();
            
            define.Get("Hello/World", o => "Hello World");
            
            app.UseSuperscribeRouter(define)
                .UseSuperscribeHandler(define);
        }
    }
        

You can use modules to respond to Owin requests too:


    public class HelloWorldModule : SuperscribeOwinModule
    {
        public HelloWorldModule()
        {
          this.Get["/"] = o => "Hello Owin!";
        }
    }
        

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var define = OwinRouteEngineFactory.Create();
                        
            app.UseSuperscribeRouter(define)
                .UseSuperscribeHandler(define);
        }
    }