C# 如何在反序列化过程中以编程方式选择构造函数?
我想反序列化一个C# 如何在反序列化过程中以编程方式选择构造函数?,c#,json.net,C#,Json.net,我想反序列化一个System.Security.Claims.Claims对象,序列化方式如下: { "Issuer" : "LOCAL AUTHORITY", "OriginalIssuer" : "LOCAL AUTHORITY", "Type" : "http://my.org/ws/2015/01/identity/claims/mytype", "Value" : "myvalue", "ValueType" : "http://www.w3.o
System.Security.Claims.Claims
对象,序列化方式如下:
{
"Issuer" : "LOCAL AUTHORITY",
"OriginalIssuer" : "LOCAL AUTHORITY",
"Type" : "http://my.org/ws/2015/01/identity/claims/mytype",
"Value" : "myvalue",
"ValueType" : "http://www.w3.org/2001/XMLSchema#string"
}
我得到的是一个JsonSerializationException
:
找不到用于类型的构造函数
系统。安全。索赔。索赔。一个类应该有一个默认值
构造函数,一个带参数的构造函数或一个标记为
使用JsonConstructor属性
经过一些调查,我终于理解了上述消息中一个的含义:JSON反序列化程序无法找到正确的构造函数,因为在声明
类型的情况下,多个构造函数都有参数(尽管存在一个构造函数,其参数与上述属性完全匹配)
有没有一种方法可以告诉反序列化器选择哪个构造函数而不向该mscorlib类型添加JsonConstructor
属性
丹尼尔·哈兰用一种新的方法解决了这个问题。现在有没有办法在不修改Json.NET的情况下解决这个问题?如果无法向目标类添加
[JsonConstructor]
属性(因为您不拥有代码),那么通常的解决方法是按照@James Thorpe在注释中的建议创建一个自定义的JsonConverter
。这很简单。您可以将JSON加载到一个JObject
,然后从中选择各个属性来实例化您的Claim
实例。以下是您需要的代码:
class ClaimConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(System.Security.Claims.Claim));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
string type = (string)jo["Type"];
string value = (string)jo["Value"];
string valueType = (string)jo["ValueType"];
string issuer = (string)jo["Issuer"];
string originalIssuer = (string)jo["OriginalIssuer"];
return new Claim(type, value, valueType, issuer, originalIssuer);
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
要使用转换器,只需将其实例传递给JsonConvert.DeserializeObject()
方法调用:
Claim claim = JsonConvert.DeserializeObject<Claim>(json, new ClaimConverter());
Claim-Claim=JsonConvert.DeserializeObject(json,new ClaimConverter());
Fiddle:另一种方法,至少对非密封类有效,就是对它进行子类化,但只使用您感兴趣的构造函数:
class MyClaim : Claim {
public MyClaim(string type, string value, string valueType, string issuer, string originalIssuer):
base(type, value, valueType, issuer, originalIssuer){}
}
然后,您可以在没有帮助器类的情况下反序列化到此对象,然后将其视为基类型
Claim claim = JsonConvert.DeserializeObject<MyClaim>(json);
ClaimConverter
已与打包
命名空间:IdentityServer4.Stores.Serialization
使用示例:
JsonConvert.DeserializeObject<T>(value, new IdentityServer4.Stores.Serialization.ClaimConverter());
JsonConvert.DeserializeObject(值,新标识服务器4.Stores.Serialization.ClaimConverter());
谢谢@chen zhe,这是包括公认答案在内的上述帖子中最简单的解决方案。
在我的例子中,我需要对整个客户端(Is4模型)进行反序列化,包括声明,声明只是客户端的子类之一
这是我尝试过的,并且做得很好-
[HttpPost]
public async Task<ActionResult<Client>> Post(Object model)
{
var clientString = model.ToString();
Client client = JsonConvert.DeserializeObject<Client>(clientString, new ClaimConverter());
}
[HttpPost]
公共异步任务绑定方法
你能发布你的代码+构造函数吗?很遗憾,我现在没有时间讨论它,但是你可以重写并实现你自己的JsonConverter
。这可能有助于您入门,但您需要进一步阅读json字段,然后再调用ConstructorBank,以获取使用JsonCreationConverter
返回上一个答案的链接!很高兴有人有时间恰当地回答:)这正是我要找的!(感谢您修复了我问题中的错误名称空间!;-)@CodeFox没问题;很高兴我能帮忙!我的救世主!!!感谢您的解决方案+1感谢您分享您的备选方法!我相信在某些情况下,它们比自定义转换器更合适。如果您已经在使用IdentityServer4,这可能是最简单的方法。谢谢
[HttpPost]
public async Task<ActionResult<Client>> Post(Object model)
{
var clientString = model.ToString();
Client client = JsonConvert.DeserializeObject<Client>(clientString, new ClaimConverter());
}