2

im getting StackOverflowException in method JsonTypeConverter.ConvertTo when calling Project.Settings.Default.Save()

i think this it is because method JsonConvert.SerializeObject detect typeconverter on model type and calls it internally ...

whats the correct way to write this? (only way i can think of is storing string in settings and do serialization/deserialization manualy ...)

public class JsonTypeConverter<TModel> : TypeConverter { #region Overrides of TypeConverter public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return sourceType == typeof(string); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { return destinationType == typeof(string); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is string strValue) { return JsonConvert.DeserializeObject<TModel>(strValue); } return base.ConvertFrom(context, culture, value); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string) && value is TModel model) { return JsonConvert.SerializeObject(model, Formatting.None); } return base.ConvertTo(context, culture, value, destinationType); } #endregion } namespace Model { [TypeConverter(typeof(JsonTypeConverter<DataModel>))] [SettingsSerializeAs(SettingsSerializeAs.String)] public class DataModel { public string Value { get; set; } } } 

content of 'Properties/Settings.settings':

<?xml version='1.0' encoding='utf-8'?> <SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Builder.Properties" GeneratedClassName="Settings"> <Profiles /> <Settings> <Setting Name="DataSource" Type="Model.DataModel" Scope="User"> <Value Profile="(Default)" /> </Setting> </Settings> </SettingsFile> 

PS: Any suggestions for this question title?

1 Answer 1

2

The problem is that both the JsonConverter and the Settings Serializer are using the TypeConverter attribute to tell them how to serialize the object. When JsonConverter tries to serialize the object it will end up calling itself again through your custom converter and eventually get the stack overflow.

To solve this in your converter you have to tell the JsonConverter to not use the type TypeConverterAttribute and to just do the default object serialization. This is the way I found to accomplish this:

public class JsonTypeConverter<TModel> : TypeConverter { /* rest of your class ... */ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is string strValue) { return JsonConvert.DeserializeObject<TModel>(strValue, new JsonSerializerSettings { ContractResolver = new CustomContractResolver(), }); } return base.ConvertFrom(context, culture, value); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string) && value is TModel model) { return JsonConvert.SerializeObject(model, new JsonSerializerSettings { ContractResolver = new CustomContractResolver(), }); } return base.ConvertTo(context, culture, value, destinationType); } } class CustomContractResolver : DefaultContractResolver { protected override JsonContract CreateContract(Type objectType) { if (typeof(DataModel).IsAssignableFrom(objectType)) { return this.CreateObjectContract(objectType); } return base.CreateContract(objectType); } } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.