【问题标题】:Multiple optional parameters including enum type in ASP.NET Core Web API routing多个可选参数,包括 ASP.NET Core Web API 路由中的枚举类型
【发布时间】:2020-08-29 04:33:18
【问题描述】:

我正在我的 ASP.NET Core Web Api 中创建一个采用多个参数的方法,所有这些参数都是可选的。在邮递员上调用此方法时出现错误:

System.InvalidOperationException: The constraint reference 'StatusEnum' could not be resolved to a type. Register the constraint type with 'Microsoft.AspNetCore.Routing.RouteOptions.ConstraintMap'

如何在路由中使用枚举作为我的参数类型? 我的控制器:

[HttpPost("filter-reports/{reportStatus:StatusEnum?}/{IsNecessary:bool?}/{completionStatus: completionStatusEnum?}")]
    [Authorize]
    public ObjectResult GetDamageReportByFilters(StatusEnum? reportStatus, bool? IsNecessary, completionStatusEnum? completionStatus)
    {
        var result = _reportService.GetReportByFilters(reportStatus,IsNecessary, completionStatus);

        return StatusCode(200, result);
    }

我该如何解决这个问题?

【问题讨论】:

    标签: c# asp.net-core asp.net-web-api enums routes


    【解决方案1】:

    这个问题已经有很长时间了,但我希望这能帮助其他正在寻找相同问题的人:https://nickheath.net/2019/02/20/asp-net-core-enum-route-constraints/

    我刚刚个性化:

    namespace MyWebApp
    {
        using Microsoft.AspNetCore.Http;
        using Microsoft.AspNetCore.Routing;
        public static partial class Extensions
        {
            public class CustomRouteConstraint<TEnum> : IRouteConstraint
                where TEnum : struct, Enum
            {
                public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
                {
                    // retrieve the candidate value
                    var candidate = values[routeKey]?.ToString();
                    // attempt to parse the candidate to the required Enum type, and return the result
                    return Enum.TryParse(candidate, true, out TEnum _);
                }
            }
        }
    }
    

    在 startup.cs 上:

    public void ConfigureServices(IServiceCollection services)
    {
        //...
        //! Enum route constraints: ref https://nickheath.net/2019/02/20/asp-net-core-enum-route-constraints/
        services.Configure<Microsoft.AspNetCore.Routing.RouteOptions>(options =>
        {
            options.ConstraintMap.Add("MyCustomEnum", typeof(MyWebApp.Extensions.CustomRouteConstraint<Models.MyCustomEnum>));
        });
        //...
    }
    

    终于行动起来了:

    [Route("/{area:MyCustomEnum}")]
    public async Task<IActionResult> ViewAsync(MyCustomEnum area)
    {
        //...
    }
    

    【讨论】:

      【解决方案2】:

      如果您只想将值解析为 Enum 对象,那么您只需为每个 Enum 类型添加自定义模型绑定器

      Custom Model Binding in ASP.NET Core

      【讨论】:

        【解决方案3】:

        您的问题是,通过希望将路由参数的值限制为枚举值,您使用了不正确的路由约束:您不能使用枚举的名称作为路由约束(供参考,有效的路由限制列在this page)

        你不需要指定约束来标记一个路由参数为可选,你可以使用问号:

        [HttpPost("filter-reports/{reportStatus?}/{IsNecessary:bool?}/{completionStatus?}")]
        [Authorize]
        public ObjectResult GetDamageReportByFilters(StatusEnum? reportStatus, bool? IsNecessary, completionStatusEnum? completionStatus)
        {
            var result = _reportService.GetReportByFilters(reportStatus,IsNecessary, completionStatus);
        
            return StatusCode(200, result);
        }
        

        请注意,由于没有路由约束,因此可以将任何值传递给 enum 参数。如果那不是有效值,则传递给函数的实际值为 0。如果 0 映射到有效的枚举值,则使用该值,否则只需处理 0 值(在 C# 中,任何 @987654323 @value 可以存储在枚举中)。

        【讨论】:

          【解决方案4】:

          一种更简单的方法(无需关心约束映射)是用实际枚举值的简单字符串/整数表示替换您方法的 StateEnum 参数,并将其作为参数的一部分在您的方法中解析。

          [HttpPost("Test/{state}")]
          public IActionResult TestMethod(string state)
          {
              if (!Enum.TryParse(state, true, out StateEnum stateEnumValue))
                  return BadRequest();
          
              // Do stuff here
          
              return Accepted();
          }
          
          [HttpPost("Test2/{state}")]
          public IActionResult TestMethod2(int state)
          {
              StateEnum stateEnumValue = (StateEnum) state;
              // Do stuff here
              return Accepted();
          }
          
          public enum StateEnum
          {
              FirstState = 1,
              SecondState = 2
          }
          

          但由于您的参数是可选的,您可以尝试使用查询字符串来代替,允许您省略不需要的参数来请求。或者(正如其他答案所建议的那样)使用代表您的参数的 pbject (因为在那里管理可选内容更容易)

          【讨论】:

            【解决方案5】:

            路由中不能有可选参数;

            如果reportStatusisNecessary 是可选的,URL 会是什么样子?

            ../filter-reports/?/?/COMPLETED?

            从你的参数中创建一个模型并将其发送到 post 方法的主体中,然后它们可以是可选的

            【讨论】:

            • 路由中可以有可选参数,就像函数调用中可以有可选参数一样。你只需要按照它们被声明的顺序传递它们。
            • 如果只有一个可选参数,它可能会起作用,但是对于 3?您将如何使用 reportStatus:StatusEnum?IsNecessary:bool? 作为空值来调用此操作?
            • 你不能 :) 在 C# 中,你需要使用命名参数(例如 Get(completionStatusEnum: MyEnum)),并且 URL 中不存在命名参数。这并不意味着所有 3 个参数都不能是可选的。一个简单的例子是日期Get/{year?}/{month?}/{day?}:然后您接受Get/2020Get/2020/05Get/2020/05/13
            • 注意,根据需要,也可以使用查询参数代替路由参数。
            • 是的,我知道我不能,这就是我在回答中提到的,然后你说You can have optional parameters in a route, just like you can have optional parameters on a function,所以我开始想你是什么意思
            猜你喜欢
            • 2021-10-30
            • 2022-08-15
            • 2017-06-26
            • 2017-08-30
            • 1970-01-01
            • 1970-01-01
            • 2018-08-28
            • 1970-01-01
            • 2018-09-24
            相关资源
            最近更新 更多