How to set custom headers when using IHttpActionResult?

asp.net, asp.net-web-api, c#

Solution

For your scenario, you would need to create a custom `IHttpActionResult`. Following is an example where I derive from `OkNegotiatedContentResult<T>` as it runs `Content-Negotiation` and sets the `Ok` status code.

public class CustomOkResult<T> : OkNegotiatedContentResult<T>
{
    public CustomOkResult(T content, ApiController controller)
        : base(content, controller) { }

    public CustomOkResult(T content, IContentNegotiator contentNegotiator, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters) 
        : base(content, contentNegotiator, request, formatters) { }

    public string ETagValue { get; set; }

    public override async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        HttpResponseMessage response = await base.ExecuteAsync(cancellationToken);

        response.Headers.ETag = new EntityTagHeaderValue(this.ETagValue);

        return response;
    }        
}

Controller:

public class ValuesController : ApiController
{
    public IHttpActionResult Get()
    {
        return new CustomOkResult<string>(content: "Hello World!", controller: this)
            {
                    ETagValue = "You ETag value"
            };
    }
}

Note that you can also derive from `NegotiatedContentResult<T>`, in which case you would need to supply the StatusCode yourself. Hope this helps.

You can find the source code of `OkNegotiatedContentResult<T>` and `NegotiatedContentResult<T>`, which as you can imagine are simple actually.

Problem

In ASP.NET Web API 2, the `IHttpActionResult` offers a lot of value in simplifying controller code and I'm reluctant to stop using it, but I've hit a problem. I need to set an ETag on an outgoing response, and I cannot find any property which gives me access to the response's headers. At the moment I'm using the `Ok<T>(T content)` helper method from the `ApiController`, which returns an `OkNegotiatedContentResult<T>` object. That doesn't seem to have anything exposed which would let me modify the headers though. Am I missing something, or is there really no way to do this while using the stock `IHttpActionResult` types? I considered a message handler, but then I'd have to figure out how to pass the ETag out of the action (the ETags are generated differently for different actions, so it's not a matter of making a generic handler for all actions). I'd like to avoid having to use the raw HttpResponseMessage, but at the moment that's looking difficult.

Original source