Is it possible to have multiple GETs that vary only by parameters in ASP.NET Core?

情到浓时终转凉″ 提交于 2019-11-26 23:04:38

问题


I want to build truly RESTful web service so don't want to leverage RPC-style, so have currently this:

[HttpGet]
[ActionName(nameof(GetByParticipant))]
public async Task<IActionResult> GetByParticipant([FromQuery]string participantId, [FromQuery]string participantType, [FromQuery]string programName)
{
}

[HttpGet]
[ActionName(nameof(GetByProgram))]
public async Task<IActionResult> GetByProgram([FromQuery]string programName)
{
}

And I believe that would work in ASP.NET Web API. But I'm getting an exception:

AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied:

TermsController.GetByParticipant (ParticipantTerms.Api)

TermsController.GetByProgram (ParticipantTerms.Api)

Neither of the attributes actually help:

  • [HttpGet]
  • [ActionName]
  • [FromQuery]

回答1:


You can do this using an IActionConstraint.

Here is an example:

public class ExactQueryParamAttribute : Attribute, IActionConstraint
{
    private readonly string[] keys;

    public ExactQueryParamAttribute(params string[] keys)
    {
        this.keys = keys;
    }

    public int Order => 0;

    public bool Accept(ActionConstraintContext context)
    {
        var query = context.RouteContext.HttpContext.Request.Query;
        return query.Count == keys.Length && keys.All(key => query.ContainsKey(key));
    }
}

[HttpGet]
[ActionName(nameof(GetByParticipant))]
[ExactQueryParam("participantId", "participantType", "programName")]
public async Task<IActionResult> GetByParticipant([FromQuery]string participantId, [FromQuery]string participantType, [FromQuery]string programName)
{
}

[HttpGet]
[ActionName(nameof(GetByProgram))]
[ExactQueryParam("programName")]
public async Task<IActionResult> GetByProgram([FromQuery]string programName)
{
}



回答2:


When using from query you need to uniquely differentiate the actions' routes otherwise you will get the ambiguous action exception. Reason being api/action?participantId=1&participantType=2 is the same as api/action?programName=x

Suggestion:

public class ParticipantQuery {
    public string participantId { get; set; } 
    public string participantType { get; set; }
    public string programName { get; set; }
}

[Route("api/[controller]")]
public class TermsController : Controller {

    [HttpGet("participants")]  //GET api/terms/participants?participantId=123&....
    [ActionName(nameof(GetByParticipant))]
    public async Task<IActionResult> GetByParticipant([FromQuery]ParticipantQuery model) {
        //...
    }

    [HttpGet("programs/{programName}")]//GET api/terms/programs/name
    [ActionName(nameof(GetByProgram))]
    public async Task<IActionResult> GetByProgram(string programName) {
        //...
    }
}

Or you can use one action that encapsulates the available parameters and branch the result based on the provided members

public class GetTermsQuery {
    public string participantId { get; set; } 
    public string participantType { get; set; }
    public string programName { get; set; }
}

[Route("api/[controller]")]
public class TermsController : Controller {    
    [HttpGet]  //GET api/terms?participantId=123&....
    public async Task<IActionResult> Get([FromQuery]GetTermsQuery model) {
        //...
    }
}



回答3:


I've spent all day trying to do this and Andrew Radford's solution and this was perfect!

[HttpGet]
[ExactQueryParam("active")]
public IEnumerable<UserSelectAllSprocResult.DataRow> GetAll(
  [FromQuery] bool active)
{
  return ...
}

[HttpGet]
[ExactQueryParam("active", "companyId")]
public IEnumerable<UserSelectAllByCompanySprocResult.DataRow> GetByCompanyId(
  [FromQuery] bool active, [FromQuery] int companyId)
{
  return ...;
}


来源:https://stackoverflow.com/questions/46477959/is-it-possible-to-have-multiple-gets-that-vary-only-by-parameters-in-asp-net-cor

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