Newtonsoft.Json
Newtonsoft.Json copied to clipboard
Android .net6 project throw exception when serilaize Tuple in Release mode (v13.0.2)
Steps
- Need create Android project on .net6
- Add reference to Newtonsoft.Json lib 13.0.2
- Create simple class with Tuple and try to serialize it.
Result: Debug mode works well. Release mode will throw exception.
Code simple
var tuple = new Tuple<decimal, string>(1, "one");
var json = JsonConvert.SerializeObject(tuple, Formatting.Indented);
Actual behavior
Code in release mode will trow exception after try serialize
Newtonsoft.Json.JsonSerializationException
Newtonsoft.Json.JsonSerializationException: A member with the name '' already exists on 'System.Tuple`2[System.Decimal,System.String]'. Use the JsonPropertyAttribute to specify another name.
Newtonsoft.Json.Serialization.JsonPropertyCollection.AddProperty(JsonProperty property)
Newtonsoft.Json.Serialization.DefaultContractResolver.CreateConstructorParameters(ConstructorInfo constructor, JsonPropertyCollection memberProperties)
Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract(Type objectType)
Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract(Type objectType)
System.Collections.Concurrent.ConcurrentDictionary`2[[System.Type, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Newtonsoft.Json.Serialization.JsonContract, Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed]].GetOrAdd(Type , Func`2 )
Newtonsoft.Json.Utilities.ThreadSafeStore`2[[System.Type, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Newtonsoft.Json.Serialization.JsonContract, Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed]].Get(Type key)
Newtonsoft.Json.Serialization.DefaultContractResolver.ResolveContract(Type type)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.WriteStartArray(JsonWriter writer, Object values, JsonArrayContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
Newtonsoft.Json.JsonConvert.SerializeObjectInternal(Object value, Type type, JsonSerializer jsonSerializer)
Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Type type, Formatting formatting, JsonSerializerSettings settings)
Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Formatting formatting, JsonSerializerSettings settings)
Expected behavior
Code will serialize in release mode without exception
Are you by any chance trimming when building in Release mode?
@elgonzo Yes, I think problem is in trimming.
When I add <PublishTrimmed>false</PublishTrimmed>
to project file, then application works fine in release mode, but size of our application is increased from 80 Mb to 190Mb. This way is not preferred.
Then i would strongly recommend - if feasible - switching from Newtonsoft.Json to System.Text.Json, although i can't predict the success chance due to being oblivious of your project. Reflection-based serializers like Newtonsoft.Json are always a big problem regarding trimming (and native AOT compiling, for that matter), unfortunately.
I don't think switching to System.Text.Json is the best solution. I prefer to use Newtonsoft.Json :)
At current moment I've fixed problem by adding System.Private.CoreLib
lib to ignore list for trimming to .proj file
<Target Name="ConfigureTrimming" BeforeTargets="PrepareForILLink">
<ItemGroup>
<ManagedAssemblyToLink Condition="'%(Filename)' == 'System.Private.CoreLib'">
<IsTrimmable>false</IsTrimmable>
</ManagedAssemblyToLink>
</ItemGroup>
</Target>
Just my 5 cents, as a newish .net programmer, but lifelong programmer. I am having the same problem with a WASM client, but only when deployed to Azure Webapp.
When running locally there is no problem with retrieving a tuple that has an empty string as a parameter ( boolean, string="") - but it will throw exception only in release mode, eg. deployed as web app.
I guess my main contribution to this discussion is that it occurred in a WASM app, and not just android.
it also did not occur under .net 5 when we deployed to Azure Web App - only after migrating to .net 6 & .net 7
api Return -> Item1=true, Item2=""
failing code: var result = await _httpClient.GetFromJsonAsync<Tuple<bool, string>>(apiPath)
Result I then tried to use Newtonsoft, and System.Text.Json to deserialize json, using _httpClient.GetStringAsync(api_path),
but it always gave a problem with the empty string after publishing to azure web app. either with nullparameter, or nullname, or something like that. i can resetup environment if needed.
hope that helps