Returning false from IHostBufferPolicySelector.UseBufferedInputStream on web host breakes Web API + MVC side-by-side, at least in some scenarios.
Consider an MVC controller with the following code:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Test = new StreamReader(Request.InputStream).ReadToEnd();
return View();
}
}
Then, have in the same web app the following Web API setup:
public static void Register(HttpConfiguration config)
{
config.Services.Replace(typeof(IHostBufferPolicySelector), new BufferOutputOnlyPolicySelector());
config.Routes.Add("Unused", new CustomRoute());
}
private class BufferOutputOnlyPolicySelector : IHostBufferPolicySelector
{
public bool UseBufferedInputStream(object hostContext)
{
return false;
}
public bool UseBufferedOutputStream(System.Net.Http.HttpResponseMessage response)
{
return true;
}
}
private class CustomRoute : IHttpRoute
{
public IDictionary<string, object> Constraints
{
get { return null; }
}
public IDictionary<string, object> DataTokens
{
get { return null; }
}
public IDictionary<string, object> Defaults
{
get { return null; }
}
public IHttpRouteData GetRouteData(string virtualPathRoot, System.Net.Http.HttpRequestMessage request)
{
return null;
}
public IHttpVirtualPathData GetVirtualPath(System.Net.Http.HttpRequestMessage request, IDictionary<string, object> values)
{
return null;
}
public System.Net.Http.HttpMessageHandler Handler
{
get { return null; }
}
public string RouteTemplate
{
get { return null; }
}
}
Then, try viewing the MVC page. You'll find that Web API routing broke MVC access to the page.
The only reason the CustomRoute is needed for the repro is some (apparent) optimizations around HostedHttpRoute that avoid creating an HttpRequestMessage. I believe adding a route constraint will also trigger the bug.
A possible solution is not to provide access to the input stream during Web API routing. (Note that the bug repros even when the input stream is not accessed during routing; merely making it available to be accessed causes this bug.)
Consider an MVC controller with the following code:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Test = new StreamReader(Request.InputStream).ReadToEnd();
return View();
}
}
Then, have in the same web app the following Web API setup:
public static void Register(HttpConfiguration config)
{
config.Services.Replace(typeof(IHostBufferPolicySelector), new BufferOutputOnlyPolicySelector());
config.Routes.Add("Unused", new CustomRoute());
}
private class BufferOutputOnlyPolicySelector : IHostBufferPolicySelector
{
public bool UseBufferedInputStream(object hostContext)
{
return false;
}
public bool UseBufferedOutputStream(System.Net.Http.HttpResponseMessage response)
{
return true;
}
}
private class CustomRoute : IHttpRoute
{
public IDictionary<string, object> Constraints
{
get { return null; }
}
public IDictionary<string, object> DataTokens
{
get { return null; }
}
public IDictionary<string, object> Defaults
{
get { return null; }
}
public IHttpRouteData GetRouteData(string virtualPathRoot, System.Net.Http.HttpRequestMessage request)
{
return null;
}
public IHttpVirtualPathData GetVirtualPath(System.Net.Http.HttpRequestMessage request, IDictionary<string, object> values)
{
return null;
}
public System.Net.Http.HttpMessageHandler Handler
{
get { return null; }
}
public string RouteTemplate
{
get { return null; }
}
}
Then, try viewing the MVC page. You'll find that Web API routing broke MVC access to the page.
The only reason the CustomRoute is needed for the repro is some (apparent) optimizations around HostedHttpRoute that avoid creating an HttpRequestMessage. I believe adding a route constraint will also trigger the bug.
A possible solution is not to provide access to the input stream during Web API routing. (Note that the bug repros even when the input stream is not accessed during routing; merely making it available to be accessed causes this bug.)