3

This is more of a design related question, and any help/pointers in the right direction is highly appreciated.

I am working on a ASP.NET Web API2 application, and have an Authorization filter and other Action filters. Within these filters, I need to access the Request object that comes as a part of the HttpPost request body. I use the following code to read the request body content and deserialize into the desired object. It works fine.

//actionContext is HttpActionContext
var requestContent = actionContext.Request.Content.ReadAsStringAsync();
var request = JsonSerializer.GetObject<BaseOTARequestModel>(requestContent.Result);

To serve a particular request, I am deserializing the request content twice (I have 2 filters). Once the request reaches the controller action, it is deserialized again by the Web API framework. I feel guilty that every request is deserialized 3 times, and have a feeling there is a better way to handle this.

How can I avoid deserializing the request multiple times in a request?

2
  • 1
    What are you wanting to access at the filter level? Does your API only ever receive one type of request object? I've only really checked headers in filters and other middleware code. Maybe you could pass your data via an http header instead. Commented Dec 19, 2017 at 13:46
  • We do not use Authorization filters for that purpose. As you found out they are not intended to access the request body. You can however do authorization later at the request processing and in doubt change the response to the appropriate HTTP status. E.g. at global.asax.cs in AuthorizeRequest(...). Commented Dec 26, 2017 at 9:48

1 Answer 1

2

I took this on as a challenge and came up with this solution. Here's a base filter attribute class:

public abstract class BaseOTARequestFilterAttribute : ActionFilterAttribute
{
    private HttpActionContext _actionContext;

    protected BaseOTARequestModel RequestModel
    {
        get
        {
            if (_actionContext.Request.Properties.ContainsKey("RequestModel"))
            {
                return _actionContext.Request.Properties["RequestModel"] as BaseOTARequestModel;
            }

            return null;
        }
        set
        {
            _actionContext.Request.Properties["RequestModel"] = value;
        }
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        _actionContext = actionContext;

        if (RequestModel == null)
        {
            //actionContext is HttpActionContext
            var requestContent = actionContext.Request.Content.ReadAsStringAsync();
            RequestModel = JsonSerializer.GetObject<BaseOTARequestModel>(requestContent.Result);
        }
    }
}

This base class handles your deserialization and uses the Request.Properties collection to store it. (OK, I know a Web API is stateless but this state only exists during the execution of the request so fine imho.)

Your various attributes should all inherit this base class and can use the derialized object as follows:

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        base.OnActionExecuting(actionContext);

        var data = RequestModel;
        // etc.
    }

This may not be the most elegant solution, but I believe it works. Interested to hear the views of others.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.