Reputation: 545
I have to get back an object the frontend is sending me. Thing is, front team wanted their component to be as generic as it can be so, in the dto, i'll recieve a Value
property that can be different things (a boolean, a string, a list a strings, a numeric value...), as following :
"conditions": [
{
"alias": "FSTNM",
"providerKey": "Marketing",
"hasValue": true,
"conditionType": "Text",
"values": "john",
"startDate": null,
"endDate": null
},
{
"alias": "LSTNM",
"providerKey": "Marketing",
"hasValue": true,
"conditionType": "Text",
"values": null,
"startDate": null,
"endDate": null
},
{
"alias": "BTHDT",
"providerKey": "Marketing",
"hasValue": true,
"conditionType": "DateTime",
"values": null,
"startDate": "02-10-1980",
"endDate": "17-08-1989"
},
{
"alias": "AMECH",
"providerKey": "Custom",
"hasValue": true,
"conditionType": "Boolean",
"values": true,
"startDate": null,
"endDate": null
},
{
"alias": "CMBCH",
"providerKey": "Custom",
"hasValue": true,
"conditionType": "Number",
"values": 2,
"startDate": null,
"endDate": null
},
{
"alias": "FVRDR",
"providerKey": "Custom",
"hasValue": true,
"conditionType": "List",
"values": [
1,
3
],
"startDate": null,
"endDate": null
}
]
So, I tried to set the Values
property as object
like this :
public class DataTableFilterValueDTO
{
public string Alias { get; set; }
public string ProviderKey { get; set; }
public bool HasValue { get; set; }
public string ConditionType { get; set; }
public object Values { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
}
It seems that it works. When the request reack my controller, Values
seems to be the right type, and depending on conditionType
, I can cast it to the object i'm supposed to retrieve, like this :
var values = condition.Values as string;
var values = condition.Values as bool;
var values = condition.Values as List<string>;
But is this a thing to do?
I mean, it does not feel right using this but I've never worked with the object
type and can't really tell when it's good to use it.
Upvotes: 1
Views: 62
Reputation: 3576
You could implement a Custom JsonConverter
. To do this, declare your class as abstract, and define a class that inherits it for each data type you expect to receive, like so:
[JsonConverter(typeof(ValueConverter))]
public abstract class Value
{
public string Alias { get; set; }
public string ProviderKey { get; set; }
public bool HasValue { get; set; }
public string ConditionType { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
}
public class BooleanValue : Value { public bool? Values { get; set; } }
public class ListValue : Value { public List<string> Values { get; set; } }
public class StringValue : Value { public string Values { get; set; } }
public class DateTimeValue : Value { public DateTime? Values { get; set; } }
public class IntegerValue : Value { public int? Values { get; set; } }
Then you need to define your custom JsonConverter
where you perform the type conversion according to the value of the conditionType
property:
public class ValueConverter : JsonConverter
{
static readonly JsonSerializerSettings SpecifiedSubclassConversion = new JsonSerializerSettings() { ContractResolver = new CustomResolver() };
public override bool CanConvert(Type objectType) => objectType == typeof(Value);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject obj = JObject.Load(reader);
return (obj["conditionType"].Value<string>()) switch
{
"Text" => JsonConvert.DeserializeObject<StringValue>(obj.ToString(), SpecifiedSubclassConversion),
"DateTime" => JsonConvert.DeserializeObject<DateTimeValue>(obj.ToString(), SpecifiedSubclassConversion),
"Boolean" => JsonConvert.DeserializeObject<BooleanValue>(obj.ToString(), SpecifiedSubclassConversion),
"Number" => JsonConvert.DeserializeObject<IntegerValue>(obj.ToString(), SpecifiedSubclassConversion),
"List" => JsonConvert.DeserializeObject<ListValue>(obj.ToString(), SpecifiedSubclassConversion),
_ => throw new Exception("Unknown conditionType"),
};
throw new NotImplementedException();
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public class CustomResolver: DefaultContractResolver
{
protected override JsonConverter ResolveContractConverter(Type objectType)
{
if (typeof(Value).IsAssignableFrom(objectType) && !objectType.IsAbstract)
return null;
return base.ResolveContractConverter(objectType);
}
}
And finally the usage:
foreach (var value in JsonConvert.DeserializeObject<List<Value>>(json))
{
if (value is StringValue)
{
string s = ((StringValue)value).Values;
}
}
Upvotes: 1