【问题标题】:Right way of implementing MediaTypeFormatter.WriteToStreamAsync in Web API在 Web API 中实现 MediaTypeFormatter.WriteToStreamAsync 的正确方法
【发布时间】:2013-07-08 22:12:57
【问题描述】:

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

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

我见过很多同步操作的例子,为了返回Task,他们将代码包含在Task.Factory.StartNew()中,但是……这样可以吗?我的意思是,这不是让任务链接 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呢?

另外,我用的是内部内存流,和WriteAsyncwriteStream

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

最好的方法是什么?

【问题讨论】:

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


    【解决方案1】:

    当我知道某个操作将同步运行,但需要一个 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;
        }
    

    【讨论】:

      【解决方案2】:

      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

      【讨论】:

      • WriteToStreamAsync 的 MSDN 文档指出“此方法的实现不应在完成后关闭 writeStream”-msdn.microsoft.com/en-us/library/dn479105(v=vs.118).aspx。 StreamWriter 的默认构造函数导致在释放 writer 时释放流。
      • 简单,只需这样做以使其保持打开状态: using (var streamWriter = new StreamWriter(stream, UTF8, 1460, leaveOpen: true)) {
      猜你喜欢
      • 1970-01-01
      • 2018-09-07
      • 1970-01-01
      • 2017-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多