当前位置: 首页 > 面试题库 >

SignalR类型名称处理

唐宏壮
2023-03-14
问题内容

我正在尝试让SignalR与自定义JsonSerializerSettings一起处理其有效负载,特别是我正在尝试设置TypeNameHandling = TypeNameHandling.Auto

这个问题似乎是,该SignalR中使用的设置hubConnection.JsonSerializer,并GlobalHost.DependencyResolver.Resolve<JsonSerializer>()为它的内部数据结构以及它然后导致各种混乱的(当我设置内部服务器崩溃TypeNameHandling.All的最粗鲁的例子,但TypeNameHandling.Auto我也得问题,特别是当IProgress<>回调参与)。

有任何解决方法,还是我做错了?

示例代码演示:

服务器:

class Program
{
    static void Main(string[] args)
    {
        using (WebApp.Start("http://localhost:8080"))
        {
            Console.ReadLine();
        }
    }
}

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var hubConfig = new HubConfiguration()
        {
            EnableDetailedErrors = true
        };
        GlobalHost.DependencyResolver.Register(typeof(JsonSerializer), ConverterSettings.GetSerializer);
        app.MapSignalR(hubConfig);
    }
}

public interface IFoo
{
    string Val { get; set; }
}
public class Foo : IFoo
{
    public string Val { get; set; }
}

public class MyHub : Hub
{
    public IFoo Send()
    {
        return new Foo { Val = "Hello World" };
    }
}

客户:

class Program
{
    static void Main(string[] args)
    {
        Task.Run(async () => await Start()).Wait();
    }

    public static async Task Start()
    {
        var hubConnection = new HubConnection("http://localhost:8080");
        hubConnection.JsonSerializer = ConverterSettings.GetSerializer();
        var proxy = hubConnection.CreateHubProxy("MyHub");
        await hubConnection.Start();
        var result = await proxy.Invoke<IFoo>("Send");
        Console.WriteLine(result.GetType());
    }

共享:

public static class ConverterSettings
{
    public static JsonSerializer GetSerializer()
    {
        return JsonSerializer.Create(new JsonSerializerSettings()
        {
            TypeNameHandling = TypeNameHandling.All
        });
    }
}

问题答案:

这可以通过利用您的类型和SignalR类型在不同的程序集中的事实来完成。这个想法是要创建一个JsonConverter适用于
程序集中所有类型的 。当在对象图中(可能是根对象)首先遇到某个程序集中jsonSerializer.TypeNameHandling = TypeNameHandling.Auto的类型时,转换器将临时设置,然后对该类型进行标准序列化,并在一段时间内禁用自身以防止无限递归:

public class PolymorphicAssemblyRootConverter : JsonConverter
{
    [ThreadStatic]
    static bool disabled;

    // Disables the converter in a thread-safe manner.
    bool Disabled { get { return disabled; } set { disabled = value; } }

    public override bool CanWrite { get { return !Disabled; } }

    public override bool CanRead { get { return !Disabled; } }

    readonly HashSet<Assembly> assemblies;

    public PolymorphicAssemblyRootConverter(IEnumerable<Assembly> assemblies)
    {
        if (assemblies == null)
            throw new ArgumentNullException();
        this.assemblies = new HashSet<Assembly>(assemblies);
    }

    public override bool CanConvert(Type objectType)
    {
        return assemblies.Contains(objectType.Assembly);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        using (new PushValue<bool>(true, () => Disabled, val => Disabled = val)) // Prevent infinite recursion of converters
        using (new PushValue<TypeNameHandling>(TypeNameHandling.Auto, () => serializer.TypeNameHandling, val => serializer.TypeNameHandling = val))
        {
            return serializer.Deserialize(reader, objectType);
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        using (new PushValue<bool>(true, () => Disabled, val => Disabled = val)) // Prevent infinite recursion of converters
        using (new PushValue<TypeNameHandling>(TypeNameHandling.Auto, () => serializer.TypeNameHandling, val => serializer.TypeNameHandling = val))
        {
            // Force the $type to be written unconditionally by passing typeof(object) as the type being serialized.
            serializer.Serialize(writer, value, typeof(object));
        }
    }
}

public struct PushValue<T> : IDisposable
{
    Action<T> setValue;
    T oldValue;

    public PushValue(T value, Func<T> getValue, Action<T> setValue)
    {
        if (getValue == null || setValue == null)
            throw new ArgumentNullException();
        this.setValue = setValue;
        this.oldValue = getValue();
        setValue(value);
    }

    #region IDisposable Members

    // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
    public void Dispose()
    {
        if (setValue != null)
            setValue(oldValue);
    }

