有什么方法可以让 Newtonsoft.Create 在界面上调用您的自定义创建方法吗?

Is there some way to have Newtonsoft.Create call your custom creation method on an interface?

我正在使用 Hangfire 到 运行 我的自定义 interface 的多个任务,我们称之为 IType。但是,由于 Hangfire 序列化该方法,从而破坏了该类型的实例,因此当它尝试调用它时,我收到如下错误消息:

Newtonsoft.Json.JsonSerializationException: Could not create an instance of type IType. Type is an interface or abstract class and cannot be instantiated. Path 'Something', line 1, position 17. at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(...

我认为解决这个问题的一种方法是让作为我的 interface 实例的每个 class 可以存储它的 fully qualified domain name,然后我可以使用 reflection 来return 它是它需要的类型,唯一的问题是我不知道如何让 Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject() 调用我的反序列化方法。为了完成这项工作,我需要一些 attribute 或一些特定的方法名称吗?

您需要指定包含合适 TypeNameHandling 值的 JsonSerializerSettings。这会将 JSON 中的完全限定名称嵌入到 $type 属性 中,然后可以使用它来反序列化。这是一个完整的例子:

using System;
using Newtonsoft.Json;

interface IFoo
{
    void Method();
}

class Foo1 : IFoo
{
    public string Name { get; set; }
    public void Method() => Console.WriteLine("Method in Foo1");
}

class Foo2 : IFoo
{
    public int Value { get; set; }
    public void Method() => Console.WriteLine("Method in Foo2");
}

class Root
{
    public IFoo First { get; set; }
    public IFoo Second { get; set; }
}

class Test
{
    static void Main()
    {
        Root root = new Root
        { 
            First = new Foo1 { Name = "Fred" },
            Second = new Foo2 { Value = 10 }
        };
        var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
        string json = JsonConvert.SerializeObject(root, settings);

        Console.WriteLine(json);

        Root root2 = JsonConvert.DeserializeObject<Root>(json, settings);
        root2.First.Method();
        root2.Second.Method();
    }
}

输出,显示 JSON 以及 Root 中的接口属性已被适当反序列化的事实:

{"$type":"Root, Test","First":{"$type":"Foo1, Test","Name":"Fred"},"Second":{"$type":"Foo2, Test","Value":10}}
Method in Foo1
Method in Foo2

您可能想使用其他 TypeNameHandling 值来代替 All - 有关详细信息,请参阅 the documentation

为了完整性,将@Daisy 对 Hangfire 的回答应用到您的 StartUp(这是针对 .NET Core):

app.UseHangfireDashboard("/hangfire", ...);

app.UseHangfireServer(...);

JobHelper.SetSerializerSettings(new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All
});

对于 .Net 核心

GlobalConfiguration.Configuration.UseSerializerSettings(new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.All
            })