动作filter中的Web Api请求内容为空

我有一个名为Log的属性,它试图将请求和响应的内容记录到文本文件中。 我把它放在我的控制器上以涵盖所有动作。 在LogAttribute中,我正在读取内容为字符串(ReadAsStringAsync),所以我不会丢失请求体。

public class LogAttribute : ActionFilterAttribute { // .. public override void OnActionExecuting(HttpActionContext actionContext) { // stuff goes here var content = actionContext.Request.Content.ReadAsStringAsync().Result; // content is always empty because request body is cleared } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { // other stuff goes here var content = actionContext.Request.Content.ReadAsStringAsync().Result; // content is always empty because request body is cleared } // .. } 

另一方面,我在我的动作参数类之前放置了FromBody属性以利用它的好处。

 [Log] public class SomethingController { public HttpResponseMessage Foo([FromBody] myModel) { // something } } 

问题是ActionExecuting或ActionExecuted中的内容始终为空。

我认为这是因为FromBody在我的Log属性之前运行,而不像它们在代码中的顺序。 我再次认为是因为根据动作参数(路径处理)找到了请求的最佳动作/控制器匹配。 之后我的请求正文被清除,因为请求正文在WebApi中是非缓冲的。

我想知道是否有任何方法可以更改FromBody属性和我的Log属性的运行时顺序? 或其他解决问题的方法! 我应该提一下,我不想删除FromBody并使用HttpRequestMessage而不是我的模型或类似的东西。

请求主体是不可重绕的流; 它只能读一次。 格式化程序已经读取了流并填充了模型。 我们无法在动作filter中再次读取流。

你可以尝试:

 public class LogAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { var myModel = actionContext.ActionArguments["myModel"]; } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { var myModel = actionContext.ActionArguments["myModel"]; } } 

实际上, ActionArguments只是一个字典,如果我们需要避免硬编码的参数名称( "myModel" ),我们可以循环它。 当我们创建一个通用的动作filter,需要处理一类类似的对象以满足某些特定的需求时,我们可以让我们的模型实现一个接口=>知道哪个参数是我们需要处理的模型,我们可以调用这些方法界面。

示例代码:

 public class LogAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { foreach(var argument in actionContext.ActionArguments.Values.Where(v => v is ILogable))) { ILogable model = argument as ILogable;//assume that only objects implementing this interface are logable //do something with it. Maybe call model.log } } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { foreach(var argument in actionContext.ActionArguments.Values.Where(v => v is ILogable))) { ILogable model = argument as ILogable;//assume that only objects implementing this interface are logable //do something with it. Maybe call model.log } } } 

这种方法对我有用:

 using (var stream = new MemoryStream()) { var context = (HttpContextBase)Request.Properties["MS_HttpContext"]; context.Request.InputStream.Seek(0, SeekOrigin.Begin); context.Request.InputStream.CopyTo(stream); string requestBody = Encoding.UTF8.GetString(stream.ToArray()); } 

为我返回了我的动作参数对象的json表示,触发了日志记录或exception情况。

在这里找到接受的答案