Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在反序列化过程中以编程方式选择构造函数?_C#_Json.net - Fatal编程技术网

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());
}