Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically bind pascal case c# model from snake case JSON in WebApi

I am trying to bind my PascalCased c# model from snake_cased JSON in WebApi v2 (full framework, not dot net core).

Here's my api:

public class MyApi : ApiController
{
    [HttpPost]
    public IHttpActionResult DoSomething([FromBody]InputObjectDTO inputObject)
    {
        database.InsertData(inputObject.FullName, inputObject.TotalPrice)
        return Ok();
    }
}

And here's my input object:

public class InputObjectDTO
{
    public string FullName { get; set; }
    public int TotalPrice { get; set; }
    ...
}

The problem that I have is that the JSON looks like this:

{
    "full_name": "John Smith",
    "total_price": "20.00"
}

I am aware that I can use the JsonProperty attribute:

public class InputObjectDTO
{
    [JsonProperty(PropertyName = "full_name")]
    public string FullName { get; set; }

    [JsonProperty(PropertyName = "total_price")]
    public int TotalPrice { get; set; }
}

However my InputObjectDTO is huge, and there are many others like it too. It has hundreds of properties that are all snake cased, and it would be nice to not have to specify the JsonProperty attribute for each property. Can I make it to work "automatically"? Perhaps with a custom model binder or a custom json converter?

like image 975
Rocklan Avatar asked Feb 05 '19 06:02

Rocklan


People also ask

What is create Pascal bindings for C?

Creating Pascal bindings for C is a tutorial with source code that explains in detail how to create manual bindings for C libraries. It deals with various data types (strings, arrays, etc).

How do I use C libraries in Pascal?

In order to use C libraries in Pascal, you have to create a pascal translation for every C function, type and variable. To do that one can either utilized an automated tool, like h2pas or do a manual headers conversion The H2Pas tool that automatically translates many common C things.

How do I change a Pascal case to a camel case?

Converting Pascal Case to Camel Case. Converting Pascal Case to Camel Case: Using shortcut. You can just select the first character of the string and use the shortcut “Ctrl+U” and it will convert the first character of the string to Lower case. The shortcut option is not limited to C#.

Does defaultcontractresolver automatically convert to Pascal?

Remember that DefaultContractResolver preserves whatever is the casing of the C# class. It doesn't automatically convert it to pascal casing. Just to make this clear have a look at the following figure.


1 Answers

No need to reinvent the wheel. Json.Net already has a SnakeCaseNamingStrategy class to do exactly what you want. You just need to set it as the NamingStrategy on the DefaultContractResolver via settings.

Add this line to the Register method in your WebApiConfig class:

config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
    new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() };

Here is a demo (console app) to prove the concept: https://dotnetfiddle.net/v5siz7


If you want to apply the snake casing to some classes but not others, you can do this by applying a [JsonObject] attribute specifying the naming strategy like so:

[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
public class InputObjectDTO
{
    public string FullName { get; set; }
    public decimal TotalPrice { get; set; }
}

The naming strategy set via attribute takes precedence over the naming strategy set via the resolver, so you can set your default strategy in the resolver and then use attributes to override it where needed. (There are three naming strategies included with Json.Net: SnakeCaseNamingStrategy, CamelCaseNamingStrategy and DefaultNamingStrategy.)


Now, if you want to deserialize using one naming strategy and serialize using a different strategy for the same class(es), then neither of the above solutions will work for you, because the naming strategies will be applied in both directions in Web API. So in in that case, you will need something custom like what is shown in @icepickle's answer to control when each is applied.

like image 108
Brian Rogers Avatar answered Oct 07 '22 21:10

Brian Rogers