Santosh Achanta
Oct 5, 2016
  7087
(1 votes)

FormattingJsonAttribute for camel case formatting of variable names and converting enums to strings

I am tired of using JsonProperty decorator for each class member so decided to do something that will automatically take care of camel case conversion of variable names for Json response.

"FormattingJson" is a decorator for a class or a method to convert property names to camel case and enum values to strings whle serializing response object.

Usage: Decorate a class(eg. a API controller) or a method with the below

[FormattingJson(FormatterTypes.CamelCase, FormatterTypes.EnumToString)]

Underlying functions those are respinsible for this utility are CamelCasePropertyNamesContractResolver and StringEnumConverter from Newtonsoft.Json library.

Below is the code for implementation.

using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http.Filters;
using Episerver.Web.Site.Attributes.Formatting.Formatters;

namespace Episerver.Web.Site.Attributes.Formatting
{
    /// <summary>
    /// Apply required formatting on the response content
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public sealed class FormattingJsonAttribute : ActionFilterAttribute
    {
        private readonly FormatterTypes[] _formatterTypes;

        /// <summary>
        /// Initializes a new instance of the <see cref="FormattingJsonAttribute"/> class.
        /// </summary>
        /// <param name="formatterTypes">The formatter types.</param>
        /// <exception cref="System.ArgumentException">At least one formatter type must be provided;formatterTypes</exception>
        public FormattingJsonAttribute(params FormatterTypes[] formatterTypes)
        {
            if (formatterTypes == null || !formatterTypes.Any())
            {
                throw new ArgumentException("At least one formatter type must be provided");
            }

            _formatterTypes = formatterTypes;
        }

        /// <summary>
        /// Occurs after the action method is invoked.
        /// </summary>
        /// <param name="actionExecutedContext">The action executed context.</param>
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext == null || actionExecutedContext.Response == null)
            {
                return;
            }

            var content = actionExecutedContext.Response.Content as ObjectContent;

            if (content != null)
            {
                var jsonFormatter = new JsonMediaTypeFormatter();
                if (content.Formatter is JsonMediaTypeFormatter)
                {
                    var factory = new FormatterFactory();

                    foreach (var formatter in _formatterTypes)
                    {
                        factory.Create(formatter)
                            .Apply(jsonFormatter);
                    }

                    actionExecutedContext.Response.Content = new ObjectContent(content.ObjectType, content.Value, jsonFormatter);
                }
            }
        }
    }
}

namespace Episerver.Web.Site.Attributes.Formatting
{
    public enum FormatterTypes
    {
        /// <summary>
        /// Changes it from 'CamelCase' to 'camelCase'.
        /// </summary>
        CamelCase = 1,

        /// <summary>
        /// Returns the 'string' version of the enum. The default parsing is 'int'. Example: BalancePosition.Credit will be 'Credit' not '0'
        /// </summary>
        EnumToString = 2
    }
}

using System.Net.Http.Formatting;
using Newtonsoft.Json.Serialization;

namespace Episerver.Web.Site.Attributes.Formatting.Formatters
{
    /// <summary>
    /// Converts output to camel case
    /// </summary>
    public class CamelCaseFormatterApplier : IFormatterApplier
    {
        /// <summary>
        /// Applies the specified formatter.
        /// </summary>
        /// <param name="formatter">The formatter.</param>
        public void Apply(JsonMediaTypeFormatter formatter)
        {
            formatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        }
    }
}

using System.Net.Http.Formatting;
using Newtonsoft.Json.Converters;

namespace Episerver.Web.Site.Attributes.Formatting.Formatters
{
    /// <summary>
    /// Converts enums from int to string
    /// </summary>
    public class EnumStringFormatterApplier : IFormatterApplier
    {
        /// <summary>
        /// Applies the specified formatter.
        /// </summary>
        /// <param name="formatter">The formatter.</param>
        public void Apply(JsonMediaTypeFormatter formatter)
        {
            formatter.SerializerSettings.Converters.Add(new StringEnumConverter());
        }
    }
}

using System.Net.Http.Formatting;

namespace Episerver.Web.Site.Attributes.Formatting.Formatters
{
    /// <summary>
    /// Applies formatting to the response output
    /// </summary>
    public interface IFormatterApplier
    {
        /// <summary>
        /// Applies the specified formatter.
        /// </summary>
        /// <param name="formatter">The formatter.</param>
        void Apply(JsonMediaTypeFormatter formatter);
    }
}

using System;

namespace Episerver.Web.Site.Attributes.Formatting.Formatters
{
    /// <summary>
    /// Creates formatters
    /// </summary>
    public class FormatterFactory
    {
        /// <summary>
        /// Creates the approriate formatter
        /// </summary>
        /// <param name="formatterType"></param>
        /// <returns></returns>
        public IFormatterApplier Create(FormatterTypes formatterType)
        {
            switch (formatterType)
            {
                case FormatterTypes.CamelCase:
                    return new CamelCaseFormatterApplier();

                case FormatterTypes.EnumToString:
                    return new EnumStringFormatterApplier();

                default:
                    throw new ArgumentOutOfRangeException("formatterType", formatterType, "Invalid formatter type");
            }
        }
    }
}
Oct 05, 2016

Comments

Thomas Schmidt
Thomas Schmidt Oct 5, 2016 01:44 PM

I am not entirely sure what you are trying to achieve here, but assuming you just want all json to be serialized with camelCase, then why don't you just set the ContractResolver to CamelCasePropertyNamesContractResolver instead of going whit this attribute approach? One line of code for WebApi configuration and a few lines for Mvc making custom CamelCaseJsonActionResult or similar?

Santosh Achanta
Santosh Achanta Oct 5, 2016 10:21 PM

That's a good point Thomas but I want the formatting/conversion done only if I ask it to do for a method or for the whole controller so went with this Attribute approach.

Please login to comment.
Latest blogs
Optimizely PaaS + Figma + AI: Auto‑Generate Blocks with Cursor

What if your design handoff wrote itself? In this end‑to‑end demo, I use an AI Agent (inside Cursor) to translate a Figma design into an... The pos...

Naveed Ul-Haq | Feb 5, 2026 |

Graph access with only JS and Fetch

Postman is a popular tool for testing APIs. However, when testing an API like Optimizely Graph that I will be consuming in the front-end I prefer t...

Daniel Halse | Feb 4, 2026

Best Practices for Implementing Optimizely SaaS CMS: A Collective Wisdom Guide

This guide compiles collective insights and recommendations from Optimizely experts for implementing Optimizely SaaS CMS, focusing on achieving...

David Knipe | Feb 4, 2026 |

A day in the life of an Optimizely OMVP: Learning Optimizely Just Got Easier: Introducing the Optimizely Learning Centre

On the back of my last post about the Opti Graph Learning Centre, I am now happy to announce a revamped interactive learning platform that makes...

Graham Carr | Jan 31, 2026

Scheduled job for deleting content types and all related content

In my previous blog post which was about getting an overview of your sites content https://world.optimizely.com/blogs/Per-Nergard/Dates/2026/1/sche...

Per Nergård (MVP) | Jan 30, 2026

Working With Applications in Optimizely CMS 13

💡 Note:  The following content has been written based on Optimizely CMS 13 Preview 2 and may not accurately reflect the final release version. As...

Mark Stott | Jan 30, 2026