C# Web Api 必需参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19278759/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Web Api Required Parameter
提问by Jason Boyd
Using ASP.NET Web API. Is there a way to automatically return a status code 400 if a parameter is null? I found this questionbut that is a global solution that is applied to all methods, I want to do this on a per method per parameter basis.
使用 ASP.NET Web API。如果参数为空,有没有办法自动返回状态代码 400?我发现了这个问题,但这是一个适用于所有方法的全局解决方案,我想在每个方法每个参数的基础上执行此操作。
So, for example, this is what I am currently doing:
因此,例如,这就是我目前正在做的事情:
public HttpResponseMessage SomeMethod(SomeNullableParameter parameter)
{
if (parameter == null)
throw new HttpResponseException(HttpStatusCode.BadRequest);
// Otherwise do more stuff.
}
I would really just like to do something like this (notice the required attribute):
我真的很想做这样的事情(注意 required 属性):
public HttpResponseMessage SomeMethod([Required] SomeNullableParameter parameter)
{
// Do stuff.
}
采纳答案by Jason Boyd
The approach I ended up using was to create a custom filter that I registered globally. The filter checks all request parameters for the RequiredAttribute
. If the attribute is found then it checks if the parameter was passed with the request (not null) and returns status code 400 if it was null. I also added a cache to the filter to store the required parameters for each request to avoid the reflection hit on future calls. I was pleasantly surprised to find that this works for value types as well since the action context stores the parameters as objects.
我最终使用的方法是创建一个我全局注册的自定义过滤器。过滤器检查RequiredAttribute
. 如果找到该属性,则它检查该参数是否与请求一起传递(非空),如果为空则返回状态代码 400。我还在过滤器中添加了一个缓存来存储每个请求所需的参数,以避免在以后的调用中发生反射。我惊喜地发现这也适用于值类型,因为动作上下文将参数存储为对象。
EDIT - Updated solution based on tecfield's comment
编辑 - 根据 tecfield 的评论更新解决方案
public class RequiredParametersFilter : ActionFilterAttribute
{
// Cache used to store the required parameters for each request based on the
// request's http method and local path.
private readonly ConcurrentDictionary<Tuple<HttpMethod, string>, List<string>> _Cache =
new ConcurrentDictionary<Tuple<HttpMethod, string>, List<string>>();
public override void OnActionExecuting(HttpActionContext actionContext)
{
// Get the request's required parameters.
List<string> requiredParameters = this.GetRequiredParameters(actionContext);
// If the required parameters are valid then continue with the request.
// Otherwise, return status code 400.
if(this.ValidateParameters(actionContext, requiredParameters))
{
base.OnActionExecuting(actionContext);
}
else
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
}
private bool ValidateParameters(HttpActionContext actionContext, List<string> requiredParameters)
{
// If the list of required parameters is null or containst no parameters
// then there is nothing to validate.
// Return true.
if (requiredParameters == null || requiredParameters.Count == 0)
{
return true;
}
// Attempt to find at least one required parameter that is null.
bool hasNullParameter =
actionContext
.ActionArguments
.Any(a => requiredParameters.Contains(a.Key) && a.Value == null);
// If a null required paramter was found then return false.
// Otherwise, return true.
return !hasNullParameter;
}
private List<string> GetRequiredParameters(HttpActionContext actionContext)
{
// Instantiate a list of strings to store the required parameters.
List<string> result = null;
// Instantiate a tuple using the request's http method and the local path.
// This will be used to add/lookup the required parameters in the cache.
Tuple<HttpMethod, string> request =
new Tuple<HttpMethod, string>(
actionContext.Request.Method,
actionContext.Request.RequestUri.LocalPath);
// Attempt to find the required parameters in the cache.
if (!this._Cache.TryGetValue(request, out result))
{
// If the required parameters were not found in the cache then get all
// parameters decorated with the 'RequiredAttribute' from the action context.
result =
actionContext
.ActionDescriptor
.GetParameters()
.Where(p => p.GetCustomAttributes<RequiredAttribute>().Any())
.Select(p => p.ParameterName)
.ToList();
// Add the required parameters to the cache.
this._Cache.TryAdd(request, result);
}
// Return the required parameters.
return result;
}
}
回答by Timothy Lee Russell
Set [Required]
on a property in your model and then check the ModelState
to see if it IsValid
.
设置[Required]
模型中的属性,然后检查ModelState
它是否存在IsValid
。
This will allow all the required properties to be tested at the same time.
这将允许同时测试所有必需的属性。
See the "Under-Posting" section @ Model validation in WebAPI
请参阅“Under-Posting”部分@WebAPI 中的模型验证
回答by James Law
A solution for asp.net core...
一个asp.net核心的解决方案...
[AttributeUsage(AttributeTargets.Method)]
public sealed class CheckRequiredModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var requiredParameters = context.ActionDescriptor.Parameters.Where(
p => ((ControllerParameterDescriptor)p).ParameterInfo.GetCustomAttribute<RequiredModelAttribute>() != null).Select(p => p.Name);
foreach (var argument in context.ActionArguments.Where(a => requiredParameters.Contains(a.Key, StringComparer.Ordinal)))
{
if (argument.Value == null)
{
context.ModelState.AddModelError(argument.Key, $"The argument '{argument.Key}' cannot be null.");
}
}
if (!context.ModelState.IsValid)
{
var errors = context.ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage);
context.Result = new BadRequestObjectResult(errors);
return;
}
base.OnActionExecuting(context);
}
}
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class RequiredModelAttribute : Attribute
{
}
services.AddMvc(options =>
{
options.Filters.Add(typeof(CheckRequiredModelAttribute));
});
public async Task<IActionResult> CreateAsync([FromBody][RequiredModel]RequestModel request, CancellationToken cancellationToken)
{
//...
}
回答by XDS
The accepted solution takes it upon itself to report back any errors. A more appropriate approach for MVC5 is to let the controller handle (via model validation) the reporting of any errors, aka something like this:
已接受的解决方案会自行报告任何错误。MVC5 更合适的方法是让控制器处理(通过模型验证)任何错误的报告,也就是这样的:
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Http.ModelBinding;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public sealed class ValidateParametersAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext context)
{
var descriptor = context.ActionDescriptor;
if (descriptor != null)
{
var modelState = context.ModelState;
foreach (var parameterDescriptor in descriptor.GetParameters())
{
EvaluateValidationAttributes(
suppliedValue: context.ActionArguments[parameterDescriptor.ParameterName],
modelState: modelState,
parameterDescriptor: parameterDescriptor
);
}
}
base.OnActionExecuting(context);
}
static private void EvaluateValidationAttributes(HttpParameterDescriptor parameterDescriptor, object suppliedValue, ModelStateDictionary modelState)
{
var parameterName = parameterDescriptor.ParameterName;
parameterDescriptor
.GetCustomAttributes<object>()
.OfType<ValidationAttribute>()
.Where(x => !x.IsValid(suppliedValue))
.ForEach(x => modelState.AddModelError(parameterName, x.FormatErrorMessage(parameterName)));
}
}
You may then plug it in universally via WebApiConfig.cs:
然后你可以通过 WebApiConfig.cs 通用地插入它:
config.Filters.Add(new ValidateParametersAttribute());
回答by Jaydeep Shil
we can use the BindRequired
, which is from Microsoft.AspNetCore.Mvc.ModelBinding
namespace.
我们可以使用BindRequired
来自Microsoft.AspNetCore.Mvc.ModelBinding
命名空间的 。
public async Task<ActionResult<IEnumerable<Numbers>>> GetAll([BindRequired, FromQuery]string[] numbers)
{
var result = await _service.GetAllDetails(numbers);
return Ok(result);
}
after that your swagger will look like below.
之后你的招摇将如下所示。