ASP.NET的Web API记录入站请求内容 [英] ASP.NET Web API Logging Inbound Request Content

查看:154
本文介绍了ASP.NET的Web API记录入站请求内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想注销的Web API请求内容 - 即JSON字符串。我实现了一个ITraceWriter类(<一个href=\"http://www.asp.net/web-api/overview/testing-and-debugging/tracing-in-aspnet-web-api\">example)并配置它,使网页API在管道调用它。但是,如果我读request.Content或复制到到流读它不适用于产生一个空模型的方法。<一href=\"http://stackoverflow.com/questions/13021089/why-is-the-body-of-a-web-api-request-read-once\">This帖子有关问题的会谈一点点。任何人都有经验注销入站Web API请求的内容,知道最好的方法是什么呢?

感谢

更新

我创建了一个简单的示例Web API项目,以排除任何东西在我的项目,我仍然看到,该模型也会因为日志为空。我要做的只是通过张贴Fidder酒店试连续几次,看看我的模型进来空。有了断点,它可能工作这就是为什么我认为有一个同步/计时问题。关于如何得到这个任何想法来工作?

标题:

 的User-Agent:提琴手
主机:本地主机:56824
内容类型:应用程序/ JSON
内容长度:22

正文:

  {
A:1,B:测试
}

这里的code:

控制器:

 公共类Values​​Controller:ApiController
{
    [HttpPost]
    公共无效后(Values​​Model模型)
    {
        如果(型号== NULL)
        {
            的Debug.WriteLine(模式为空!);
        }
        其他
        {
            的Debug.WriteLine(模式是不为空!);
        }
    }
}

型号:

 公共类Values​​Model
{
    公众诠释A {搞定;组; }
    公共字符串B {搞定;组; }
}

日志:

 公共类APITraceLogger:DelegatingHandler
    {
        保护覆盖System.Threading.Tasks.Task&LT; Htt的presponseMessage&GT; SendAsync(HTT prequestMessage要求,System.Threading.CancellationToken的CancellationToken)
        {
            如果(request.Content!= NULL)
            {
                //这可能会导致模型为空
                。request.Content.ReadAsStringAsync()ContinueWith(S =&GT;
                {
                    字符串requestText = s.Result;
                    的Debug.WriteLine(requestText);
                });                //所以可以这样
                //request.Content.ReadAsByteArrayAsync()
                // .ContinueWith((任务)= GT;
                // {
                //字符串requestText = System.Text.UTF8Encoding.UTF8.GetString(task.Result);
                //的Debug.WriteLine(requestText);
                //});
            }
            //执行的请求,这不会阻止
            VAR响应= base.SendAsync(请求的CancellationToken);            // 去做:
            //一旦响应异步处理,登录响应数据
            //到数据库
            返回响应;
        }
    }

在WebApiConfig类布线起来记录:

  config.MessageHandlers.Add(新APITraceLogger());

更新乙

现在看来似乎如果我改变记录以下code添加的await,异步和返回结果现在工作。看起来似乎我不是在异步code或一个真正的计时问题什么的理解。

 公共类APITraceLogger:DelegatingHandler
{
    保护异步覆盖System.Threading.Tasks.Task其中p型Htt presponseMessage&GT; SendAsync(HTT prequestMessage要求,System.Threading.CancellationToken的CancellationToken)
    {
        如果(request.Content!= NULL)
        {            //这似乎工作 - 是它,因为它是同步的?这是一个潜在的问题?
            VAR requestText =等待request.Content.ReadAsStringAsync();
            的Debug.WriteLine(requestText);
        }
        //执行的请求,这不会阻止
        VAR响应= base.SendAsync(请求的CancellationToken);        // 去做:
        //一旦响应异步处理,登录响应数据
        //到数据库
        返回response.Result;
    }
}


解决方案

由于菲利普在该职位ReadAsStringAsync或ReadAsByteArrayAsync方法提到内部缓存请求的内容。这意味着,即使你传入的请求的流类型是一个非缓冲流,你可以放心地做一个ReadAsStringAsync / ReadAsByteArrayAsync在例如消息处理程序,并且也期望模型绑定做工精细。

在默认情况下,请求的流在两个虚拟主机提供商和selfhost案件缓冲。但是,如果你想检查是否使用ReadAsStringAsync / ReadAsByteArrayAsync和型号招投标工作正常,即使在非缓冲模式下,您可以执行以下操作来强制非缓冲模式:

 公共类CustomBufferPolicySelector:WebHostBufferPolicySelector
{
    公众覆盖布尔UseBufferedInputStream(对象hostContext)
    {
        //注意:默认情况下,请求流始终处于缓冲模式。
        //返回base.UseBufferedInputStream(hostContext);        返回false;
    }
}config.Services.Replace(typeof运算(IHostBufferPolicySelector),新CustomBufferPolicySelector());

仅供参考......上述政策选择仅适用于目前的虚拟主机。如果你想做好SelfHost类似的试验,然后执行以下操作:

  //注意:默认情况下,传输模式是TransferMode.Buffered
config.TransferMode = System.ServiceModel.TransferMode.StreamedRequest;

完成上述职务的更新A:

您可以修改您的处理程序如下图所示:

 公共类LoggingHandler:DelegatingHandler
{
    保护覆盖异步任务&LT; Htt的presponseMessage&GT; SendAsync(HTT prequestMessage请求的CancellationToken的CancellationToken)
    {
        如果(request.Content!= NULL)
        {
            字符串requestContent =等待request.Content.ReadAsStringAsync();
        }        HTT presponseMessage响应=等待base.SendAsync(请求的CancellationToken);        如果(response.Content!= NULL)
        {
            字符串responseContent =等待response.Content.ReadAsStringAsync();
        }        返回响应;
    }
}

I’m trying to log out Web API Request Content – i.e. the json string. I implemented an ITraceWriter class (example) and configured it so that Web API calls it in the pipeline. But if I read the request.Content or copy into to a stream to read it is not available for the method resulting in a null model. This post talks about that issue a little. Anyone have experience logging out inbound Web API request content and know what the best approach is?

Thanks

Update A

I created a simple sample Web API project to rule out anything in my project and I still see that the model will be null because of logging. I simply test a few times in a row by posting via Fidder and see my model comes in null. With breakpoints in place, it might work which is why I think there is a sync/timing issue. Any thoughts on how to get this to work?

Header:

User-Agent: Fiddler
Host: localhost:56824
Content-Type: application/json
Content-Length: 22

Body:

{
"A":1,"B":"test"
}

Here's the code:

Controller:

public class ValuesController : ApiController
{
    [HttpPost]
    public void Post(ValuesModel model)
    {
        if (model == null)
        {
            Debug.WriteLine("model was null!");
        }
        else
        {
            Debug.WriteLine("model was NOT null!");
        }
    }
}

Model:

public class ValuesModel
{
    public int A { get; set; }
    public string B { get; set; }
}

Logger:

public class APITraceLogger : DelegatingHandler
    {
        protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            if (request.Content != null)
            {
                // This can cause model to be null
                request.Content.ReadAsStringAsync().ContinueWith(s =>
                {
                    string requestText = s.Result;
                    Debug.WriteLine(requestText);
                });

                // and so can this
                //request.Content.ReadAsByteArrayAsync()
                //    .ContinueWith((task) =>
                //    {
                //        string requestText = System.Text.UTF8Encoding.UTF8.GetString(task.Result);
                //        Debug.WriteLine(requestText);
                //    });
            }
            // Execute the request, this does not block
            var response = base.SendAsync(request, cancellationToken);

            // TODO:
            // Once the response is processed asynchronously, log the response data
            // to the database


            return response;
        }


    }

