在Web API中实现MediaTypeFormatter.WriteToStreamAsync的正确方法

时间:2013-07-08 12:12:05

标签: .net asynchronous asp.net-web-api task-parallel-library

我正在实现自己的MediaTypeFormatter,我对我正在做的自定义XML序列化程序的方法WriteToStreamAsync有一些疑问:

public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)

我已经看到很多同步操作的示例,为了返回Task,它们将代码括在Task.Factory.StartNew()中,但是......可以吗?我的意思是,这是否超过了使用Task链接IO操作来提高可伸缩性的目的?

我找到了两种可能的解决方案:

首先,我使用StreamWriter并返回FlushAsync任务。

    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
    {
        XDocument doc = new XDocument();
        doc.Add(SerializeType(type, value));

        var sw = new StreamWriter(writeStream,Encoding.UTF8,4096);
        sw.AutoFlush = false;
        doc.Save(sw);
        return sw.FlushAsync();
    }

我的问题是,之后StreamWriter会发生什么?我想框架会处理writeStream,但是StreamWriter

另一方面,我使用内部内存流,WriteAsync使用writeStream

    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
    {
        XDocument doc = new XDocument();
        doc.Add(SerializeType(type, value));

        Byte[] buffer = null;
        using (var ms = new MemoryStream(4096))
        {
            doc.Save(ms);
            buffer = ms.ToArray();
        }

        return writeStream.WriteAsync(buffer, 0, buffer.Length);
    }

这是最好的方式吗?

2 个答案:

答案 0 :(得分:2)

当我有一个我知道将要同步运行的操作但需要一个Task作为返回值时,我使用TaskCompletionSource实例来创建一个已完成的Task并返回它。

 public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
    {
        XDocument doc = new XDocument();
        doc.Add(SerializeType(type, value));

        doc.Save(writeStream);

        var tcs = new TaskCompletionSource<object>();
        tcs.SetResult(null);
        return tcs.Task;
    }

答案 1 :(得分:-1)

StartNew用于计算绑定工作,而不用于I / O绑定。显然,给一个线程没有意义,因为该线程也必须等待。 MSDN说

  

仅在需要细粒度控制时才使用StartNew方法   一个长期运行的计算限制任务。

您可以使用using这样的内容。

public override async Task WriteToStreamAsync(Type type, object value, 
                                              Stream stream, 
                                              HttpContent content, 
                                              TransportContext transportContext)
{                                     
    if (string.IsNullOrEmpty(JsonpCallbackFunction))
    {
        await base.WriteToStreamAsync(type, value, stream, content,
                                                            transportContext);
        return;
    }

    using (var writer = new StreamWriter(stream))
    {
        writer.Write(JsonpCallbackFunction + "(");
        writer.Flush();

        await base.WriteToStreamAsync(type, value, stream, content,
                                                            transportContext);

        writer.Write(")");
        writer.Flush();
    }
}

我引用Brad Wilson