ModelBinder的Request.Content.ReadAsStringAsync性能 [英] ModelBinder Request.Content.ReadAsStringAsync performance

查看:1347
本文介绍了ModelBinder的Request.Content.ReadAsStringAsync性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的模型绑定器,其中,当我加载测试我的应用程序,并运行在蚂蚁探查,识别读取Request.Content作为字符串作为热点:

I have a custom ModelBinder, which, when I load test my app, and run Ants profiler on, identified reading the Request.Content as string as a hotspot:

 public class QueryModelBinder : IModelBinder
    {
        public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            var body = actionContext.Request.Content.ReadAsStringAsync().Result;

是否有这样做的更有效的方法?
还是我读蚂蚁探查是否有误?

Is there a more efficient way of doing this? Or am I reading the ANTS profiler incorrectly?

推荐答案

多大内容?请注意,您可能会看到大量的时间,因为你是在调用此同步网络呼叫,而不是异步。

How big is the content? Note that you might be seeing a lot of time because you are calling this network call in sync rather than async.

您可以潜在地读取字符串早些时候异步和请求财产藏匿了。

You can potentially read the string earlier async and stash it in the request property.

另外,您可以编写一个格式代替,然后用装饰[FromBody]您的参数。

Alternatively you can write a formatter instead, and then decorate your parameter with [FromBody].

这里建议的方法是使用一个FromBody和一格式化器,因为它自然与的WebAPI架构符合:

The recommended approach here is to use a FromBody and a formatter, since it naturally fits with the WebAPI architecture:

有关,你会写一个媒体类型格式:

For that you would write a media type formatter:

public class StringFormatter : MediaTypeFormatter
{
    public StringFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/mystring"));
    }

    public override bool CanReadType(Type type)
    {
        return (type == typeof (string));
    }

    public override bool CanWriteType(Type type)
    {
        return false;
    }

    public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger,
        CancellationToken cancellationToken)
    {
        if (!CanReadType(type))
        {
            throw new InvalidOperationException();
        }

        return await content.ReadAsStringAsync();
    }
}

webapiconfig.cs

config.Formatters.Add(new StringFormatter());

和一个动作消耗

public string Get([FromBody]string myString)
{
    return myString;
}

的其它设计(不作为推荐的,因为在过滤器和粘合剂之间的耦合):

The other design (not as recommended because of coupling between the filter and the binder):

实现一个模型绑定(这是超级天真):

Implement a model binder (this is super Naive):

public class MyStringModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        // this is a Naive comparison of media type
        if (actionContext.Request.Content.Headers.ContentType.MediaType == "application/mystring")
        {
            bindingContext.Model = actionContext.Request.Properties["MyString"] as string;
            return true;
        }

        return false;
    }
}

添加authroization过滤器(他们冲在最前面modelbinding的),你可以访问异步操作。这也适用于委托处理程序:

Add an authroization filter (they run ahead of modelbinding), to you can async access the action. This also works on a delegating handler:

public class MyStringFilter : AuthorizationFilterAttribute
{
    public override async Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        if (actionContext.Request.Content.Headers.ContentType.MediaType == "application/mystring")
        {
            var myString = await actionContext.Request.Content.ReadAsStringAsync();
            actionContext.Request.Properties.Add("MyString", myString);
        }
    }
}

注册它WebApi.Config或将其应用到控制器:

Register it in WebApi.Config or apply it to the controller:

WebApiConfig.cs

config.Filters.Add(new MyStringFilter());

Values​​Controller.cs

[MyStringFilter] // this is optional, you can register it globally as well
public class ValuesController : ApiController
{
    // specifying the type here is optional, but I'm using it because it avoids having to specify the prefix
    public string Get([ModelBinder(typeof(MyStringModelBinder))]string myString = null)
    {
        return myString;
    }
}

(感谢@Kiran Challa为找过我的肩膀,并建议授权过滤器)

(Thanks for @Kiran Challa for looking over my shoulder, and suggesting the Authorization filter)

编辑:有一件事总是有比较大的字符串(大于消耗更多85KB左右如此40K字)记得可以进入大对象堆,这将造成的对您的网站的性能造成严重破坏。如果你的东西,这是很常见,打破输入成类似字符串的字符串生成器/数组或不连续的内存类似的东西。请参见为什么大对象堆和何必计较?

One thing to always remember with relatively large strings (consuming more than 85KB so about 40K Chars) can go into the Large Object heap, which will wreak havoc on your site performance. If you thing this is common enough, break the input down into something like a string builder/array of strings or something similar without contiguous memory. See Why Large Object Heap and why do we care?

这篇关于ModelBinder的Request.Content.ReadAsStringAsync性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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