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

Does WebAPI support reading chunked requests by chunk?

问题

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

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

有没有办法让 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 的结尾...!

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

为了让您的应用程序甚至有机会查看此数据,您需要离开 IIS/HttpListener 并改用套接字。

感兴趣的可能是 Nowin project,它提供所有 OWIN 功能而不使用 HttpListener,而是依赖于套接字异步 API。我不太了解它,但是 可能 是在解码之前获取流的钩子......看起来很多虽然努力。