Overriding the default JSON serializer settings for web API on application level has been covered in a lot of SO threads. But how can I configure its settings on action level? For example, I might want to serialize using camelcase properties in one of my actions, but not in the others.
Asked
Active
Viewed 3.1k times
41
-
Could you not just craft the `HttpResponseMessage` manually setting the content to your desired json output? It's not as tidy as dealing with a global formatter but you can still create DRY helpers for dealing with these one off situations. – Phil Cooper Jun 12 '17 at 12:12
-
Have you considered ActionFilterAttributes for the task? – Padraic Jun 12 '17 at 12:19
-
The best approach would be to build an HTTP module and intercept each request and process as you need to for each different action. – Derek Hackett Jun 12 '17 at 12:20
-
Would you consider an override per controller instead of per action? – Federico Dipuma Jun 12 '17 at 12:24
-
@FedericoDipuma Sure, that would be fine – Johan Jun 12 '17 at 12:32
-
@Padraic How would I access the serializer there? – Johan Jun 12 '17 at 12:33
-
@DerekHackett Could you provide a brief example? – Johan Jun 12 '17 at 12:33
-
@Johan I would tweak what they are doing in this example. If you need a detailed example for your use case just let me know. http://alexwolfthoughts.com/efficient-mvc-redirects-using-an-http-module/ – Derek Hackett Jun 12 '17 at 15:53
-
@DerekHackett Thanks, I'll look in to it. Though Federico provided me with a good response too – Johan Jun 12 '17 at 16:02
3 Answers
76
Option 1 (quickest)
At action level you may always use a custom JsonSerializerSettings
instance while using Json
method:
public class MyController : ApiController
{
public IHttpActionResult Get()
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var model = new MyModel();
return Json(model, settings);
}
}
Option 2 (controller level)
You may create a new IControllerConfiguration
attribute which customizes the JsonFormatter:
public class CustomJsonAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
var formatter = controllerSettings.Formatters.JsonFormatter;
controllerSettings.Formatters.Remove(formatter);
formatter = new JsonMediaTypeFormatter
{
SerializerSettings =
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
}
};
controllerSettings.Formatters.Insert(0, formatter);
}
}
[CustomJson]
public class MyController : ApiController
{
public IHttpActionResult Get()
{
var model = new MyModel();
return Ok(model);
}
}

Federico Dipuma
- 17,655
- 4
- 39
- 56
-
do we need to instantiate a new formmater? can't we tweak the current instance or the change will be applied everywhere? – JobaDiniz Jan 19 '18 at 17:43
-
2@JobaDiniz as you stated, if you change properties of the original formatter, those changes will affect every other controller – Federico Dipuma Jan 19 '18 at 17:47
-
Nice initialization of SerializerSettings! I didn't know about that C# feature. – gius Feb 01 '18 at 10:38
15
Here's an implementation of the above as Action Attribute:
public class CustomActionJsonFormatAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext?.Response == null) return;
var content = actionExecutedContext.Response.Content as ObjectContent;
if (content?.Formatter is JsonMediaTypeFormatter)
{
var formatter = new JsonMediaTypeFormatter
{
SerializerSettings =
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
}
};
actionExecutedContext.Response.Content = new ObjectContent(content.ObjectType, content.Value, formatter);
}
}
}
public class MyController : ApiController
{
[CustomActionJsonFormat]
public IHttpActionResult Get()
{
var model = new MyModel();
return Ok(model);
}
}

Dimitri
- 6,923
- 4
- 35
- 49
-
I used this code but I gave it a `Type ContractResolverType` property and then did `ContractResolver = (IContractResolver)Activator.CreateInstance(ContractResolverType)` so I don't have to create one of these for each contract resolver type. In use it looks like this: `[ActionContractResolver(ContractResolverType = typeof(DefaultContractResolver))]` – R. Salisbury Mar 09 '21 at 19:11
0
I needed to return a 404 status error code alongside a json object with error details. I solved it using WebApi.Content with a new new JsonMediaTypeFormatter.
public class MyController : ApiController
{
public IHttpActionResult Get()
{
// Configure new Json formatter
var formatter = new JsonMediaTypeFormatter
{
SerializerSettings =
{
TypeNameHandling = TypeNameHandling.None,
PreserveReferencesHandling = PreserveReferencesHandling.None,
Culture = CultureInfo.InvariantCulture,
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore
}
};
try
{
var model = new MyModel();
return Content(HttpStatusCode.OK, model, formatter);
}
catch (Exception err)
{
var errorDto = GetErrorDto(HttpStatusCode.NotFound, $"{err.Message}");
return Content(HttpStatusCode.NotFound, errorDto, formatter);
}
}
}

Javier Rojano
- 814
- 9
- 17