SignalR没有反序列化自定义对象

时间:2017-11-08 18:43:48

标签: c# signalr signalr.client signalr-2

我在.NET 4.5.2中使用SignalR 2.2.2(最新版本)

我发现了这个错误:

  

无法创建类型的实例   DF.ApplicationBlocks.IPropertyValueData。类型是接口或   抽象类,无法实例化。路径'属性[0] .Id',   第1行,第881位。

问题是:

我发送了一个自定义对象的SignalR客户端(用.NET编写,使用Signal.Client包),在该对象上有一个对象数组作为接口(IPropertyValueData)。数组中的值是此接口的实现。

在signalR客户端中,我已配置为使用TypeNameHandling.Auto:

        this._connection.JsonSerializer.TypeNameHandling = TypeNameHandling.Auto;
        this._connection.JsonSerializer.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
        this._connection.JsonSerializer.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;

并且它正确完成,因为这是客户发送的内容的摘录:

"Properties":[  
    {  
       "$id":"20",
       "$type":"DF.MailFlow.Services.Contract.Data.MailDataProperty, DF.MailFlow.Services.Contract",
       "Id":"5588ce9e-30fb-45b1-afbe-1e6ad0c3e8d4",

因此定义了$ type属性并且值是正确的。 但无论如何,服务器仍会在收到消息时触发错误。

我还将服务器配置为使用TypeNameHandling.Auto,以下是集线器的配置方式(我使用Castle Windsor作为IoC):

        var resolver = new WindsorDependencyResolver(WebAPILoader.Container);

        var hubConfig = new HubConfiguration()
        {
            EnableJSONP = true,
            EnableDetailedErrors = true,
            EnableJavaScriptProxies = true,
            Resolver = resolver
        };


        GlobalHost.DependencyResolver = resolver;

        // Configure signalR and run it
        app.UseCors(CorsOptions.AllowAll);
        app.Map("/live", map =>
        {
            map.UseCors(CorsOptions.AllowAll);
            map.RunSignalR(hubConfig);
        });

        var serializerSettings = new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.Auto,
            PreserveReferencesHandling = PreserveReferencesHandling.Objects,
            ReferenceLoopHandling = ReferenceLoopHandling.Serialize
        };
        GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = serializerSettings;
        GlobalConfiguration.Configuration.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;

        // Register in Castle.Windsor container
        WebAPILoader.Container.Register(Castle.MicroKernel.Registration.Component
                              .For<JsonSerializer>()
                              .UsingFactoryMethod(() => JsonSerializer.Create(serializerSettings)));

我已经检查过,当收到第一条消息时,将调用factory方法并且设置仍然具有正确的TypeNameHandling.Auto。

我也测试过以这种方式注册序列化器:

GlobalHost.DependencyResolver.Register(typeof(JsonSerializer), () => JsonSerializer.Create(serializerSettings));

但是没办法,服务器总是在收到消息时触发相同的错误。

增加复杂性,应用程序运行signalr和webapi组件(在不同的URL中)。我检查过webapi没有注册任何JsonSerializer,所使用的Windsor容器对于两个组件都是相同的。

有什么想法吗?

编辑#1:

我刚试过这张票https://github.com/SignalR/SignalR/issues/3304
似乎令人难以置信的是,即使有人制作PR(https://github.com/SignalR/SignalR/pull/3343),也会在3年内没有任何修复的情况下列出错误 所以现在我试图找到一个解决方法......

1 个答案:

答案 0 :(得分:0)

这个问题显然是由于SignalR中的错误

造成的

link中发布的解决方法有效,即注册自定义解析程序:

private class Resolver : DefaultParameterResolver
{
    private readonly JsonSerializer _serializer;

    public Resolver(JsonSerializer serializer)
    {
        _serializer = serializer;
    }

    private FieldInfo _valueField;
    public override object ResolveParameter(ParameterDescriptor descriptor, Microsoft.AspNet.SignalR.Json.IJsonValue value)
    {
        if (value.GetType() == descriptor.ParameterType)
        {
            return value;
        }

        if (_valueField == null)
            _valueField = value.GetType().GetField("_value", BindingFlags.Instance | BindingFlags.NonPublic);

        var json = (string)_valueField.GetValue(value);
        using (var reader = new StringReader(json))
            return _serializer.Deserialize(reader, descriptor.ParameterType);
    }
}

关于如何解决此错误的讨论现在在this ticket,所以你可以在那里找到(希望)解决它