Search code examples
c#asp.net-core-webapiactionfilterattribute

Change JSON response to Pascal case using web API custom attribute


My Custom Action Filter Attribute to convert a JSON response of MVC core webApi from "camelCase" to "pascalCase" is not working.

Tried using:

services.AddMvc()
    .AddJsonOptions(options => 
        options.SerializerSettings.ContractResolver = new DefaultContractResolver());

However, this kind of global setting changes all response to Pascal case. I want to change only a limited API response to Pascal case.

Custom ActionFilterAttribute:

public class CancelCamelCaseResolverConfigurationAttribute : ActionFilterAttribute
{

    public override void OnResultExecuted(ResultExecutedContext context)
    {
        base.OnResultExecuted(context);

        var objectResult = context.Result as ObjectResult;
        if (objectResult != null)
        {
            objectResult.Formatters.Clear();
            objectResult.Formatters.Add(new JsonOutputFormatter(
                new JsonSerializerSettings()
                {
                    Formatting = Formatting.None,
                    ContractResolver = new DefaultContractResolver()
                }, ArrayPool<char>.Shared));
        }
    }
}

And use in the webApi controller:

[CancelCamelCaseResolverConfiguration]
public class FrmMainSearchController : AtlasApiController<FrmMainSearchController>
{
    /*Api*/
}

Expected result:

searchCriteria = [{Key: "xx", Value: "yy"}]

Actual result:

searchCriteria = [{key: "xx", value: "yy"}]

Solution

  • You're almost there: You need override the OnActionExecuted() method instead of the OnResultExecuted().

    It's too late to change the formatters when the OnResultExecuted() filter method is invoked.

    How to fix:

    Override the OnResultExecuted method so that the formatter is changed before the result execution:

    public override void OnResultExecuted(ResultExecutedContext context)
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        ...
    }
    

    As a side note, you didn't check for type JsonResult. To make it work with Json() or JsonResult(), you need check the result type dynamically:

    public class CancelCamelCaseResolverConfigurationAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            base.OnActionExecuted(context);
            switch(context.Result){
                case JsonResult j:
                    var result = new ObjectResult(j.Value);
                    context.Result = result;
                    ChangeFormatting(result);
                    break;
                case ObjectResult o:
                    ChangeFormatting(o);
                    break;
                default:
                    return;
            }
    
        }
    
        private void ChangeFormatting(ObjectResult result){
            if (result == null){ return; }
            result.Formatters.Clear();
            result.Formatters.Add(new JsonOutputFormatter(
                new JsonSerializerSettings()
                {
                    Formatting = Formatting.None,
                    ContractResolver = new DefaultContractResolver()
                }, ArrayPool<char>.Shared)
            );
        }
    }