Search code examples
c#asp.net-web-apimediatypeformattermessage-handlers

Web API modify incoming payload in formatter


All,

I am trying to modify the payload of incoming object via the web API. Currently I'm using a custom formatter which inherits from JsonMediaTypeFormatter and overrides the relevant methods.

Looks like this:

public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger,
    CancellationToken cancellationToken)
{
    object obj =  await base.ReadFromStreamAsync(type, readStream, content, formatterLogger, cancellationToken);
    TrySetEventNo(obj, GetEventNo());
    return obj;
}

private void TrySetEventNo(object content, long eventNo)
{
    if (content is EventModelBase)
    {
        EventModelBase eventBase = (EventModelBase)content;
        eventBase.EventNo = eventNo;
    }
}

I'm using this to track every object that comes through the API.

Before all of this happens, I have a MessageHandler which is creating an event number and adding it to Request.Properties.

Trying to get the event number in the formatter which was created previously in the MessageHandler is proving difficult. Access HttpContext.Current.Items["MS_HttpRequestMessage"].Properties seems to be a different request as it does not contain the event number.

I've two questions:

  1. Am I doing this the correctly or is there a better way?
  2. If I am taking the correct approach, how to I get the correct Request to extract the event number?

Thanks


Solution

  • I've found a solution, instead of attempting to do this inside a formatter I'm now using an ActionFilterAttribute.

    overriding OnActionExecuting(HttpActionContext actionContext) and enumerating action actionContext.ActionArguments.

    The complete solution looks like so:

    public class SetModelEventNumberActionFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
    
            foreach (KeyValuePair<string, object> actionArgument in actionContext.ActionArguments)
            {
                TrySetEventNo(actionArgument.Value, GetEventNo(actionContext));
            }
    
            base.OnActionExecuting(actionContext);
        }
        private void TrySetEventNo(object content, long eventNo)
        {
            if (content is EventPivotRequestMessageBase)
            {
                EventPivotRequestMessageBase eventBase = (EventPivotRequestMessageBase)content;
                eventBase.EventNo = eventNo;
            }
        }
    
        private long GetEventNo(HttpActionContext actionContext)
        {
    
            long eventNo = (long)actionContext.Request.Properties[Constant.EVENT_ID];
    
            return eventNo;
        }
    }