C# 在ASP.NET核心中是否可能有多个仅随参数变化的GET?
我想构建真正的RESTful web服务,因此不想利用RPC样式,因此目前有以下内容:C# 在ASP.NET核心中是否可能有多个仅随参数变化的GET?,c#,asp.net-core,.net-core,asp.net-core-routing,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(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)
{
}
[HttpGet]
[ActionName(nameof(GetByParticipant))]
公共异步任务GetByParticipant([FromQuery]string participantId,[FromQuery]string participantType,[FromQuery]string programName)
{
}
[HttpGet]
[ActionName(nameof(GetByProgram))]
公共异步任务GetByProgram([FromQuery]字符串程序名)
{
}
我相信这在ASP.NETWebAPI中是可行的。但我有个例外:
AmbiguousActionException:匹配了多个操作。以下操作与路线数据匹配,并满足所有约束条件:
TermsController.GetByParticipant(ParticipantTerms.Api)
TermsController.GetByProgram(ParticipantTerms.Api)
这两个属性实际上都没有帮助:
[HttpGet]
[ActionName]
[FromQuery]
api/action?participantId=1和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) {
//...
}
}
公共类参与者查询{
公共字符串participantId{get;set;}
公共字符串participantType{get;set;}
公共字符串程序名{get;set;}
}
[路由(“api/[控制器]”)]
公共类术语控制器:控制器{
[HttpGet(“参与者”)]//获取api/terms/participants?participantId=123&。。。。
[ActionName(nameof(GetByParticipant))]
公共异步任务GetByParticipant([FromQuery]ParticipantQuery模型){
//...
}
[HttpGet(“programs/{programName}”)]///GET-api/terms/programs/name
[ActionName(nameof(GetByProgram))]
公共异步任务GetByProgram(字符串程序名){
//...
}
}
或者,可以使用一个动作封装可用参数,并根据提供的成员对结果进行分支
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) {
//...
}
}
公共类GetTermsQuery{
公共字符串participantId{get;set;}
公共字符串participantType{get;set;}
公共字符串程序名{get;set;}
}
[路由(“api/[控制器]”)]
公共类TermsController:控制器{
[HttpGet]//获取api/术语?participantId=123&。。。。
公共异步任务Get([FromQuery]GetTermsQuery模型){
//...
}
}
您可以使用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)
{
}
公共类ExactQueryParamAttribute:属性,IActionConstraint
{
私有只读字符串[]键;
公共ExactQueryParamAttribute(参数字符串[]键)
{
this.keys=keys;
}
公共整数顺序=>0;
公共bool Accept(ActionConstraintContext上下文)
{
var query=context.RouteContext.HttpContext.Request.query;
返回query.Count==keys.Length&&keys.All(key=>query.ContainsKey(key));
}
}
[HttpGet]
[ActionName(nameof(GetByParticipant))]
[ExactQueryParam(“participantId”、“participantType”、“programName”)]
公共异步任务GetByParticipant([FromQuery]string participantId,[FromQuery]string participantType,[FromQuery]string programName)
{
}
[HttpGet]
[ActionName(nameof(GetByProgram))]
[ExactQueryParam(“程序名”)]
公共异步任务GetByProgram([FromQuery]字符串程序名)
{
}
我花了一整天的时间来尝试这个和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 ...;
}
[HttpGet]
[ExactQueryParam(“活动”)]
公共IEnumerable GetAll(
[FromQuery]布尔激活)
{
返回。。。
}
[HttpGet]
[ExactQueryParam(“活动”、“公司ID”)]
公共IEnumerable GetByCompanyId(
[FromQuery]布尔激活,[FromQuery]公司ID)
{
返回。。。;
}
使用from查询时,您需要唯一区分操作的路径,否则您将得到不明确的操作异常。原因是api/action?participantId=1和participantType=2
与api/action?programName=x
是相同的,区分操作是我在这里可以找到的常见建议。但我觉得这不是一个基于资源的适当休息,例如,GET-api/terms/?cond=a
和GET-api/terms?cond=b
其中api/terms
是术语资源。想知道是否有办法定制ASP.NET核心以模仿以前的Web apibehavior@abatishchev在提供的更新中,您的想法是什么。@abatishchev关键是两个操作都使用了相同的programName
,否则您可以尝试[FromRoute]
属性。在上也询问了此问题