Telerik blogs
owin_header

OWIN (which stands for Open Web Interface for .NET) allows a developer to decouple their ASP.NET application from a web server, such as IIS. Additionally, OWIN allows developers to "plug in" various components to their web apps without tightly coupling them to one another. A good example of this may be to build a logger which logs various information about each request to an external source.

When rebuilding a web site, the URLs for your individual pages, blog posts and whatnot frequently change. If you care about your "SEO juice" or inbound links to your site, you'll probably want to make redirects to handle this.

I recently rebuilt my personal site, mattmillican.com, using the new ASP.NET vNext framework. Although I could have done redirects the "old way" in the web.config, I decided to set out in creating OWIN middleware to do the job. In this article, we'll look at how to build this solution. This was actually my first time building my own piece of middleware, and it was pretty painless.

Creating the Redirect Service

I'm a big fan of "services" for any data access and logic handling. While in this particular case, a service may be overkill, I decided to still make one for encapsulation and unit testing purposes.

Let's look at the service below:

public interface IRedirectService
{
    bool UrlHasRedirect(string url, out string redirectUrl);
}

public class RedirectService : IRedirectService
{
    private readonly List<Redirect>
        _redirects;

    public RedirectService(IOptions<Redirects> redirects)
    {
        _redirects = redirects.Value.Permanent;
    }

    public bool UrlHasRedirect(string url, out string redirectUrl)
    {
        var redirect = _redirects.SingleOrDefault(x => x.Source == url);

        if (redirect == null)
        {
            redirectUrl = null;
            return false;
        }
        redirectUrl = redirect.Dest;
        return true;
    }
}

I'm injecting the redirects via the built-in IOptions interface that vNext provides. We'll look at how this is registered later in the configuration section. The only method this class has is a UrlHasRedirect method. It returns a bool if the URL (source) has a redirect method. If it finds a redirect for the source, it returns the destination via the out parameter, redirectUrl.

Creating the Middleware

The middleware class is fairly simple. We'll walk through each of the parts.

First, note that the constructor is taking in a RequestDelegate (as part of the OWIN middleware) and an IRedirectService (shown above). The Invoke method is where all the magic lives for the middleware. It takes the current request's URL, and then checks to see if there is a redirect for that URL via the IRedirectService.

If a redirect exists, the request is redirected to the destination URL. Otherwise, the request will continue to be processed normally. I do all my redirects as a 301 Permanent Redirect, which is what the true in the Redirect call signifies.

public class UrlRedirectMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IRedirectService _redirectService;

    public UrlRedirectMiddleware(RequestDelegate next, IRedirectService redirectService)
    {
        _next = next;
        _redirectService = redirectService;
    }

    public async Task Invoke(HttpContext context)
    {
        var url = context.Request.Path.ToString();
        string redirectTo;

        if (_redirectService.UrlHasRedirect(url, out redirectTo))
        {
            context.Response.Redirect(redirectTo, true);
        }
        else
        {
            await _next(context);
        }
    }
}

Extension Method

In order to make the middleware easier to call from the Startup class (which we'll cover later), you can also make an extension method. Again, this is fairly simple with only a few lines of code.

public static class RedirectExtensions
{
    public static IApplicationBuilder UseRedirects(this IApplicationBuilder appBuilder)
    {
        var redirectService = appBuilder.ApplicationServices.GetService(typeof (IRedirectService));
        return appBuilder.UseMiddleware<UrlRedirectMiddleware>(redirectService);
    }
}

This method uses the "dependency resolver" (provided out of the box with vNext) to resolve the IRedirectService, then tells the application to use the UrlRedirectMiddleware and passes the redirect service to it.

The redirect.json File

Because URL redirects rarely change, I decided I didn't need to create an admin UI or anything for it - the redirects are stored in a JSON file. The format follows the snippet below.

{
  "Permanent": [
    {
      "Source": "/about-matt",
      "Dest":  "/about"
    },
  ]
}

This JSON file gets deserialized into the class Redirects, which just contains a List<Redirect>, as shown here:

public class Redirects
{
    public List<Redirect> Permanent { get; set; }
}

public class Redirect
{
    public string Source { get; set; }
    public string Dest { get; set; }
}

Configuration

The last and final part of the redirect middleware is to configure it in the Startup class. This entails a few different steps.

The first is to register the Redirects class as an IOptions<T> instance, and read the data from the redirects.json file. By convention, vNext will match the class name to the file name (sans the ".json"). Registering the file is a simple line in the ConfigureServices() method.

services.Configure<Redirects>(Configuration);

Also in the ConfigureServices() method, we need to register the IRedirectService. This is done like so:

services.AddTransient<IRedirectService, RedirectService>();

The last and final thing to do is to tell the application to use the middleware in the Configure() method of Startup. Again, this a simple one-liner:

app.UseRedirects();

So, here is just one example of how you could incorporate OWIN middleware into your next vNext project. There are many ways you could incorporate and leverage OWIN - the 301 redirect module is just one of those.

Header image courtesy of Richard Drdul


Telerik Blogging Ninja
About the Author

The Telerik Team

 

Comments

Comments are disabled in preview mode.