0

First I write it a little bit general, if you need more informations, tell me!

My C#-Class looks like this, when sent/received on the frontend:

    public class Recipe : ICRUD
    {       
        public Guid ID { get; set; }
        public Guid UnitID { get; set; }
        public string Title { get; set; }
        // ... plus Lists ...
    }

[Backend => Frontend]

Backend

 [HttpGet("Recipe/[action]")]
 public async Task<JsonResult> GetRecipes(ServerRequest filter)

Frontend

   getRecipes(filter: ServerRequest) {
        return this._http.get(this.myAppUrl + 'Recipe/GetRecipes' + '?' + this.toQueryString(filter))
            .pipe(map((res: Recipe[]) => { return res; }));
    }

I was looking at my network traffic and(something)changed the model:

ID => id
UnitID => unitId 
// ... plus Lists ...

So I changed my (frontend, typescript) model as well:

export class Recipe {
    id: string;
    unitId: string;
    title: string; 
}

Now finally I got a stable state, and I want to sent the data back to the server.

Next problem:

[Frontend => Backend]

Frontend

createRecipe(recipe: Recipe) {
        return this._http.post(this.myAppUrl + 'Recipe/CreateRecipe', recipe)
            .pipe(map(res => { return res; })); 

Backend

[HttpPost("Recipe/[action]")]
public async Task<HttpResponseMessage> CreateRecipe([FromBody]Recipe recipe)

Guess what ?

ModelState is invalid, because he is missing UnitID, yeah, because it's written like this unitId

He is expecting capital letter(...UnitID..), but I am sending unitId, then UnitID is null(at least this is my explaination) ?

What shall I do ?

Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66
StartingAgain
  • 219
  • 2
  • 11
  • Change the backend, fields are usually not written in lowerCamelCase – MoxxiManagarm Nov 28 '19 at 18:55
  • they are still like this,(` public class Recipe : ICRUD { public Guid ID { get; set; } public Guid UnitID { get; set; } public string Title { get; set; } // ... plus Lists ... }`) only frontend object is like lowercase(almost) – StartingAgain Nov 28 '19 at 19:08
  • Sorry I didn't mean to say -not-. I did mean they should be written in lowerCamelCase – MoxxiManagarm Nov 28 '19 at 19:17
  • it should be `unitID` and you don't need to change your back end. – Eldar Nov 28 '19 at 19:55
  • The capital D is the problem. The back end should be `UnitId` that would be the standard convention – Charleh Nov 28 '19 at 20:16
  • I think asp.net-core camel cases by default, see [asp.net core 1.0 web api use camelcase](https://stackoverflow.com/q/38139607) for how to disable. Or if you are using asp.net-core 3.0 see [ASP.NET Core 3.0 System.Text.Json Camel Case Serialization](https://stackoverflow.com/q/58476681), because 3.0 uses a new serializer by default. – dbc Nov 28 '19 at 20:32

1 Answers1

0

The "thing" that is converting your data without your knowledge is the JSON serializer. In ASP.NET Core the default JSON serializer will convert pascal cased C# types into camel cased JSON. E.g. given this C# class

class Recipe
{
    public Guid ID { get; set; }
    public Guid UnitID { get; set; }
}

an instance will be converted to this JSON:

{
    "id": "...",
    "unitID": "..."
}

The reverse process happens when binding JSON to a C# class. Notice how the two occurrences of "id" are different.

You have several options:

  • You can use the default JSON serializer which maps to camel case and adjust your front-end code match the JSON this results in.
  • You can do same with a slight twist: Change "ID" to "Id" in C#. This will be less confusing because your JSON properties will then be id and unitId.
  • Decorate the properties on the C# class with attributes like [JsonProperty] (when using Json.NET) or [JsonPropertyName] (when using System.Text.Json) to take full control over how they they will be named in JSON.
  • You can configure the JSON serializer to not convert to camel case. The JSON property names will then match the C# property names. How you configure the JSON serializer depends on the version of ASP.NET Core you are using. This was changed in ASP.NET Core 3 where Json.NET was replaced by System.Text.Json.

In case you are using ASP.NET Core MVC 2.1 you can configure the Json.NET serializer used in Startup.ConfigureServices:

services.AddMvc()
    .AddJsonOptions(options => {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
        // Other changes to options.SerializerSettings ...
    });

Here I'm setting the contract resolver back to the default instead of the camel case version (CamelCasePropertyNamesContractResolver).

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256