【发布时间】:2020-09-22 02:23:14
【问题描述】:
上下文:
Cust 有一个发送以下 json 的服务。他可以轻松更改该查询的目标,但不能更改它自己的查询。
我必须构建一个接受如下 JSON 查询的 WebService。 虽然我处理 Json 没有问题,但我在尝试定义将接受这样的查询的方法/接口时遇到问题。
问题来自 Houses > Things:它是一个字符串字典,“objectThing”其中“objectThing”的属性值可能包含多种类型。
例如:
- 整数,
"Value": 42 - 字符串,
"Value": "Catty" - 字符串数组,
"Value": ["Book1", "Book2", "Book3"] - 对象,对象类型的有限列表
"Value": { "PeopleId": "1234ABCD", "Name": "John" } - 对象数组,对象类型有限列表的数组
价值对我来说不是动态的。它在我可以定义的有限类型列表中。"Value": [ { "PeopleId": "1234ABCD", "Name": "John" }, { "PeopleId": "0000AAAA", "Name": "Doe" } ]
Json 示例:
{
"RootID" : "0123456",
"FooID" : "0123456",
"BarID" : "0123456",
"Houses" :[
{
"OwnerId" : "0123456",
"Date" : 1890895600000,
"Location" : {
"Latitude" : -1,
"Longitude" : -1
},
"Things" :{
"1" :{
"Label": "Books",
"Type" : "List",
"Value": ["Book1", "Book2", "Book3"]
},
"2" :{
"Label": "Cat",
"Type" : "Text",
"Value": "Catty"
},
"3" :{
"Label": "A Number",
"Type" : "Int",
"Value": 42
},
"4" :{
"Label": "Peoples",
"Type" : "People",
"Value": [
{
"PeopleId": "1234ABCD",
"Name": "John"
},
{
"PeopleId": "0000AAAA",
"Name": "Doe"
}
]
}
}
},
{
"OwnerId" : "111111",
"Things" :{}
},
{
"OwnerId" : "000001",
"Things" :{}
}
]
}
以及类定义,如果我要将这个 Json 反序列化为适当的类型:
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class QueryRoot
{
[JsonProperty("RootID")]
public string RootId { get; set; }
[JsonProperty("FooID")]
public string FooId { get; set; }
[JsonProperty("BarID")]
public string BarId { get; set; }
[JsonProperty("Houses")]
public List<House> Houses { get; set; }
}
public partial class House
{
[JsonProperty("OwnerId")]
public string OwnerId { get; set; }
[JsonProperty("Date", NullValueHandling = NullValueHandling.Ignore)]
public long? Date { get; set; }
[JsonProperty("Location", NullValueHandling = NullValueHandling.Ignore)]
public Location Location { get; set; }
[JsonProperty("Things")]
public Dictionary<string, Thing> Things { get; set; }
}
public partial class Location
{
[JsonProperty("Latitude")]
public long Latitude { get; set; }
[JsonProperty("Longitude")]
public long Longitude { get; set; }
}
public partial class Thing
{
[JsonProperty("Label")]
public string Label { get; set; }
[JsonProperty("Type")]
public string Type { get; set; }
[JsonProperty("Value")]
public ThingValue Value { get; set; }
}
public partial class ValueClass
{
[JsonProperty("PeopleId")]
public string PeopleId { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
}
public partial struct ValueElement
{
public string String;
public ValueClass ValueClass;
public static implicit operator ValueElement(string String) => new ValueElement { String = String };
public static implicit operator ValueElement(ValueClass ValueClass) => new ValueElement { ValueClass = ValueClass };
}
public partial struct ThingValue
{
public List<ValueElement> AnythingArray;
public long? Integer;
public string String;
public static implicit operator ThingValue(List<ValueElement> AnythingArray) => new ThingValue { AnythingArray = AnythingArray };
public static implicit operator ThingValue(long Integer) => new ThingValue { Integer = Integer };
public static implicit operator ThingValue(string String) => new ThingValue { String = String };
}
public partial class QueryRoot
{
public static QueryRoot FromJson(string json) => JsonConvert.DeserializeObject<QueryRoot>(json, QuickType.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this QueryRoot self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
ThingValueConverter.Singleton,
ValueElementConverter.Singleton,
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
internal class ThingValueConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(ThingValue) || t == typeof(ThingValue?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.Integer:
var integerValue = serializer.Deserialize<long>(reader);
return new ThingValue { Integer = integerValue };
case JsonToken.String:
case JsonToken.Date:
var stringValue = serializer.Deserialize<string>(reader);
return new ThingValue { String = stringValue };
case JsonToken.StartArray:
var arrayValue = serializer.Deserialize<List<ValueElement>>(reader);
return new ThingValue { AnythingArray = arrayValue };
}
throw new Exception("Cannot unmarshal type ThingValue");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
var value = (ThingValue)untypedValue;
if (value.Integer != null)
{
serializer.Serialize(writer, value.Integer.Value);
return;
}
if (value.String != null)
{
serializer.Serialize(writer, value.String);
return;
}
if (value.AnythingArray != null)
{
serializer.Serialize(writer, value.AnythingArray);
return;
}
throw new Exception("Cannot marshal type ThingValue");
}
public static readonly ThingValueConverter Singleton = new ThingValueConverter();
}
internal class ValueElementConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(ValueElement) || t == typeof(ValueElement?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.String:
case JsonToken.Date:
var stringValue = serializer.Deserialize<string>(reader);
return new ValueElement { String = stringValue };
case JsonToken.StartObject:
var objectValue = serializer.Deserialize<ValueClass>(reader);
return new ValueElement { ValueClass = objectValue };
}
throw new Exception("Cannot unmarshal type ValueElement");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
var value = (ValueElement)untypedValue;
if (value.String != null)
{
serializer.Serialize(writer, value.String);
return;
}
if (value.ValueClass != null)
{
serializer.Serialize(writer, value.ValueClass);
return;
}
throw new Exception("Cannot marshal type ValueElement");
}
public static readonly ValueElementConverter Singleton = new ValueElementConverter();
}
我已经有一个处理 Json 的 WCF 服务。它工作正常,问题是声明将接受这种查询的方法/接口。 如果 WCF Web 服务是一个限制因素,或者(ASP.NET/Core)Web API 提供了更简单的路径,那么它是受欢迎的。
【问题讨论】:
标签: c# json web-services wcf asp.net-web-api