【问题标题】:SignalR : Using base type messages between client and hubSignalR:在客户端和集线器之间使用基本类型消息
【发布时间】:2018-07-13 15:47:21
【问题描述】:

我对 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 });
}

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

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

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

提前致谢!

干杯, 奇瓦

【问题讨论】:

    标签: signalr


    【解决方案1】:

    我已经能够解决这个问题了。

    问题的根本原因是信号器代码库中的这一行 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 属性。

    【讨论】:

    • 我知道这是一个老问题,但非常感谢 StocksR 的回答,很好发现,它绝对有帮助。干杯!
    【解决方案2】:

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

    【讨论】:

    • 你好Pawel,非常感谢你的回答,我会试试这个并尽快让你知道。
    • 不幸的是,这种方法没有解决我的问题,因为 IJsonValue 已经包含我期望的感兴趣的数据类型:{"$type":"Zenith.Network.Api.Messages.QueryNodeRequest, Zenith.Network.Api", ...<Rest of JSON omitted for brevity> } 我根本无法将它转换回 HubRequestMessageBase(作为 ParameterType 中的值)。我最终为每种请求类型编写了单独的方法,它按预期工作。但是,我会将您的响应标记为已接受,因为这是处理多态消息类型的一种方法,也许有人会发现它很有用。
    猜你喜欢
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-16
    • 2021-10-18
    相关资源
    最近更新 更多