Rez*_*adi 30 c# asp.net asp.net-mvc asp.net-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
}
// ..
}
Run Code Online (Sandbox Code Playgroud)
另一方面,我在我的动作参数类之前放置了FromBody属性以利用它的好处.
[Log]
public class SomethingController
{
public HttpResponseMessage Foo([FromBody] myModel)
{
// something
}
}
Run Code Online (Sandbox Code Playgroud)
问题是ActionExecuting或ActionExecuted中的内容始终为空.
我认为这是因为FromBody在我的Log属性之前运行,而不像它们在代码中的顺序.我再次认为是因为根据动作参数(路径处理)找到了请求的最佳动作/控制器匹配.之后我的请求正文被清除,因为请求正文在WebApi中是非缓冲的.
我想知道是否有任何方法可以更改FromBody属性和我的Log属性的运行时顺序?或其他解决问题的方法!我应该提一下,我不想删除FromBody并使用HttpRequestMessage而不是我的模型或类似的东西.
Kha*_* TO 30
请求主体是不可重绕的流; 它只能读一次.格式化程序已经读取了流并填充了模型.我们无法在动作过滤器中再次读取流.
你可以尝试:
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"];
}
}
Run Code Online (Sandbox Code Playgroud)
实际上,ActionArguments只是一个字典,如果我们需要避免使用硬编码的参数name("myModel"),我们可以循环它.当我们创建一个通用的动作过滤器,需要为一些特定的需求处理一类类似的对象时,我们可以让我们的模型实现一个接口=>知道哪个参数是我们需要处理的模型,我们可以调用这些方法界面.
示例代码:
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
Any*_*toe 15
这种方法对我有用:
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());
}
Run Code Online (Sandbox Code Playgroud)
为我返回了我的动作参数对象的json表示,触发了日志记录或异常情况.
在这里找到接受的答案
| 归档时间: |
|
| 查看次数: |
16007 次 |
| 最近记录: |