    #endregion
}

然后在启动时,将此转换器添加到默认转换器中JsonSerializer,传入要"$type"应用的程序集。

更新资料

如果出于某种原因在启动时不方便传递程序集列表,则可以通过启用转换器objectType.Namespace。居住在指定名称空间中的所有类型都将自动使用序列化TypeNameHandling.Auto

或者,您可以引入Attribute其目标的组件,类或接口,使TypeNameHandling.Auto当与适当的转换器结合使用:

public class EnableJsonTypeNameHandlingConverter : JsonConverter
{
    [ThreadStatic]
    static bool disabled;

    // Disables the converter in a thread-safe manner.
    bool Disabled { get { return disabled; } set { disabled = value; } }

    public override bool CanWrite { get { return !Disabled; } }

    public override bool CanRead { get { return !Disabled; } }

    public override bool CanConvert(Type objectType)
    {
        if (Disabled)
            return false;
        if (objectType.Assembly.GetCustomAttributes<EnableJsonTypeNameHandlingAttribute>().Any())
            return true;
        if (objectType.GetCustomAttributes<EnableJsonTypeNameHandlingAttribute>(true).Any())
            return true;
        foreach (var type in objectType.GetInterfaces())
            if (type.GetCustomAttributes<EnableJsonTypeNameHandlingAttribute>(true).Any())
                return true;
        return false;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        using (new PushValue<bool>(true, () => Disabled, val => Disabled = val)) // Prevent infinite recursion of converters
        using (new PushValue<TypeNameHandling>(TypeNameHandling.Auto, () => serializer.TypeNameHandling, val => serializer.TypeNameHandling = val))
        {
            return serializer.Deserialize(reader, objectType);
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        using (new PushValue<bool>(true, () => Disabled, val => Disabled = val)) // Prevent infinite recursion of converters
        using (new PushValue<TypeNameHandling>(TypeNameHandling.Auto, () => serializer.TypeNameHandling, val => serializer.TypeNameHandling = val))
        {
            // Force the $type to be written unconditionally by passing typeof(object) as the type being serialized.
            serializer.Serialize(writer, value, typeof(object));
        }
    }
}

[System.AttributeUsage(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Interface)]
public class EnableJsonTypeNameHandlingAttribute : System.Attribute
{
    public EnableJsonTypeNameHandlingAttribute()
    {
    }
}

注意-已通过各种测试用例进行了测试,但未对SignalR本身进行过测试,因为我目前尚未安装它。

TypeNameHandling 警告

使用时TypeNameHandling,请注意Newtonsoft文档中的这一警告:

当您的应用程序从外部源反序列化JSON时,应谨慎使用TypeNameHandling。反序列化除None以外的其他值时,应使用自定义SerializationBinder验证传入的类型。



 类似资料:
  • 我需要在使用EasyNetQ的微服务和使用Spring AMQP的之间发送消息。 问题在于properties消息,Spring Boot Amqp中的类型位于propertyheaders容器中,而在EasynetQ中,则来自名为的其他属性。 谁能告诉我,我需要定制什么,让Comunication他们以及?

  • 问题内容: 我正在尝试验证并保存具有以下结构的Passport配置文件: http://passportjs.org/guide/profile/ 这是我想出的方案: 电子邮件具有名为“ type”的属性,该属性保留用于猫鼬类型。我该如何解决? 问题答案: 您需要使用对象定义字段:

  • 问题内容: 当声明为时,Elasticsearch 6.0将显示此错误。 问题答案: Elasticsearch删除了该类型,现在正在使用。所以你的代码应该是这样的

  • 问题内容: 我有一个用swift编写的CustomViewController类和用Objective C编写的CustomNavigationController类。我试图将CustomNavigationController作为属性添加到我的CustomViewController中。我已经添加到我的桥接头中。 在我的CustomViewController中,我有: 在尝试构建并运行之前没有

  • 问题内容: 是否有一个JavaScript的等效的Java的? 问题答案: 是否有与Java等效的JavaScript ? 没有 。 名称为。不论类别如何,的类别名称均为。ES2015环境中的内置构造函数具有正确的属性;例如是。 但是,这里有各种各样的骇客,它们都以一种或另一种方式下降: 这是一种可以满足您需要的技巧-请注意,它会修改Object的原型,而人们对此并不满意(通常是出于充分的理由)

  • 问题内容: 在我的Android应用程序,我需要和从当我得到执行命令后的结果。我怎样才能做到这一点? 问题答案: 就这么简单(是您的对象,应该在数据库中将其设置为正确的表名):