【问题标题】:ModelBinder Request.Content.ReadAsStringAsync performanceModelBinder Request.Content.ReadAsStringAsync 性能
【发布时间】:2014-05-12 21:01:49
【问题描述】:

我有一个自定义 ModelBinder,当我加载测试我的应用程序并在其上运行 Ants 分析器时,将 Request.Content 识别为字符串作为热点:

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

有没有更有效的方法来做到这一点? 还是我错误地阅读了 ANTS 分析器?

【问题讨论】:

    标签: asp.net-web-api performance-testing ants


    【解决方案1】:

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

    您可以提前异步读取字符串并将其存储在请求属性中。

    您也可以编写一个格式化程序,然后用 [FromBody] 装饰您的参数。

    这里推荐的方法是使用 FromBody 和格式化程序,因为它自然适合 WebAPI 架构:

    为此,您将编写一个媒体类型格式化程序:

    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;
    }
    

    另一种设计(不推荐,因为过滤器和绑定器之间的耦合):

    实现一个模型绑定器(这太天真了):

    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;
        }
    }
    

    添加一个授权过滤器(它们在模型绑定之前运行),您可以异步访问该操作。这也适用于委托处理程序:

    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 中注册或应用到控制器:

    WebApiConfig.cs

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

    ValuesController.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 看着我,并建议使用授权过滤器)

    编辑:要始终记住相对较大的字符串(消耗超过 85KB,因此大约 40K 个字符)可能会进入大对象堆,这将对您的站点性能造成严重破坏。如果您认为这很常见,请将输入分解为字符串构建器/字符串数组或类似的东西,而无需连续内存。见Why Large Object Heap and why do we care?

    【讨论】:

    • 例如在过滤器中,因为过滤器是异步的。
    • 不确定我是否在关注,请您提供示例吗?
    • 添加了两个示例。请注意,您需要授权过滤器而不是操作过滤器,因为操作过滤器在模型绑定之后运行。
    猜你喜欢
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多