首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对HttpContent ReadAsAsync的多次调用

对HttpContent ReadAsAsync的多次调用
EN

Stack Overflow用户
提问于 2014-11-15 04:22:35
回答 4查看 17.1K关注 0票数 33

使用WebAPI2.2,假设我想从HttpContent读取两次,每次都是不同的类型。

代码语言:javascript
复制
await httpContent.LoadIntoBufferAsync(); //necessary to buffer content for multiple reads
var X = await httpContent.ReadAsAsync<T>(); //read as first type
var Y = await httpContent.ReadAsAsync<Dictionary<string, object>>(); //read as second type

当我运行上述代码时,XT的非空实例,而Y是null。如果我切换顺序,Y将是一个非空字典,而X将为null。换句话说,对ReadAsAsync的第二次调用和后续调用将始终返回null,除非使用相同的泛型类型参数调用它们。独立地,对ReadAsAsync的任何调用都按预期工作(即使在不必要地调用LoadIntoBufferAsync时也是如此)。

这对我来说是出乎意料的--似乎我应该能够尽可能多地阅读不同类型的缓冲内容。如果我再加一行:

代码语言:javascript
复制
var Z = await httpContent.ReadAsString();

结果是Z将是一个非空字符串,而不管分配给X, Y, Z的顺序如何。

为什么会发生这种情况,为什么我不能使用具有多种类型的HttpContent读取ReadAsAsync呢?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-11-15 04:58:31

在这个问题上,文档很少,但对于我来说,HttpContent的作用就像一个流,因为您只需读一次就不足为奇了。在.NET中,几乎每一个名字中的“读”方法都是这样操作的。

我不知道为什么要多次读取相同的数据,每次对数据进行不同的解释,除非可能出于调试目的。在我看来,你的榜样是人为的。但是,如果您真的想这样做,您可以尝试ReadAsStreamAsync(),然后您可以直接从Stream读取它,每次您想再次读取它时,都可以将Position属性重置为0,或者ReadAsByteArrayAsync(),给您一个字节数组,您可以随意读取它。

当然,您必须显式地使用格式化程序将其转换为所需的类型。但这不应该是太大的障碍。

票数 15
EN

Stack Overflow用户

发布于 2014-11-15 09:25:11

@彼得是对的。如果您想要一遍又一遍地阅读,您可能希望以流的形式阅读,并在每次读取流时寻求开始。但是,如果你想做什么,你现在做什么,但让第二读工作,你可以寻求开始的流,在第一次阅读后,像这样。

代码语言:javascript
复制
await httpContent.LoadIntoBufferAsync();
var X = await httpContent.ReadAsAsync<T>();

Stream stream = await httpContent.ReadAsStreamAsync();
stream.Seek(0, SeekOrigin.Begin);

var Y = await httpContent.ReadAsAsync<Dictionary<string, object>>();
票数 29
EN

Stack Overflow用户

发布于 2015-01-26 11:06:40

为此,我找到了一个可行的解决方案,但是它需要使用ReadAsync的重载,该重载显式地接收媒体格式化程序列表。它看上去就像一个讨厌的黑客,但它是有效的。

事实上,HttpContent作为一个流在引擎盖下,一旦被格式化程序读取,它就不会被自动重卷。但是有一种方法可以进行手动倒带,这是可以这样做的。

首先,为媒体类型格式化程序创建一个装饰器,如下所示:

代码语言:javascript
复制
public class RewindStreamFormatterDecorator : MediaTypeFormatter
{
    private readonly MediaTypeFormatter formatter;

    public RewindStreamFormatterDecorator(MediaTypeFormatter formatter)
    {
        this.formatter = formatter;

        this.SupportedMediaTypes.Clear();
        foreach(var type in formatter.SupportedMediaTypes)
            this.SupportedMediaTypes.Add(type);

        this.SupportedEncodings.Clear();
        foreach(var encoding in formatter.SupportedEncodings)
            this.SupportedEncodings.Add(encoding);
    }

    public override bool CanReadType(Type type)
    {
        return formatter.CanReadType(type);
    }

    public override Task<object> ReadFromStreamAsync(
        Type type,
        Stream readStream,
        HttpContent content,
        IFormatterLogger formatterLogger,
        CancellationToken cancellationToken)
    {
        var result = formatter.ReadFromStreamAsync
           (type, readStream, content, formatterLogger, cancellationToken);
        readStream.Seek(0, SeekOrigin.Begin);
        return result;
    }

    //There are more overridable methods but none seem to be used by ReadAsAsync
}

其次,将格式化程序列表转换为修饰格式化程序列表:

代码语言:javascript
复制
formatters = formatters.Select(f => new RewindStreamFormatterDecorator(f)).ToArray();

...and现在您可以任意多次调用ReadAsAsync

代码语言:javascript
复制
var X = await httpContent.ReadAsAsync<T>(formatters);
var Y = await httpContent.ReadAsAsync<Dictionary<string, object>>(formatters);

我在自定义模型绑定中使用了这个解决方案,因此我从传递给构造函数的HttpParameterDescriptor实例中获得了格式化程序集合。您可能在执行上下文中的某个地方有一个这样的集合,但如果没有,只需创建一个与ASP.NET相同的默认集合:

代码语言:javascript
复制
formatters = new MediaTypeFormatter[]
{
    new JsonMediaTypeFormatter(),
    new XmlMediaTypeFormatter(),
    new FormUrlEncodedMediaTypeFormatter()
};
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26942514

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档