ajaxasp.net-mvchttphandlerrequestcontext

Using an HttpModule in MVC to return new response if AJAX request content length exceeds maximum allowed


I'm trying to create an HttpModule for my MVC application that will intercept a file upload request.

The goal is to catch the request before it's sent in order to check the content length of the request.

If the content length is larger than what is allowed, it should cancel that request and send an empty string as the response.

When a user clicks to upload a document, an ajax call is made to the UploadSignedDocument action:

[NoCache, HttpPost, ValidateAntiForgeryToken]        
public string UploadSignedDocument(int orderid, HttpPostedFileBase fileUpload)
{
    try
    {
        var fileinfo = new FileInfo(fileUpload.FileName);
        var newFileName = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss_") + fileinfo.Name;
        var docPath = Path.Combine(Server.MapPath("~/Uploads/"), newFileName);
        fileUpload.SaveAs(docPath);
        return newFileName;
    }
    catch
    {
        return "";
    }
}

Which is intercepted by the following HttpModule:

public class UploadedFileSizeScreeningModule : IHttpModule
{    
    public void Init(HttpApplication application)
    {
        application.EndRequest += ValidateUploadRequest;
    }

    public void Dispose()
    {
    }

    private static void ValidateUploadRequest(object source, EventArgs e)
    {
        HttpApplication context = source as HttpApplication;

        if (context.Request.HttpMethod.ToUpperInvariant() != "POST" ||
            !context.Request.Path.Contains("OrderQueue/UploadSignedDocument"))
        {
            return;
        }

        var requestLengthInMB = context.Request.ContentLength / 1024 / 1024;

        if (requestLengthInMB > Settings.Default.MaxFileSizeInMB)
        {
            // TODO: Return new response (empty string)
        }
    }
}

How do I return an empty string back to the caller from the HttpHandler?


Solution

    1. You should be using the context.Response itself to return the ajax response. Just write in there the empty string.
    2. You should be subscribed to HttpApplication.EndRequest. That's where you may actually change (or even replace) the HTTP response.
    3. You should not be using the HttpApplication.PreSendRequestHeaders event:

    You can use the PreSendRequestHeaders and PreSendRequestContext events with native IIS modules, but do not use them with managed modules that implement IHttpModule. Setting these properties can cause issues with asynchronous requests.

    From What not to do in ASP.NET, and what to do instead.

    Edit

    Maybe something like this?

    public class UploadedFileSizeScreeningModule : IHttpModule
    {    
        public void Init(HttpApplication application)
        {
            application.EndRequest += ValidateUploadRequest;
        }
    
        public void Dispose()
        {}
    
        private static void ValidateUploadRequest(object source, EventArgs e)
        {
            HttpApplication context = source as HttpApplication;
    
            if (context.Request.HttpMethod.ToUpperInvariant() != "POST" ||
                !context.Request.Path.Contains("OrderQueue/UploadSignedDocument"))
            {
                return;
            }
    
            var requestLengthInMB = context.Request.ContentLength / 1024 / 1024;
    
            if (requestLengthInMB > Settings.Default.MaxFileSizeInMB)
            {
                context.Response.Clear();
                context.Response.Write(string.Empty);
                context.Response.End();            
            }
        }
    }