WebAPI是否支持按块读取分块请求?

时间:2015-12-18 15:31:38

标签: c# http asp.net-web-api2 owin

问题

我正在尝试将一些数据上传到网络服务。

我想上传数据in chunks,让网络服务依次读取每个块。但是,我在实践中发现,Web服务一次只能读取一个完整的缓冲区。

有没有办法获得WebAPI(理想情况下由Owin自行运行,但如果需要,我可以使用IIS)来尊重传输块?

我在Wireshark中验证过我的客户端正在发送数据块,因此我认为这是一个WebAPI问题。

为清楚起见,响应中的流数据非常正常 - 我的问题是从请求流中读取分块数据。

代码

控制器如下所示:

using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;

public class StreamingController : ApiController
{
    [HttpPost]
    public async Task<HttpResponseMessage> Upload()
    {
        var stream = await this.Request.Content.ReadAsStreamAsync();
        var data = new byte[20];
        int chunkCount = 1;
        while (true)
        {
            // I was hoping that every time I sent a chunk, then 
            // ReadAsync would return, but I find that it will only
            // return when I have sent 20 bytes of data. 
            var bytesRead = await stream.ReadAsync(data, 0, data.Length);

            if (bytesRead <= 0)
            {
                break;
            }

            Console.WriteLine($"{chunkCount++}: {Encoding.UTF8.GetString(data)}");
        }

        return new HttpResponseMessage(HttpStatusCode.OK);
    }
}

我的测试客户端看起来像这样:

void Main()
{
    var url = "http://localhost:6001/streaming/upload";
    var relayRequest = (HttpWebRequest)HttpWebRequest.Create(url);
    relayRequest.Method = "POST";
    relayRequest.AllowWriteStreamBuffering = false;
    relayRequest.AllowReadStreamBuffering = false;
    relayRequest.SendChunked = true;
    relayRequest.ContentType = "application/octet-stream";
    var stream = relayRequest.GetRequestStream();

    string nextLine;
    int totalBytes = 0;

    // Read a series of lines from the console and transmit them to the server.
    while(!string.IsNullOrEmpty((nextLine = Console.ReadLine())))
    {
        var bytes = Encoding.UTF8.GetBytes(nextLine);
        totalBytes += bytes.Length;
        Console.WriteLine(
            "CLIENT: Sending {0} bytes ({1} total)", 
            bytes.Length, 
            totalBytes);
        stream.Write(bytes, 0, bytes.Length);
        stream.Flush();
    }

    var response = relayRequest.GetResponse();
    Console.WriteLine(response);
}

理由

我的具体动机是我正在为RTP客户端编写HTTPS隧道。但是,这个问题在即时消息聊天应用程序的上下文中也是有意义的。您不希望部分聊天消息通过,然后必须等待消息2才能找到消息1的结尾......!

1 个答案:

答案 0 :(得分:2)

Transfer-Encoding: chunked的解码远离您的控制器。根据您的主机,它可能根本不会在应用程序中发生,而是由大多数服务器插入的http.sys pipeline API处理。

为了使您的应用程序能够查看此数据,您需要远离IIS / HttpListener并使用套接字。

感兴趣的可能是Nowin project,它提供了所有OWIN功能而不使用HttpListener,而是依赖于Socket异步API。我对此并不了解,但 可能 可以在解码之前获取流,但这似乎很费劲。