【问题标题】:Deserialize interface in request body based on specific condition asp.net core根据特定条件在请求正文中反序列化接口 asp.net core
【发布时间】:2019-09-23 16:41:25
【问题描述】:

我正在使用 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,
        ...
    }
}

如果location type为1,ILocation将反序列化为StreetLocation,如果location type为2则反序列化为GeoCoordinateLocation

请问有什么解决办法吗? IModelBinder 在 asp.net core 中可以做到吗?

谢谢

【问题讨论】:

    标签: c# asp.net-core asp.net-core-webapi asp.net-core-2.1


    【解决方案1】:

    您可以创建一个自定义 JsonConverter 来执行此操作。

    1. 创建一个辅助函数来在运行时解析位置类型:Type ResolveILocationTypeRuntime(typeCode)
    2. 创建一个辅助函数以在运行时创建某个特定类型的实例:DeserializeLocationRuntime(json, type)
    3. 根据当前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 );
        }
    }
    

    并用JsonConverterAttribute 装饰您的Address 属性:

    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,
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-02
      • 2019-09-17
      • 2019-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-19
      相关资源
      最近更新 更多