During the upgrade of a solution from the Web Api Preview 6 to MVC 4 Beta Web Api, I encountered a bug with a custom MediaTypeFormatter. In the Api controller I had a need to take the posted content object as well as some string identifiers/keys as parameters. The problem I encountered as that if I utilized a custom MediaTypeFormatter, these values came in as Null
Take the following Api controller Post:
// POST /api/values
public HttpResponseMessage<SomeObj> Post(string key, string id, SomeObject value)
The string key always came in null. However, if I switch and used one of the built in formatters XmlMediaTypeFormatter for example, this was not a problem. It is my understanding that this issue will be fixed post Beta. I posted my problem on MSDN and did receive a response, you can find it here.
In the meantime, something like the following can be used for a workaround.
Add an Action Filter to handle the parameter binding for you. Below is an example of such a filter. It currently would only work with string or int route parameterrs (but can be changed/expanded).
public class ParameterFilter : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.Request.Method != HttpMethod.Get)
{
var idParams = actionContext.ControllerContext.Request.GetRouteData();
foreach (var item in idParams.Values)
{
object value;
var result = actionContext.ActionArguments.TryGetValue(item.Key, out value);
if (result)
{
var parm = actionContext.ActionDescriptor.GetParameters().Where(x => x.ParameterName == item.Key).SingleOrDefault();
var type = parm.ParameterType;
// Check Action parameter type and convert if needed
if (type == typeof(int))
{
actionContext.ActionArguments[item.Key] = Convert.ToInt32(item.Value);
}
if (type == typeof(string))
{
actionContext.ActionArguments[item.Key] = item.Value.ToString();
}
}
}
}
base.OnActionExecuting(actionContext);
}
}
Register the Action Filter in the Global.asax
protected void Application_Start()
{
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Filters.Add(new ParameterFilter());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
BundleTable.Bundles.RegisterTemplateBundles();
}