Wiring up logger in WebApiConfig class:

config.MessageHandlers.Add(new APITraceLogger());

Update B

It seems like it is now working if I change the logger to the following code adding the await, async and returning the result. Seems like something I'm not understanding in the async code or truly a timing issue or something.

public class APITraceLogger : DelegatingHandler
{
    protected async override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        if (request.Content != null)
        {

            // This does seem to work - is it because it is synchronous?  Is this a potential problem?
            var requestText = await request.Content.ReadAsStringAsync();
            Debug.WriteLine(requestText);
        }
        // Execute the request, this does not block
        var response = base.SendAsync(request, cancellationToken);

        // TODO:
        // Once the response is processed asynchronously, log the response data
        // to the database


        return response.Result;
    }


}

解决方案

As Filip mentions in that post ReadAsStringAsync or ReadAsByteArrayAsync methods buffer the request content internally. This means that even if your incoming request's stream type is a non-buffered stream, you could safely do a ReadAsStringAsync/ReadAsByteArrayAsync at a message handler for example, and also expect the model binding to work fine.

By default, a request's stream is buffered in both webhost and selfhost cases. But if you would like to check if using ReadAsStringAsync/ReadAsByteArrayAsync and model biding works fine even in non-buffered mode, you can do the following to force non-buffered mode:

public class CustomBufferPolicySelector : WebHostBufferPolicySelector
{
    public override bool UseBufferedInputStream(object hostContext)
    {
        //NOTE: by default, the request stream is always in buffered mode.
        //return base.UseBufferedInputStream(hostContext);

        return false;
    }
}

config.Services.Replace(typeof(IHostBufferPolicySelector), new CustomBufferPolicySelector());

Just FYI...the above policy selector works only for Web Host currently. If you would like to do a similar test in SelfHost, then do the following:

//NOTE: by default, the transfer mode is TransferMode.Buffered
config.TransferMode = System.ServiceModel.TransferMode.StreamedRequest;

After Update B of the post above:

You could modify your handler like below:

public class LoggingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Content != null)
        {
            string requestContent = await request.Content.ReadAsStringAsync();
        }

        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

        if (response.Content != null)
        {
            string responseContent = await response.Content.ReadAsStringAsync();
        }

        return response;
    }
}

这篇关于ASP.NET的Web API记录入站请求内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