.net core 从 ActionFilterAttribute 获取Request.Body 的正确方式

由于 ModelBinding在动作过滤器之前运行,直接使用 context.ActionArguments["parameter"]  获取模型对象

This article shows how to use an ActionFilter to validate the model from a HTTP POST request in an ASP.NET Core MVC application.

Code: https://github.com/damienbod/AngularAutoSaveCommands

2019-07-31: Updated to ASP.NET Core 3.0 Preview 7, Updated to Angular 8.1.3
2019-02-16: Updated to Angular 7.2.4, ASP.NET Core 2.2 nuget packages
2018-11-22: Updated to Angular 7.1.0, nuget packages
2018-09-28: Updated to ASP.NET Core 2.1.4 and Angular 6.1.9
2018-06-16: Updated to ASP.NET Core 2.1 and Angular 6.0.5
2018-02-11: Updated to ASP.NET Core All 2.0.5 and Angular 5.2.4
2017-08-19: Updated to ASP.NET Core 2.0 and Angular 4.3.5
2017.02.03: Updated to Angular 2.4.5 and webpack 2.2.1, VS2017 RC3, msbuild3
2016.12.23: Updated to Visual Studio 2017 and ASP.NET Core 1.1

Other articles in this series:

  1. Implementing UNDO, REDO in ASP.NET Core
  2. Angular Auto Save, Undo and Redo
  3. ASP.NET Core Action Arguments Validation using an ActionFilter

In an ASP.NET Core MVC application, custom validation logic can be implemented in an ActionFilter. Because the ActionFilter is processed after the model binding in the action execution, the model and action parameters can be used in an ActionFilter without having to read from the Request Body, or the URL.

The model can be accessed using the context.ActionArguments dictionary. The key for the property has to match the parameter name in the MVC Controller action method. Ryan Nowak also explained in this issue, that the context.ActionDescriptor.Parameters can also be used to access the request payload data.

If the model is invalid, the context status code is set to 400 (bad request) and the reason is added to the context result using a ContentResult object. The request is then no longer processed but short circuited using the terminology from the ASP.NET Core documentation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System;
using System.IO;
using System.Text;
using AngularAutoSaveCommands.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
 
namespace AngularAutoSaveCommands.ActionFilters
{
     public class ValidateCommandDtoFilter : ActionFilterAttribute
     {
         private readonly ILogger _logger;
 
         public ValidateCommandDtoFilter(ILoggerFactory loggerFactory)
         {
             _logger = loggerFactory.CreateLogger( "ValidatePayloadTypeFilter" );
         }
 
         public override void OnActionExecuting(ActionExecutingContext context)
         {
             var commandDto = context.ActionArguments[ "commandDto" ] as CommandDto;
             if (commandDto == null )
             {
                 context.HttpContext.Response.StatusCode = 400;
                 context.Result = new ContentResult()
                 {
                     Content = "The body is not a CommandDto type"
                 };
                 return ;
             }
 
             _logger.LogDebug( "validating CommandType" );
             if (!CommandTypes.AllowedTypes.Contains(commandDto.CommandType))
             {
                 context.HttpContext.Response.StatusCode = 400;
                 context.Result = new ContentResult()
                 {
                     Content = "CommandTypes not allowed"
                 };
                 return ;
             }
 
             _logger.LogDebug( "validating PayloadType" );
             if (!PayloadTypes.AllowedTypes.Contains(commandDto.PayloadType))
             {
                 context.HttpContext.Response.StatusCode = 400;
                 context.Result = new ContentResult()
                 {
                     Content = "PayloadType not allowed"
                 };
                 return ;
             }
 
             base .OnActionExecuting(context);
         }
     }
}

The ActionFilter is added to the services in the Startup class. This is not needed if the ActionFilter is used directly in the MVC Controller.

1
services.AddScoped<ValidateCommandDtoFilter>();

The filter can then be used in the MVC Controller using the ServiceFilter attribute. If the commandDto model is invalid, a BadRequest response is returned without processing the business in the action method.

1
2
3
4
5
6
7
8
[ServiceFilter( typeof (ValidateCommandDtoFilter))]
[HttpPost]
[Route( "Execute" )]
public IActionResult Post([FromBody]CommandDto commandDto)
{
     _commandHandler.Execute(commandDto);
     return Ok(commandDto);
}

Links

https://docs.asp.net/en/latest/mvc/controllers/filters.html

https://github.com/aspnet/Mvc/issues/5260#issuecomment-245936046

https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Abstractions/Filters/ActionExecutingContext.cs

猜你喜欢

转载自www.cnblogs.com/mschen/p/12052693.html