Streaming large files (>2GB over IIS) using WebAPI

IMHO there is no easy way to do that.

The call to GetBufferlessInputStream is buried deep inside HttpControllerHandler, which is the lowest possible layer of ASP.NET Web API (it's an HTTP Handler on top of which the entire Web API stack is built.

You can see the code here.

As you see it's full of statics, long methods with nested logical conditions, internals and privates, so it's not really customisable at all.
While the entire HttpControllerHandler in Web API can theoretically be replaced with a custom implementation (this is done inside HttpControllerRouteHandler - by overriding the GetHttpHandler method), it's de facto impossible (you could try to internalize this code in your application, but you'll end up dragging lots of extra internal classes too).

The best thing (and I dread to say that) that comes to my mind is to modify the source HttpControllerHandler class to use the overload of GetBufferlessInputStream that disables the request length limit and recompile the System.Web.Http.WebHost assembly, and deploy that modded version with your app.


According to MSDN, the way to read an unlimited stream length is HttpRequest.GetBufferlessInputStream. You could do something like:

public void ReadStream(HttpContext context, string filePath)
{
    using (var reader = new StreamReader(context.Request.GetBufferlessInputStream(true)))
    using (var filestream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read, 4096, true))
    using (var writer = new StreamWriter(filestream))
    {
        var readBuffer = reader.ReadToEnd();
        writer.WriteAsync(readBuffer);
    }
}

Ok, I found a pretty simple solution. The answer from @JustinR. would work, of course. But I wanted to continue to use a MultipartFormDataStreamProvider because that handles all the MIME stuff.

The solution is to simply create a new StreamContent instance with the correct bufferless Input stream and populate it with the headers from the original Content:

var provider = new MultipartFormDataStreamProvider(path);
var content = new StreamContent(HttpContext.Current.Request.GetBufferlessInputStream(true));
foreach (var header in Request.Content.Headers)
{
    content.Headers.TryAddWithoutValidation(header.Key, header.Value);
}

await content.ReadAsMultipartAsync(provider);