2017-08-04 140 views
3

樣品我請求有什麼辦法可以在.NET Core FilterAttribute中獲取請求體?

http://localhost:8065/api/note 
POST 
content-type:application/json 
request body: { "id" : "1234", "title" : "test", "status" : "draft"} 

和反應應該是

{ "msg" : "ok", "code" : 1} 

行動

public async Task<IActionResult> Post([FromBody]NoteModel model) 

爲了讓每一個請求自動登錄,我創建屬性做這個工作。屬性是這樣的:(從Microsoft Docs

public class SampleActionFilterAttribute : TypeFilterAttribute 
{ 
    public SampleActionFilterAttribute():base(typeof(SampleActionFilterImpl)) 
    { 
    } 

    private class SampleActionFilterImpl : IActionFilter 
    { 
     private readonly ILogger _logger; 
     public SampleActionFilterImpl(ILoggerFactory loggerFactory) 
     { 
      _logger = loggerFactory.CreateLogger<SampleActionFilterAttribute>(); 
     } 

     public void OnActionExecuting(ActionExecutingContext context) 
     { 

     } 

     public void OnActionExecuted(ActionExecutedContext context) 
     { 
      _logger.LogDebug("[path]" + context.HttpContext.Request.Path); 
      _logger.LogDebug("[method]" + context.HttpContext.Request.Method); 
      _logger.LogDebug("[body]"); //log request body, expectation: { "id" : "1234", "title" : "test", "status" : "draft"} 
      _logger.LogDebug("[statuscode]" + context.HttpContext.Response.StatusCode); 
      _logger.LogDebug("[response]"); //log response 
     } 
    } 
} 

我嘗試使用的StreamReader獲取請求主體只能得到空字符串。

StreamReader reader = new StreamReader(context.HttpContext.Request.Body); 
string text = reader.ReadToEnd(); 

這是因爲身體是由[fromBody]從控制器讀取的,所以流不能被讀取兩次?如果是這樣,我應該如何在OnActionExecuted方法中獲得請求體和響應?


更新:

我剛纔複製設置的代碼到我的項目,而不是工作。這裏是調試GIF enter image description here

+0

另外,它已在https://stackoverflow.com/a/43404745/4074527得到很好的回答。 –

回答

4

因此這種 「Best way to log/read request body in a middleware」 線程,下面應該工作:

// using Microsoft.AspNetCore.Http.Internal; 

public class SampleActionFilterAttribute : TypeFilterAttribute 
{ 
    ... 

    public void OnActionExecuting(ActionExecutedContext context) 
    { 
     // read body before MVC action execution 
     string bodyData = ReadBodyAsString(context.HttpContext.Request); 
    } 

    private string ReadBodyAsString(HttpRequest request) 
    { 
     var initialBody = request.Body; // Workaround 

     try 
     { 
      request.EnableRewind(); 

      using (StreamReader reader = new StreamReader(request.Body)) 
      { 
       string text = reader.ReadToEnd(); 
       return text; 
      } 
     } 
     finally 
     { 
      // Workaround so MVC action will be able to read body as well 
      request.Body = initialBody; 
     } 

     return string.Empty; 
    } 
} 

Read request body twice描述同樣類似的方法,使張貼


更新:以上在ReadBodyAsString中的方法將在中間件中使用,而不是在操作過濾器中使用。不同的是,當動作過濾器正在調用(即使對於OnActionExecuting),正文流已經被讀取並且[FromBody] model已經被填充。

好的nesw是,所以它有可能通過使用context.ActionArguments["<model_name>"]直接在操作過濾器中獲取模型。你的情況:

public void OnActionExecuted(ActionExecutedContext context) 
{ 
    var model = context.ActionArguments["model"] as NoteModel; 
} 
+0

剛剛嘗試過這種污染。 OnActionExecuting'中的'ReadBodyAsString'方法仍然會注意到,請參閱我粘貼的gif。('[fromBody]模型'有價值)。 – wtf512

+0

@ wtf512更新了答案。您可以直接使用'context.ActionArguments'來獲取模型的動作過濾器,或者如果您想使用原始請求主體進行操作,請轉到中間件方法進行日誌記錄。 – Set

+0

'context.ActionArguments'解決了我的問題。我只是循環ActionArgumetns中的每個項目,並使用newtonsoft.json序列化爲字符串和日誌。 – wtf512

0

如果你在你的控制器使用IActionResult和你想要的.NET對象,你可以寫這樣的過濾器:

public class SampleFilter : IActionFilter 
{ 
    public void OnActionExecuted(ActionExecutedContext context) 
    { 
     if (context.Result is ObjectResult) 
     { 
      var objResult = (ObjectResult)context.Result; 
     } 
    } 

    public void OnActionExecuting(ActionExecutingContext context) 
    { 

    } 
} 

通過它擊中OnActionExecuted點, ObjectResult任務已經完成,所以你可以提取值。您也可以使用objResult.StatusCode獲取StatusCode。

在控制器中,返回OK(...)實際上創建了一個OkObjectResult等

如果你特別想要的serialzied結果,然後設置的回答是更有效的。

相關問題