A simple reverse proxy implementation for use in an ASP.NET Core application.
This reverse proxy implementation is inspired by how Mvc uses routing to actions.
Package Manager:
PM> Install-Package Spinit.AspNetCore.ReverseProxy
.NET CLI:
> dotnet add package Spinit.AspNetCore.ReverseProxy
public void ConfigureServices(IServiceCollection services)
{
services
...
.AddReverseProxy(options =>
{
// optional configuration
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app
...
.UseMvc() // recommendation is to use Mvc before the reverse proxy to allow proxy overrides in controllers
.UseReverseProxy(c =>
{
c.MapRoute(
"proxy/http/{*uri}", // the route template to use, see https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing
rd => new Uri($"http://{rd.Values["uri"]}", UriKind.Absolute) // supply a function that given the route data from the template should return the proxy uri
);
c.MapRoute(
...
);
});
}
Filters are inspired by Mvc filters and is an extension point for acting before a proxy request is sent.
public class MyLoggingFilter : IReverseProxyFilter
{
private readonly ILogger _logger;
public MyLoggingFilter(ILogger<MyLoggingFilter> logger)
{
_logger = logger;
}
public Task OnExecutingAsync(ReverseProxyExecutingContext context)
{
// here you can modify the outgoing proxy request before it is sent
_logger.LogDebug($"Calling proxy: {context.ProxyRequest.RequestUri.ToString()}");
return Task.CompletedTask;
}
}
public void ConfigureServices(IServiceCollection services)
{
services
...
.AddReverseProxy(options =>
{
options.Filters.Add<MyLoggingFilter>()
});
}
The IReverseProxy
can be used in a controller if this is desired.
[Route("api/[controller]")]
[ApiController]
public class ProxyController : ControllerBase
{
private readonly IReverseProxy _reverseProxy;
public ProxyController(IReverseProxy reverseProxy)
{
_reverseProxy = reverseProxy;
}
[HttpGet]
public async Task<IActionResult> Get()
{
var proxyUri = new Uri("http://myapiserver:7331/api/");
var proxyResponse = await _reverseProxy.ExecuteAsync(Request, proxyUri).ConfigureAwait(false);
return new ResponseResult(proxyResponse); // use ResponseResult to wrap the proxyResponse in a IActionResult implementation
}
}