如何编写一个接受具有“多类型属性”的 Json 的 WebService?
Posted
技术标签:
【中文标题】如何编写一个接受具有“多类型属性”的 Json 的 WebService?【英文标题】:How to write a WebService that will accept Json with "Multi Type Property"? 【发布时间】: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 提供了更简单的路径,那么它是受欢迎的。
【问题讨论】:
相关:***.com/questions/11465858/…. Anonymous and Weakly-Typed Objects with web api 【参考方案1】:您可以接收 JSON 字符串并将其转换为对象。这是一个演示:
[WebMethod]
public string HelloWorld()
Stream s = HttpContext.Current.Request.InputStream;
byte[] b = new byte[s.Length];
s.Read(b, 0, (int)s.Length);
string jsontext = Encoding.UTF8.GetString(b);
var productProperty = JsonHelper.JsonDeserialize<School>(jsontext); //Deserialize JSON strings to objects
return "Hello World";
这是WebService中的方法。
[DataContract]
public class School
[DataMember]
public int Clas-s-roomId set; get;
[DataMember]
public List<Student> StudentList set; get;
[DataContract]
public class Student
[DataMember]
public int StudentId set; get;
[DataMember]
public string StudentName set; get;
这是JSON字符串要转换的对象。
public class JsonHelper
public static string JsonSerializer<T>(T t)
var ser = new DataContractJsonSerializer(typeof(T));
var ms = new MemoryStream();
ser.WriteObject(ms, t);
string jsonString = Encoding.UTF8.GetString(ms.ToArray());
ms.Close();
return jsonString;
public static T JsonDeserialize<T>(string jsonString)
var ser = new DataContractJsonSerializer(typeof(T));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
var obj = (T)ser.ReadObject(ms);
return obj;
为了将 JSON 字符反序列化为对象,有很多开源类库。我用的是.net 3.5或以上版本自带的DatacontractJsonSerializer。我写了一个JsonHelper类。
【讨论】:
WebInvoke(Method = "POST")
并使用带有RequestContext.RequestMessage.GetBody
的正文。是我没有考虑过的事情。并要求将其发送为Content-Type:text/plain
。
我也会给HttpContext.Current.Request.InputStream
。
好吧,您可以预计在此之前几周会遇到沙盒。这部分似乎没有被最终客户使用,虽然它在 100% 的覆盖范围内,但我不确定是否有人会活得够久才能看到它。我会尝试一下个人发展的工作。但是没找到时间和精力。以上是关于如何编写一个接受具有“多类型属性”的 Json 的 WebService?的主要内容,如果未能解决你的问题,请参考以下文章
Phpmyadmin 仅接受来自具有多个输入值的 json 数组中的一个条目
如何在 express 和 bodyParser 中接受 application/csp-report 作为 json?