Reputation: 53
I have a .net core 3.0 preview 6 MVC application and API. In the API, I am using a third party class library (that I can't change) which defines the class properties as Pascal cased with the JsonProperty, PropertyName snaked cased eg...
public class Company
{
[JsonProperty(PropertyName = "company_name")]
public string CompanyName { get; set; }
more properties ….
}
The problem is that when I supply these via the api they reach the MVC app as Camel case (the default for .net core 3)... and then can't be Deserialized back the to the class model.
Not matter what I try, the API always produces camel cased JSon, eg. the property above will be called companyName.
I tried,
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver { NamingStrategy = new CamelCaseNamingStrategy { OverrideSpecifiedNames = true } };
options.SerializerSettings.ContractResolver = new DefaultContractResolver { NamingStrategy = new DefaultNamingStrategy { OverrideSpecifiedNames = true } };
I've tried NamingStrategy = null on both camel and default ContractResolver. Also tried setting the NamingStrategy to Snake
But nothing changes the outputted Json, it's always camelcased.
I can see the resulting string is camel cased by using ReadAsStringAsync in the MVC app... I when I use JsonConvert.DeserializeObject, the properties are always null, because neither the name or Json PropertyName match the names in the resulting string.
Is this a bug in .net core previews or am missing something else?
Thanks Mustafa, your suggested duplicate is kinda the same issue with kinda the same solutions that I've already tried i.e. changing the setting of the ContractResolver / NamingStrategy to different values.... however, My issue is that none of the suggested solutions appear to have any effect on the API response it always comes back as camelCased.
Interestingly, when I change the NamingStrategy to say Snake, Swagger shows the schema as set (i.e. snake) but the actual output is still camelCased!!!
Also, I have no control over the base classes so I can't change the names / json properties of the classes I'm attempting to transmit.
Upvotes: 3
Views: 2212
Reputation: 778
Try this:
builder.Services.AddControllers().AddJsonOptions(jsonOptions =>
{
//To prevent pascal case properties from being renamed to camel case (default behavior) during serialization
jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null;
});
I use this in .NET 7.0 and it is working.
Upvotes: 0
Reputation: 1595
I came across this issue when converting my api from .netcore 2.2 to .netcore 3.
My api was returning responses converted to camelCase even though my models were PascalCase.
In startup.cs
:
.netcore 2:
services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
.netcore 3:
// keeps the casing of models when serializing to json (default is converting to camelCase)
services.AddMvc()
.AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
This means you don't need to import newtonsoft.json.
Upvotes: 0
Reputation: 148
Microsoft.AspNetCore.Mvc.NewtonsoftJson
Doesn't come up default. Try to install this nuget package manually to your service project. That worked for me.
Upvotes: 3
Reputation: 53
Not really sure where the issue was but had a feeling it was something to do with the mix of Newtonsoft.Json, Json.Net, Swagger and the fact that I was using the Microsoft.AspNet.WebApi.Client to get the HttpContent.ReadAsAsync….all having different Json's
So, I decided to start again with a real simple app and api using the new System.Text.Json included in .Net Core preview (and none of the other libraries). Also not using the HttpContent.ReadAsAsync but instead reading the response as a string and then deserializing with the new library (System.Text.Json)
Doing this I had exactly the same issue …. neither the property name or Json PropertyName match the names in the api returned string i.e class property name = "CompanyName" and Json PropertyName = "company_name" and the api supplied json name = "companyName". So the value isn't set when Deserializing.
However, in the new System.Text.Json options I'm able to specify PropertyNameCaseInsensitive = true, which fixes my problem, now companyName does equal CompanyName and the class model values are set correctly when Deserializing.
So my api call methods end up looking like this...
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, string.Format("Companies?aCompanyName={0}", aCompanyName));
using HttpResponseMessage response = await Client.SendAsync(request);
string content = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode == false)
{
throw new ApiException
{
StatusCode = (int)response.StatusCode,
Content = content
};
}
_JsonOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
return JsonSerializer.Deserialize<IEnumerable<Company>> (content, _JsonOptions);
I did attempt to set the JsonSerializerOptions globally in the startup class but this didn't work.
I've transferred this approach to all my http calls in my app, removed all references to Newtonsoft and it all works.
Upvotes: 0
Reputation: 713
Try this and remove all JsonProperty
attributes.
From now if you don't specify any JsonProperty
y it will act like this CompanyName
like company_name
or ProPertyName1
like pro_perty_name1
. In this examples will explain the idea of the property name.
And be sure add this configuration to bottom of the ConfigureServices
method, it may overwritten by another things i dont know.
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() };
});
Upvotes: 1