SignalR:在客户端和集线器之间使用基本类型消息

时间:2016-10-12 00:28:54

标签: signalr

我对SignalR很新,所以我会尽量保持清醒。这就是我想要完成的事情:

1.Create self-hosted web application using SignalR
2.Create WPF rich client which will communicate with above-mentioned server app.
3.Use strongly typed request/response messages which inherit from base types respectively to pass data from client to server and vice-versa.

以下是我的请求/回复消息的一些定义:

//Base request message
public class HubRequestMessageBase
{

}

//Base response message
public class HubResponseMessageBase
{
    public bool Success { get; set; }
    public Exception Error { get; set; }
}

//Request message to query node by name
public class QueryNodeRequest : HubRequestMessageBase
{
    public string Name { get; set; }
    public Guid Identifier { get; set; }
}

//Response message carrying metadata for the specified node
public class QueryNodeResponse : HubResponseMessageBase
{
   public NodeMetadata NodeMetadata { get; set; }
}

现在,如果我按照以下方式定义我的服务器方法:

//Main method for handling client requests
public void HandleClientRequest(HubRequestMessageBase message)
{
    //Omitted for brevity
}

并从客户端调用服务器方法,如下所示:

internal async void QueryNode(string name)
{
    QueryNodeRequest req = new QueryNodeRequest();
    req.Name = name;

    await HubProxy.Invoke("HandleClientRequest", new object[] { req });
}

在服务器端,我仍然在 HandleClientRequest 方法中使用 HubRequestMessageBase 作为消息参数的类型,而不是 QueryNodeRequest 。现在,经过一些挖掘,我了解到SignalR默认情况下不处理多态(或者消息没有正确地序列化/反序列化,类型我希望 - 在这种情况下 QueryNodeRequest 继承自 HubRequestMessageBase )。

我的问题是:是否有可能以某种方式在客户端和服务器上使用JsonSerializer设置来完成此操作?请注意,我已经尝试了以下代码(以及一些变体),但没有成功(在服务器上):

GlobalHost.DependencyResolver.Register(typeof(JsonSerializer),
                                                () => JsonSerializer.Create(new JsonSerializerSettings
                                                {
                                                    TypeNameHandling = TypeNameHandling.All
                                                }));

提前致谢!

干杯, CIVA

2 个答案:

答案 0 :(得分:0)

您必须实施IParameterResolver并注册。默认parameter resolver只是将JValues转换为目标参数类型。

答案 1 :(得分:0)

我能够解决这个问题。

问题的根本原因是信号器代码库中的这一行 https://github.com/SignalR/SignalR/blob/dev/src/Microsoft.AspNet.SignalR.Core/Json/JRawValue.cs#L28 Signalr使用默认的序列化程序,而不允许您注入自己的序列化程序。

我的解决方案是通过设置参数JObject的类型来绕过该序列化器 然后通过使用序列化程序的自定义实例和基于JObject的JTokenReader,将该JObject变成集线器本身的具体类型。

我的Hub方法(请注意,ClientCommand是我所有可能的命令的抽象基类)

public async Task DispatchCommand(Envelope envelope)
{
    var settings = new JsonSerializerSettings
                   {
                       TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple,
                       TypeNameHandling = TypeNameHandling.Objects
                   };
    var serializer = JsonSerializer.Create(settings);
    var c = (ClientCommand) serializer.Deserialize(new JTokenReader(envelope.Command), typeof(ClientCommand));

    await commandDispatcher.SendCommand(c);
}

信封类型

public sealed class Envelope
{
    public JObject Command { get; set; }
}

通过在JsonSerializer上使用TypeNameHandling = TypeNameHandling.Objects,我需要做的就是在我从客户端发送的对象中包含$ type属性。