作者:早安丶晚安丶英语连_691 | 来源:互联网 | 2022-12-04 16:33
1> itminus..:
ModelState
仅在模型绑定之后可用。只需将ModelState
自动过滤器与动作过滤器一起存储,即可在中间件中使用它。
首先,添加一个动作过滤器以将ModelState设置为功能:
public class ModelStateFeatureFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var state = context.ModelState;
context.HttpContext.Features.Set(new ModelStateFeature(state));
await next();
}
}
这ModelStateFeature
是一个持有ModelState的虚拟类:
public class ModelStateFeature
{
public ModelStateDictionary ModelState { get; set; }
public ModelStateFeature(ModelStateDictionary state)
{
this.ModelState= state;
}
}
为了使动作过滤器自动发生,我们需要配置MVC
services.AddMvc(opts=> {
opts.Filters.Add(typeof(ModelStateFeatureFilter));
})
现在我们可以ModelState
在您的中间件中使用,如下所示:
public class ResponseFormatterMiddleware
{
// ...
public async Task Invoke(HttpContext context)
{
var originBody = context.Response.Body;
using (var respOnseBody= new MemoryStream())
{
context.Response.Body = responseBody;
// Process inner middlewares and return result.
await _next(context);
var ModelState = context.Features.Get()?.ModelState;
if (ModelState==null) {
return ; // if you need pass by , just set another flag in feature .
}
responseBody.Seek(0, SeekOrigin.Begin);
using (var streamReader = new StreamReader(responseBody))
{
// Get action result come from mvc pipeline
var strActiOnResult= streamReader.ReadToEnd();
var objActiOnResult= JsonConvert.DeserializeObject(strActionResult);
context.Response.Body = originBody;
// Create uniuqe shape for all responses.
var respOnseModel= new GenericResponseModel(objActionResult, (HttpStatusCode)context.Response.StatusCode, context.Items?["Message"]?.ToString());
// => Get error message
if (!ModelState.IsValid)
{
var errors= ModelState.Values.Where(v => v.Errors.Count > 0)
.SelectMany(v=>v.Errors)
.Select(v=>v.ErrorMessage)
.ToList();
responseModel.Result = null;
responseModel.Message = String.Join(" ; ",errors) ;
}
// Set all response code to 200 and keep actual status code inside wrapped object.
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.COntentType= "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(responseModel));
}
}
}
}
让我们用一个简单的模型进行测试
public class MyModel {
[MinLength(6)]
[MaxLength(12)]
public string Name { get; set; }
public int Age { get; set; }
}
和一个简单的控制器:
public class HomeController : Controller
{
public IActionResult Index(string name)
{
return new JsonResult(new {
Name=name
});
}
[HttpPost]
public IActionResult Person([Bind("Age,Name")]MyModel model)
{
return new JsonResult(model);
}
}
如果我们发送带有有效负载的请求:
POST https://localhost:44386/Home/Person HTTP/1.1
content-type: application/x-www-form-urlencoded
name=helloo&age=20
响应将是:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json
Server: Kestrel
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcOVw5LTE4XEFwcFxBcHBcQXBwXEhvbWVcUGVyc29u?=
X-Powered-By: ASP.NET
{
"result": {
"name": "helloo",
"age": 20
},
"statusCode": 200,
"message": null,
"version": "V1.0"
}
如果我们发送的请求的模型无效:
POST https://localhost:44386/Home/Person HTTP/1.1
content-type: application/x-www-form-urlencoded
name=hello&age=i20
响应将是
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json
Server: Kestrel
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcOVw5LTE4XEFwcFxBcHBcQXBwXEhvbWVcUGVyc29u?=
X-Powered-By: ASP.NET
{
"result": null,
"statusCode": 200,
"message": "The value 'i20' is not valid for Age. ; The field Name must be a string or array type with a minimum length of '6'.",
"version": "V1.0"
}