我正在使用ASP.Net Core 2.2
制作一个小型Web应用程序。
当前我有一个界面:
public interface ILocation {
public int Type {get;}
}
有2个类实现此ILocation
接口:
public class StreetLocation: ILocation {
public int Type {get;set;}
public string City {get;set;}
public string State {get;set;}
}
public class GeoCoordinateLocation: ILocation {
public int Type {get;set;}
public double Latitude{get;set;}
public double Longitude{get;set;}
}
我有一个类StudentViewModel
,用于接收从客户端发送到服务器的信息。此类的实现如下:
public class StudentViewModel {
public Guid Id {get;set;}
public string Name {get;set;}
public ILocation Address {get;set;}
}
我从客户端发送的请求将如下所示:
{
"id": "0da28089-c0da-41a7-a47f-89b54d52822b",
"name": "Student 01",
"location": {
"type": 1,
...
}
}
如果位置类型为1,则ILocation
将反序列化为StreetLocation
,如果位置类型为GeoCoordinateLocation
,则反序列化。 2。
请问有什么解决办法吗?
可以由IModelBinder
在asp.net核心中完成吗?
谢谢
答案 0 :(得分:1)
您可以创建一个自定义JsonConverter
来做到这一点。
Type ResolveILocationTypeRuntime(typeCode)
DeserializeLocationRuntime(json, type)
type
读取Json或写Json。实施:
public class CustomLocationConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var json= JToken.ReadFrom(reader);
var typeToken = json.SelectToken("type"); // or ??json.SelectToken("Type");
if(typeToken ==null) return null; //
var type= ResolveILocationTypeRuntime((int)typeToken);
var location = DeserializeLocationRuntime(json, type);
return location;
}
private Type ResolveILocationTypeRuntime(int type)
{
switch (type)
{
case 1:
return typeof(StreetLocation);
case 2:
return typeof(GeoCoordinateLocation);
default:
throw new ArgumentOutOfRangeException("type should be 1|2");
}
}
private ILocation DeserializeLocationRuntime(JToken json, Type locationType)
{
MethodInfo mi = typeof(JToken)
.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(m => m.Name == "ToObject" && m.GetParameters().Length == 0 && m.IsGenericMethod)
.FirstOrDefault()
?.MakeGenericMethod(locationType);
var location = mi?.Invoke(json, null);
return (ILocation)location;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var location = value as ILocation;
var type = ResolveILocationTypeRuntime(location.Type);
serializer.Serialize(writer, location, type );
}
}
并用Address
装饰您的JsonConverterAttribute
属性:
public class StudentViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
[JsonProperty("location")]
[JsonConverter(typeof(CustomLocationConverter))]
public ILocation Address { get; set; }
}
控制器操作:
public IActionResult Test([FromBody]StudentViewModel model)
{
return Json(model);
}
请求:
POST https://localhost:5001/home/test HTTP/1.1
Content-Type: application/json
{
"id": "0da28089-c0da-41a7-a47f-89b54d52822b",
"name": "Student 01",
"location": {
"type":2,
"latitude": 1.2,
"longitude":3.1415926,
}
}