是否可以对查询参数使用 Web API 模型验证?
Is it possible to use Web API model validation on query parameters?
我目前正在尝试编写一个 Web API 应用程序,其中我想验证的参数之一是查询参数(也就是说,我希望以 [=13] 的形式传递它=]):
[HttpGet]
public async Task<HttpResponseMessage> GetItems(
int offset = 0,
int limit = 100)
{
if (!ModelState.IsValid)
{
// Handle error
}
// Handle request
}
特别是,我想确保"offset"大于0,因为负数会导致数据库抛出异常。
我直接采用了在其上附加 ValidationAttribute
的合乎逻辑的方法:
[HttpGet]
public async Task<HttpResponseMessage> GetItems(
[Range(0, int.MaxValue)] int offset = 0,
int limit = 100)
{
if (!ModelState.IsValid)
{
// Handle error
}
// Handle request
}
这根本不会导致任何错误。
在对 ASP.NET 进行了大量痛苦的调试之后,在我看来这可能根本不可能。特别是,因为 offset
参数是方法参数而不是字段,所以 ModelMetadata
是使用 GetMetadataForType
而不是 GetMetadataForProperty
创建的,这意味着 PropertyName
将是 null
。反过来,这意味着 AssociatedValidatorProvider
调用 GetValidatorsForType
,它使用一个空的属性列表,即使参数上有属性也是如此。
我什至没有找到一种方法来编写自定义 ModelValidatorProvider
来获取该信息,因为这是一个函数参数的信息似乎很久以前就丢失了。一种方法可能是从 ModelMetadata
class 派生并使用自定义 ModelMetadataProvider
但基本上没有任何此代码的文档,因此它是一个废话实际上工作正常,我必须复制所有 DataAnnotationsModelValidatorProvider
逻辑。
有人能证明我错了吗?有人可以告诉我如何对参数进行验证,类似于 BindAttribute
在 MVC 中的工作方式吗?或者是否有另一种方法来绑定查询参数以允许验证正常工作?
您可以使用这 2 个属性创建一个 view 请求模型 class 并在这些属性上应用您的验证属性。
public class Req
{
[Range(1, Int32.MaxValue, ErrorMessage = "Enter number greater than 1 ")]
public int Offset { set; get; }
public int Limit { set; get; }
}
并且在你的方法中,使用这个作为参数
public HttpResponseMessage Post(Req model)
{
if (!ModelState.IsValid)
{
// to do :return something. May be the validation errors?
var errors = new List<string>();
foreach (var modelStateVal in ModelState.Values.Select(d => d.Errors))
{
errors.AddRange(modelStateVal.Select(error => error.ErrorMessage));
}
return Request.CreateResponse(HttpStatusCode.OK, new { Status = "Error",
Errors = errors });
}
// Model validation passed. Use model.Offset and Model.Limit as needed
return Request.CreateResponse(HttpStatusCode.OK);
}
当请求到来时,默认模型绑定器会将请求参数(limit
和 offset
,假设它们是请求的一部分)映射到 Req
class 你将能够调用 ModelState.IsValid
方法。
if (Offset < 1)
ModelState.AddModelError(string.Empty, "Enter number greater than 1");
if (ModelState.IsValid)
{
}
对于 .Net 5.0 并验证 查询参数:
using System.ComponentModel.DataAnnotations;
namespace XXApi.Models
{
public class LoginModel
{
[Required]
public string username { get; set; }
public string password { get; set; }
}
}
namespace XXApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LoginController : ControllerBase
{
[HttpGet]
public ActionResult login([FromQuery] LoginModel model)
{
//.Net automatically validates model from the URL string
//and gets here after validation succeeded
}
}
}
我目前正在尝试编写一个 Web API 应用程序,其中我想验证的参数之一是查询参数(也就是说,我希望以 [=13] 的形式传递它=]):
[HttpGet]
public async Task<HttpResponseMessage> GetItems(
int offset = 0,
int limit = 100)
{
if (!ModelState.IsValid)
{
// Handle error
}
// Handle request
}
特别是,我想确保"offset"大于0,因为负数会导致数据库抛出异常。
我直接采用了在其上附加 ValidationAttribute
的合乎逻辑的方法:
[HttpGet]
public async Task<HttpResponseMessage> GetItems(
[Range(0, int.MaxValue)] int offset = 0,
int limit = 100)
{
if (!ModelState.IsValid)
{
// Handle error
}
// Handle request
}
这根本不会导致任何错误。
在对 ASP.NET 进行了大量痛苦的调试之后,在我看来这可能根本不可能。特别是,因为 offset
参数是方法参数而不是字段,所以 ModelMetadata
是使用 GetMetadataForType
而不是 GetMetadataForProperty
创建的,这意味着 PropertyName
将是 null
。反过来,这意味着 AssociatedValidatorProvider
调用 GetValidatorsForType
,它使用一个空的属性列表,即使参数上有属性也是如此。
我什至没有找到一种方法来编写自定义 ModelValidatorProvider
来获取该信息,因为这是一个函数参数的信息似乎很久以前就丢失了。一种方法可能是从 ModelMetadata
class 派生并使用自定义 ModelMetadataProvider
但基本上没有任何此代码的文档,因此它是一个废话实际上工作正常,我必须复制所有 DataAnnotationsModelValidatorProvider
逻辑。
有人能证明我错了吗?有人可以告诉我如何对参数进行验证,类似于 BindAttribute
在 MVC 中的工作方式吗?或者是否有另一种方法来绑定查询参数以允许验证正常工作?
您可以使用这 2 个属性创建一个 view 请求模型 class 并在这些属性上应用您的验证属性。
public class Req
{
[Range(1, Int32.MaxValue, ErrorMessage = "Enter number greater than 1 ")]
public int Offset { set; get; }
public int Limit { set; get; }
}
并且在你的方法中,使用这个作为参数
public HttpResponseMessage Post(Req model)
{
if (!ModelState.IsValid)
{
// to do :return something. May be the validation errors?
var errors = new List<string>();
foreach (var modelStateVal in ModelState.Values.Select(d => d.Errors))
{
errors.AddRange(modelStateVal.Select(error => error.ErrorMessage));
}
return Request.CreateResponse(HttpStatusCode.OK, new { Status = "Error",
Errors = errors });
}
// Model validation passed. Use model.Offset and Model.Limit as needed
return Request.CreateResponse(HttpStatusCode.OK);
}
当请求到来时,默认模型绑定器会将请求参数(limit
和 offset
,假设它们是请求的一部分)映射到 Req
class 你将能够调用 ModelState.IsValid
方法。
if (Offset < 1)
ModelState.AddModelError(string.Empty, "Enter number greater than 1");
if (ModelState.IsValid)
{
}
对于 .Net 5.0 并验证 查询参数:
using System.ComponentModel.DataAnnotations;
namespace XXApi.Models
{
public class LoginModel
{
[Required]
public string username { get; set; }
public string password { get; set; }
}
}
namespace XXApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LoginController : ControllerBase
{
[HttpGet]
public ActionResult login([FromQuery] LoginModel model)
{
//.Net automatically validates model from the URL string
//and gets here after validation succeeded
}
}
}