【问题标题】:Header based routing in ASP.NET CoreASP.NET Core 中基于标头的路由
【发布时间】:2016-09-03 00:15:55
【问题描述】:

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

在我的Configure 方法中,我有

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

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

 private static void DoStuff(IApplicationBuilder app)
 {
    /// ?!? \\\
 }

理想情况下,如果发送标头Magic: Missile,我希望将路由重写为/Missile

【问题讨论】:

    标签: routing asp.net-core


    【解决方案1】:

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

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

    以下是该属性的简单实现:

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

    【讨论】:

      【解决方案2】:

      我最终编写了一个自定义中间件来在访问 mvc 层之前重写 uri。效果很好!

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

      【讨论】:

      • 我没有尝试过,但是动作限制,例如在接受的答案中,是一种更简洁的方法
      猜你喜欢
      • 2018-08-28
      • 1970-01-01
      • 2017-11-20
      • 1970-01-01
      • 1970-01-01
      • 2016-06-24
      • 2020-12-16
      • 2021-08-02
      相关资源
      最近更新 更多