How to include Query String in the route resolution in order to allow multiple Actions with the same Method, Route and Query String?

☆樱花仙子☆ 提交于 2020-05-09 07:54:28

问题


I am converting an ASP.NET MVC (.NET Framework) application to ASP.NET Core MVC. This is strictly a conversion, I cannot make any breaking changes hence I cannot change any Routes or Methods. I am unable to match the same functionality in ASP.NET Core MVC.

Working ASP.NET MVC:

  [HttpPut]
  [Route("status")]
  public async Task<IHttpActionResult> UpdateStatusByOrderGuid([FromUri] Guid orderGUID, [FromBody] POST_Status linkStatusModel)
  {

  }

  [HttpPut]
  [Route("status")]
  public async Task<IHttpActionResult> UpdateStatusById([FromUri] Guid id, [FromBody] POST_Status linkStatusModel)
  {

  }

Not working, ASP.NET Core MVC.

I get an error:

Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints

Code:

    [HttpPut]
    [Route("status")]
    public async Task<IActionResult> UpdateStatusByOrderGuid([FromQuery] Guid orderGUID, [FromBody] POST_Status statusModel)
    {

    }

    [HttpPut]
    [Route("status")]
    public async Task<IActionResult> UpdateStatusById([FromQuery] Guid id, [FromBody] POST_Status statusModel)
    {

    }

I need to include the query parameters when it resolves which route. It should match based on whether orderGUID or id is in the query string.

Thanks.


回答1:


Why not use a single endpoint instead? You don't need to pass Guid's, since it's a GET operation, you can pass strings and cast them later. That way you can send one parameter or the other.

[HttpPut]
[Route("status")]
public async Task<IActionResult> UpdateStatus([FromBody] POST_Status statusModel, [FromQuery] string orderGUID = null, [FromQuery] string id = null)
{
    if (!string.IsNullOrEmpty(orderGUID))
    {
        // UpdateStatusByOrderGuid implementation here
        // Guid guid = Guid.Parse(orderGUID);

    }
    else if (!string.IsNullOrEmpty(id))
    {
        // UpdateStatusById implementation here
        // Guid guid = Guid.Parse(id);
    }
    else
    {
        throw new ArgumentException("No valid GUID.");
    }
}

This endpoint should be compatible with both scenarios you specified.




回答2:


You needs to custom 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:

[HttpPut]
[Route("status")]
[QueryStringConstraint("orderGUID",true)]
[QueryStringConstraint("id", false)]
public void UpdateStatusByOrderGuid([FromQuery] Guid orderGUID,[FromBody]POST_Status model)
{

}

[HttpPut]
[Route("status")]
[QueryStringConstraint("id", true)]
[QueryStringConstraint("orderGUID", false)]
public void UpdateStatusById([FromQuery] Guid id, [FromBody]POST_Status model)
{

}

3.Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //...
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Result:



来源:https://stackoverflow.com/questions/60767827/how-to-include-query-string-in-the-route-resolution-in-order-to-allow-multiple-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!