I have a ASP.NET WebApi self-hosted application. HttpSelfHostConfiguration
is configured as below
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://0.0.0.0:54781")
{
TransferMode = TransferMode.StreamedResponse,
MaxConcurrentRequests = 1000,
SendTimeout = TimeSpan.FromMinutes(60),
};
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}",
defaults: new { @controller = "Default" }
);
HttpSelfHostServer server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
for (;;)
{
int workerThreads, completionPortThreads;
ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
Console.WriteLine("Available Completion Port Threads = {0};", completionPortThreads);
Console.Out.Flush();
Thread.Sleep(2000);
}
There is an action accepts HTTP GET request as below
public class DefaultController : ApiController
{
public HttpResponseMessage GET()
{
Console.WriteLine("Receive HTTP GET request");
Func<Stream, HttpContent, TransportContext, Task> func = (stream, httpContent, transportContext) =>
{
return Monitor(httpContent, stream);
};
HttpResponseMessage response = Request.CreateResponse();
response.StatusCode = HttpStatusCode.OK;
response.Content = new PushStreamContent(func, new MediaTypeHeaderValue("text/plain"));
return response;
}
async Task Monitor(HttpContent httpContent, Stream stream)
{
try
{
using (StreamWriter sw = new StreamWriter(stream, new UTF8Encoding(false)))
{
for (;;)
{
sw.WriteLine(Guid.NewGuid().ToString());
sw.Flush();
await Task.Delay(1000);
}
}
}
catch (CommunicationException ce)
{
HttpListenerException ex = ce.InnerException as HttpListenerException;
if (ex != null)
{
Console.WriteLine("HttpListenerException occurs, error code = {0}", ex.ErrorCode);
}
else
{
Console.WriteLine("{0} occurs : {1}", ce.GetType().Name, ce.Message);
}
}
catch (Exception ex)
{
Console.WriteLine("{0} occurs : {1}", ex.GetType().Name, ex.Message);
}
finally
{
stream.Close();
stream.Dispose();
httpContent.Dispose();
Console.WriteLine("Dispose");
}
}
}
Open the url http://127.0.0.1:54781/
and I see progressive response comming.
But If the client terminates the connection when the server is sending the response, the completion port thread is taken up and never released.
It able to bring down the application by exhausting the completion port threads pool.
After changing to OWIN self-hosting, this problem disappears. It seems a bug in
System.Web.Http.SelfHost
Here is updated code: