Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CamelCasePropertyNamesContractResolver not Working after MapHttpRoute

I'm trying to implement JSON camel casing in my .Net API project. In my start up class I add the following lines:

config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = 
    new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;

As I understand it this is what is required to implement camel casing on all routes. However when I add the following this fails to work, the responses come back as Pascal Case:

RouteTable.Routes.MapHttpRoute(
    "DefaultApi",
     "{controller}/{id}",
      new {id = RouteParameter.Optional}
);

When I remove the above MapHttpRoute line and use Route attributes in the controllers instead camel casing works fine.

Has anyone any idea as to what is happening here?

like image 305
G.C Avatar asked Nov 07 '22 16:11

G.C


1 Answers

Before we answer, you should understand first that the camel case API response overriding will NOT affect the Model Validation (we will solve this problem at the end of answer).

FOR YOUR QUESTION:

You have to use the same HttpConfiguration variable so try to use this instead

// config is an HttpConfiguration object

config.Routes.MapHttpRoute(
     name: "API Default",
     routeTemplate: "api/{controller}/{id}",
     defaults: new { id = RouteParameter.Optional });

config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

FOR THE MODEL VALIDATION:

You have to create a base controller that all your other controllers should inherit from, then override the ModelStateDictionary by creating a new method that you have to use instead (ModelState is a read-only property) as below (1):

public class BaseApiController : ApiController
{
    public ModelStateDictionary ModelStateAsCamelCase()
    {
        var newModelStateDictionary = new ModelStateDictionary();

        foreach (var element in ModelState)
        {
            if (!string.IsNullOrWhiteSpace(element.Key))
            {
                var keys = element.Key.Split('.');
                List<string> camelKeys = new List<string>();
                foreach (var key in keys)
                {
                    camelKeys.Add(key.First().ToString().ToLowerInvariant() + key.Substring(1));
                }

                // You can (add a / change this) code if the returned key is not
                // composed from the ObjectName.Property, such as when it is 
                // composed from the property name

                var newKey = camelKeys.Aggregate((i, j) => i + "." + j);

                newModelStateDictionary.Add(newKey, element.Value);
            }
            else
                newModelStateDictionary.Add(element);
        }
        return newModelStateDictionary;
    }
}

this method will edit the model state dictionary string key to comply the camel convention

now inside your action, you can use this method instead of the default ModelState

......

if (!ModelState.IsValid)
    return BadRequest(ModelStateAsCamelCase());

......

1- I have checked many answer related to solve the camelCase problem in modelState even in .net core but non has provided a default config solution. as they mentioned that the modelState will not get affected by the default config used in the first part from my answer

like image 106
AbuDawood Avatar answered Nov 14 '22 22:11

AbuDawood