【问题标题】:Is it possible to have multiple GETs that vary only by parameters in ASP.NET Core?是否可以有多个 GET 仅因 ASP.NET Core 中的参数而异?
【发布时间】:2018-03-10 17:13:19
【问题描述】:

我想构建真正的 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]

【问题讨论】:

  • 使用 from 查询时,您需要唯一区分操作的路线,否则您将获得模棱两可的操作异常。成为api/action?participantId=1&amp;participantType=2 的原因与api/action?programName=x 相同

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


【解决方案1】:

您可以使用 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)
{
}

【讨论】:

    【解决方案2】:

    使用 from 查询时,您需要唯一区分操作的路线,否则您将获得模棱两可的操作异常。成为api/action?participantId=1&amp;participantType=2 的原因与api/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) {
            //...
        }
    }
    

    【讨论】:

    • 是的,区分动作是我在 SO 上可以找到的通常建议。但我觉得这不是基于资源的适当 REST,例如GET api/terms/?cond=aGET api/terms?cond=b 其中api/terms 是术语资源。
    • 想知道是否有办法自定义 ASP.NET Core 以模仿之前的 Web API 行为
    • @abatishchev 您对提供的更新有何想法。
    • @abatishchev 的问题是这两个动作都使用了共同的programName.,否则你可以尝试[FromRoute] 属性。
    • 也在GitHub上问过这个问题
    【解决方案3】:

    我已经花了一整天的时间来尝试这样做和 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 ...;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 2019-01-25
      • 1970-01-01
      • 2021-10-30
      • 2022-01-26
      • 1970-01-01
      相关资源
      最近更新 更多