ASP.NET Core中的基于标头的路由

17

我想根据发送到服务的HTTP标头将请求路由到不同的控制器。

在我的Configure方法中,我有:

app.MapWhen(ctx => !string.IsNullOrWhiteSpace(ctx.Request.Headers["Magic"]), DoStuff);

我的问题是我不知道如何指定控制器,甚至修改路由

 private static void DoStuff(IApplicationBuilder app)
 {
    /// ?!? \\\
 }
理想情况下,如果发送标题为Magic: Missile,则重写路由为/Missile
2个回答

24

虽然编写自定义中间件是一个不错的选择,但另一个选择是创建一个操作约束(通过实现 IActionContraint 接口)。这将允许您使用属性装饰您的方法,该属性指定必须在请求中提供的标头/值,以便调用给定方法。

我发现在使用 WebHooks 时特别有帮助,其中外部系统使用单个 URL 进行所有 hook,并使用标头来区分不同的操作类型。

这里是这个属性的简单实现示例:

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;
}

这里是一个如何使用它的示例:

    [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)
    {

    }

8

最终我编写了一段自定义中间件,重写URI后再触发MVC层。效果很好!

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);
}

1
我没有尝试过,但是像接受的答案中的操作约束这样的方式更加简洁。 - ESG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接