是否有可能只有ASP.NET Core中的参数不同的多个GET?

时间:2017-09-28 20:41:38

标签: c# asp.net-core .net-core asp.net-core-routing

我想构建真正的RESTful Web服务,所以不想利用RPC风格,所以目前有这个:

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

我认为这可以在ASP.NET Web API中使用。但是我得到了一个例外:

  

AmbiguousActionException:匹配多个动作。以下操作匹配路由数据并满足所有约束:

     

TermsController.GetByParticipant(ParticipantTerms.Api)

     

TermsController.GetByProgram(ParticipantTerms.Api)

这两个属性实际上都没有帮助:

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

3 个答案:

答案 0 :(得分:8)

您可以使用IActionConstraint执行此操作。

以下是一个例子:

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

答案 1 :(得分:6)

从查询中使用时,您需要唯一地区分操作&#39;路线否则你会得到模棱两可的动作例外。原因api/action?participantId=1&participantType=2api/action?programName=x

相同

建议:

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

或者您可以使用一个封装可用参数的操作,并根据提供的成员分支结果

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

答案 2 :(得分:2)

我已经花了整整一天的时间尝试这样做,而且安德鲁·拉德福德(Andrew Radford)的解决方案非常完美!

[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 ...;
}