我有以下课程:
public class GetLogsRequestDto
{
public LogLevel Level { get; set; }
public LogSortOrder SortOrder { get; set; }
}
我有一个Web API控制器(LogsController),其中包含以下两个操作:
async Task<IHttpActionResult> Get( [FromUri]int id )
async Task<IHttpActionResult> Get( [FromUri]GetLogsRequestDto dto )
第一个用于检索特定日志,第二个用于检索日志列表。当我通过:/ logs / 123对特定日志发出GET请求时,它会正确调用第一个操作,同样如果我对/ logs发出GET请求,它会正确调用第二个操作(该类中定义的属性是可选的)并且不需要总是提供。)
但是,我想更改第一个GET方法,所以它使用类而不是int id参数,就像这样(注意它为上面的第二个动作指定了一个不同的(单数)类型):
async Task<IHttpActionResult> Get( [FromUri]GetLogRequestDto dto )
这个GetLogRequestDto
类看起来像这样:
public class GetLogRequestDto
{
[Required]
[Range( 100, int.MaxValue )]
public int Id { get; set; }
}
我采用这种方法的原因是我可以通过标准ModelStateValidationActionFilter
验证模型,并在此类中放置任何特定的验证属性,而不是在使用'int id'参数方法时,然后必须执行验证。
当我实现这种方法并尝试调用/ logs / 1时,我收到以下错误:
找到了与请求匹配的多项操作
在这两种方法中,它不区分用作params的两种不同类型。
我配置的默认路由是:
config.Routes.MapHttpRoute(
name: "controller-id",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
我无法弄清楚为什么会出现问题 - 为什么它以某种方式工作而不是另一种方式。
答案 0 :(得分:0)
在GET请求中使用复杂类型处理单个基本类型参数(也是路径的一部分)并不是一个好主意。
通过使用此方法,框架将无法将您的路由参数绑定到该复杂类型(路由定义需要id
参数,该参数必须是简单类型。)
我强烈建议您还原更改并将id
参数再次设为int
。
作为替代方法,您可以遵循this great post并实施一个操作过滤器,该过滤器可以验证由验证属性修饰的方法参数,即使它们是简单类型。
此处摘录自Mark Vincze博客文章,其中包含用于验证操作参数的操作过滤器属性:
public class ValidateActionParametersAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var descriptor = context.ActionDescriptor as ControllerActionDescriptor;
if (descriptor != null)
{
var parameters = descriptor.MethodInfo.GetParameters();
foreach (var parameter in parameters)
{
var argument = context.ActionArguments[parameter.Name];
EvaluateValidationAttributes(parameter, argument, context.ModelState);
}
}
base.OnActionExecuting(context);
}
private void EvaluateValidationAttributes(ParameterInfo parameter, object argument, ModelStateDictionary modelState)
{
var validationAttributes = parameter.CustomAttributes;
foreach (var attributeData in validationAttributes)
{
var attributeInstance = CustomAttributeExtensions.GetCustomAttribute(parameter, attributeData.AttributeType);
var validationAttribute = attributeInstance as ValidationAttribute;
if (validationAttribute != null)
{
var isValid = validationAttribute.IsValid(argument);
if (!isValid)
{
modelState.AddModelError(parameter.Name, validationAttribute.FormatErrorMessage(parameter.Name));
}
}
}
}
}