I'm trying to route requests to different controllers based on a HTTP header sent to the service.
in my Configure
method, I have
app.MapWhen(ctx => !string.IsNullOrWhiteSpace(ctx.Request.Headers["Magic"]), DoStuff);
My issue is that I have no idea how to specify controllers, or even modify the route
private static void DoStuff(IApplicationBuilder app)
{
/// ?!? \\\
}
Ideally, I'd like that if the header Magic: Missile
is sent, to rewrite the route to be /Missile
While writing a custom middleware is certainly a good option, another option would be to create an action constraint (by implementing the IActionContraint interface). This would allow you to decorate your methods with an attribute which dictates the header / value that must be provided in the request in order for a given method to be invoked.
I found this to be particularly helpful when working with WebHooks where the external system uses a single URL for all hooks, and uses a header to differentiate the different action types.
Here is what a simple implementation of this attribute could look like:
public class HttpHeaderAttribute : Attribute, IActionConstraint
{
public string Header { get; set; }
public string Value { get; set; }
public HttpHeaderAttribute (string header, string value)
{
Header = header;
Value = value;
}
public bool Accept(ActionConstraintContext context)
{
if (context.RouteContext.HttpContext.Request.Headers.TryGetValue(Header, out var value))
{
return value[0] == Value;
}
return false;
}
public int Order => 0;
}
And here's a sample of how you could use it:
[HttpPost, Route("webhook"), HttpHeader("X-Drchrono-Event", "PATIENT_CREATE")]
public IActionResult DrChronoPatientCreate(WebHookData data)
{
}
[HttpPost, Route("webhook"), HttpHeader("X-Drchrono-Event", "PATIENT_MODIFY")]
public IActionResult DrChronoPatientModify(WebHookData data)
{
}
I ended up writing a custom middleware to rewrite the uri before hitting the mvc layer. Works nicely!
public Task Invoke(HttpContext context)
{
const string apiPath = "/api";
var magic context.Request.Headers["Magic"];
if (string.IsNullOrWhiteSpace(magic))
{
return _next.Invoke(context);
}
var path = context.Request.Path.ToUriComponent();
if (!path.StartsWith(apiPath))
{
return _next.Invoke(context);
}
path = string.Concat(path.Skip(apiPath.Length));
path = $"{apiPath}/{magic}{path}";
context.Request.Path = path;
return _next.Invoke(context);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With