Proxying HTTP requests in ASP.NET Core using Kestrel

Posted on Saturday, 2nd July 2016

A bit of a short post this week but hopefully one that will save some a bit of googling!

Recently I’ve been doing a lot of ASP.NET Core MVC and in one project I’ve been working on I have an admin login area. My first instinct was to create the login section as an Area within the main application project.

Creating a login area in the same application would work, but other than sharing an /admin/ path it really was a completely separate application. It has different concerns, a completely different UI (in this instance it’s an Angular 2 application talking to a back-end API). For these reasons, creating the admin section as an MVC Area just felt wrong - so I began to look at what Kestrel could offer in terms of proxying requests to another application. This way I could keep my user facing website as one project and the administration area as another, allowing them to grow independent of one another.

Whilst proxying requests is possible in IIS, I was keen to use Kestrel as I’d like the option of hosting the application across various platforms, so I was keen to see what Kestrel had to offer.

Enter the ASP.NET Core Proxy Middleware!

After a little digging it came to no surprise that there was some middleware that made proxying requests a breeze. The middleware approach to ASP.NET Core MVC lends itself to such a task and setup was so simple that I felt it merited a blog post.

After installing the Microsoft.AspNetCore.Proxy NuGet package via the “Install-Package Microsoft.AspNetCore.Proxy“ command, all I had to do was hook the proxy middleware up to my pipeline using the _MapWhen_ method within my application’s Startup class:

// Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ...

    app.MapWhen(IsAdminPath, builder => builder.RunProxy(new ProxyOptions
    {
        Scheme = "http",
        Host = "localhost",
        Port = "8081"
    }));

    ...

}

private static bool IsAdminPath(HttpContext httpContext)
{
    return httpContext.Request.Path.Value.StartsWith(@"/admin/", StringComparison.OrdinalIgnoreCase);
}

As you can see, all I’m doing is passing a method that checks the path begins with /admin/.

Once setup, all you need to do is set your second application (in this instance it’s my admin application) to the configured port. You can do this within the Program class via the _UseUrls_ extension method:

// Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseUrls("http://localhost:8081")
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        host.Run();
    }
}

Now, if you start up your application and navigate to /admin/ (or whatever path you’ve specified) the request should be proxied to your secondary application!

Happy coding!