根据查询参数值将 HTTP 请求映射/路由到端点? asp.net核心3.x

Map / Route HTTP Request to endpoint based on query parameter value? asp.net core 3.x

我有一个客户端需要使用 rest HttpGet 调用为多个请求访问相同的基本端点 url,每个请求都具有唯一的查询参数和值。我需要为每个请求映射的函数将由 "request" 查询参数提供的值决定。是否可以在 app.UseEndpoints()、端点函数的属性或类似的简单解决方案中执行此操作?

我对这部分有点陌生,文档中没有这方面的示例。到目前为止我所拥有的(不起作用):

Startup.cs

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "test1",
            pattern: "serviceapi",
            constraints: new { request = "test1" }, //map action if param "request" value is "test1"?
            defaults: new { controller = "ServiceApi", action = "TestRequest1" }
        );
        endpoints.MapControllerRoute(
            name: "test2",
            pattern: "serviceapi",
            constraints: new { request = "test2" }, //map action if param "request" value is "test2"?
            defaults: new { controller = "ServiceApi", action = "TestRequest2" }
        );
    });

我想要的是当我使用邮递员向“{{url}}/api/serviceapi/?request=test1&uniqueparam1=foo", 它运行我的 ServiceApi.TestRequest1()

中的代码
[Route("api/[controller]")]
ServiceApiController.cs

    [HttpGet]
    public async Task<IActionResult> TestRequest1([FromQuery]string request, [FromQuery]string uniqueparam1)
    {
        return Ok($"TestRequest1: {request} - {uniqueparam1}");
    }

    [HttpGet]
    public async Task<IActionResult> TestRequest2([FromQuery]string request, [FromQuery]string uniqueparam2, [FromQuery]string uniqueparam3)
    {
        return Ok($"TestRequest2: {request} - {uniqueparam2}, {uniqueparam3}");
    }

我目前使用此代码得到的错误是两个函数都是候选函数:"Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints."

谢谢!

------ 更新 ------

多亏了 Rena 的回答,我才能够正常工作:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class RequestValueConstraintAttribute : ActionMethodSelectorAttribute
{
    public string RequestValue { get; private set; }

    private readonly string _requestParam = "request";

    public RequestValueConstraintAttribute(string requestValue)
    {
        RequestValue = requestValue;
    }

    public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
    {
        return (string)routeContext.HttpContext.Request.Query[_requestParam] == RequestValue;
    }
}

ServiceApiController.cs

[Route("api/[controller]")]
[ApiController]
public class ServiceApiController : ControllerBase
{
    [RequestValueConstraint("test1")] //uses this endpoint function if param "request" value is "test1"
    [HttpGet]
    public async Task<IActionResult> TestRequest1([FromQuery]string request, [FromQuery]string uniqueparam1)
    {
        return Ok($"TestRequest1: {request} - {uniqueparam1}");
    }

    [RequestValueConstraint("test2")] //uses this endpoint function if param "request" value is "test2"
    [HttpGet]
    public async Task<IActionResult> TestRequest2([FromQuery]string request, [FromQuery]string uniqueparam2, [FromQuery]string uniqueparam3)
    {
        return Ok($"TestRequest2: {request} - {uniqueparam2}, {uniqueparam3}");
    }
}

您需要自定义 ActionMethodSelectorAttribute:

1.QueryStringConstraintAttribute:

[AttributeUsage(AttributeTargets.Method,AllowMultiple =true)]
public class QueryStringConstraintAttribute : ActionMethodSelectorAttribute
{
    public string ValueName { get; private set; }
    public bool ValuePresent { get; private set; }
    public QueryStringConstraintAttribute(string valueName,bool valuePresent)
    {
        this.ValueName = valueName;
        this.ValuePresent = valuePresent;
    }
    public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
    {
        var value = routeContext.HttpContext.Request.Query[this.ValueName];
        if(this.ValuePresent)
        {
            return !StringValues.IsNullOrEmpty(value);
        }
        return StringValues.IsNullOrEmpty(value);
    }
}

2.Controller:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : Controller
{
    [QueryStringConstraint("uniqueparam1", true)]
    [QueryStringConstraint("uniqueparam2", false)]
    [HttpGet]
    public async Task<IActionResult> TestRequest1([FromQuery]string request, [FromQuery]string uniqueparam1)
    {
        return Ok($"TestRequest1: {request} - {uniqueparam1}");
    }
    [QueryStringConstraint("uniqueparam2", true)]
    [QueryStringConstraint("uniqueparam1", false)]
    [HttpGet]
    public async Task<IActionResult> TestRequest2([FromQuery]string request, [FromQuery]string uniqueparam2, [FromQuery]string uniqueparam3)
    {
        return Ok($"TestRequest2: {request} - {uniqueparam2}, {uniqueparam3}");
    }
}

3.Startup.cs:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //...   
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();                
    });

}

参考: