Search code examples
c#asp.netasp.net-mvciiscom

STA MVC application doesnt end long running requests


I need to run my ASP.NET MVC application in STA mode. For this purpose I developed some custom classes based on Programming ASP.NET MVC 4: Developing Real-World Web Applications with ASP.NET MVC. Here they are:

public class StaThreadRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        if (requestContext == null)
            throw new ArgumentNullException("requestContext");

        return new StaThreadHttpAsyncHandler(requestContext);
    }
}

public class StaThreadHttpAsyncHandler : Page, IHttpAsyncHandler, IRequiresSessionState
{
    private readonly RequestContext _requestContext;
    public StaThreadHttpAsyncHandler(RequestContext requestContext)
    {
        if (requestContext == null)
            throw new ArgumentNullException("requestContext");

        _requestContext = requestContext;
    }

    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
        return this.AspCompatBeginProcessRequest(context, cb, extraData);
    }

    protected override void OnInit(EventArgs e)
    {
        var controllerName = _requestContext.RouteData.GetRequiredString("controller");
        var controllerFactory = ControllerBuilder.Current.GetControllerFactory();
        var controller = controllerFactory.CreateController(_requestContext, controllerName);
        if (controller == null)
            throw new InvalidOperationException("Could not find controller: " + controllerName);
        try
        {
            controller.Execute(_requestContext);
        }
        finally
        {
            controllerFactory.ReleaseController(controller);
        }
        this.Context.ApplicationInstance.CompleteRequest();
    }

    public void EndProcessRequest(IAsyncResult result)
    {
        this.AspCompatEndProcessRequest(result);
    }

    public override void ProcessRequest(HttpContext httpContext)
    {
        throw new NotSupportedException("STAThreadRouteHandler does not support ProcessRequest called (only BeginProcessRequest)");
    }
}

Also adjusted RouteConfig:

routes.Add(new Route("{controller}/{action}/{id}", new StaThreadRouteHandler ()))

Everything works fine for majority of my actions, but I have two that take somewhere between 10 and 20 seconds to finish. For these two actions, method EndProcessRequest is never executed, even though no exception is thrown during their execution and this.Context.ApplicationInstance.CompleteRequest(); is called within OnInit without problems. As a result, such request ends in IIS with state ExecuteRequestHandler and is stuck there forever and also blocks new requests from being served. enter image description here

Why is this happening? Why breakpoint in EndProcessRequest is never hit for long running actions, while it works fine for shorter actions (1-5 seconds).


Solution

  • Problem was not related to execution time of particular actions at all. Not really sure what was happening under hood but all the problematic actions had one in common - they were creating one particular COM object, which I guess was somehow not properly destroyed and as a result EndProcessRequest was not called.

    The issue was happening for any .NET COM object, native COM objects are fine and EndProcessRequest is called.