简体   繁体   中英

Validate content-length before model binding ASP.NET Web Api

I am wondering how I can validate the content-length BEFORE the request body is read by the model binder in ASP.NET Web Api.

I can do it in the Action but then it's a waste of resources because the stream has already been read?

var contentLength = Request.Content.Headers.ContentLength;
if (contentLength > 1024*1024*20)
{
     throw new HttpResponseException(HttpStatusCode.RequestEntityTooLarge);
}

Is it ok to do it in an Action Filter?

If your are using Owin for hosting your API, and you want to globally apply this restriction to all requests, then you could make this check in a simple Owin middleware executed before Web API in your Owin pipeline:

app.Use(async (c, n) =>
{
    var request = c.Request;

    if (request != null)
    {
        string[] headerValues;
        if (request.Headers.TryGetValue("Content-Length", out headerValues))
        {
            var lengthValue = headerValues.First();
            if (Convert.ToInt64(lengthValue) > 1024 * 1024 * 20)
            {
                c.Response.StatusCode = (int)HttpStatusCode.RequestEntityTooLarge;
                return;
            }
        }
    }

    await n.Invoke();
});

//app.UseWebApi(..)

[Edit]

If you need to restrict the Content-Length in a more fine graded fashion, then your best option is to create an AuthorizationFilter that is executed before the model binding in the Web API pipeline , as opposed to a generic ActionFilter .

Something like this should work:

public class MaxContentLengthAttribute : AuthorizationFilterAttribute
{
    private readonly long _maxContentType;

    public MaxContentLengthAttribute(long maxContentType)
    {
        _maxContentType = maxContentType;
    }

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        var contentLength = actionContext.Request.Content.Headers.ContentLength;
        if (contentLength.HasValue && contentLength.Value > _maxContentType)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.RequestEntityTooLarge);
        }
    }
}

And in your controller:

[MaxContentLength(1024*1024*20)]
public void Post([FromBody]Foo value)
{
    DoWork(value);
}

This way you can respond to the request before the content is read by the model-binder.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM