How to set custom headers when using IHttpActionResult?

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.


You can create a HttpResponseMessage, add headers as needed and then create ResponseMessageResult from it:

HttpResponseMessage response =new HttpResponseMessage(HttpStatusCode.OK);
response.Headers.Add("MyHeader", "MyHeaderValue");
return ResponseMessage(response);

Here is my simple implementation without ActionFilterAttributes and is similar to AlexACD's response. My solution uses the ResponseMessageResult which implements the IHttpActionResult interface.

HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
responseMessage.Headers.Add("Headername", "Value");
ResponseMessageResult response = new ResponseMessageResult(responseMessage);
return response;

public static class HttpExtentions
{
    public static IHttpActionResult AddHeader(this IHttpActionResult action,
        string headerName, IEnumerable<string> headerValues)
    {
        return new HeaderActionResult(action, headerName, headerValues);
    }

    public static IHttpActionResult AddHeader(this IHttpActionResult action,
        string headerName, string header)
    {
        return AddHeader(action, headerName, new[] {header});
    }

    private class HeaderActionResult : IHttpActionResult
    {
        private readonly IHttpActionResult action;

        private readonly Tuple<string, IEnumerable<string>> header;

        public HeaderActionResult(IHttpActionResult action, string headerName,
            IEnumerable<string> headerValues)
        {
            this.action = action;

            header = Tuple.Create(headerName, headerValues);
        }

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

            response.Headers.Add(header.Item1, header.Item2);

            return response;
        }
    }
}