MassTransit:消息协定,多态性和动态代理对象 [英] MassTransit: Message contracts, polymorphism and dynamic proxy objects

查看:111
本文介绍了MassTransit:消息协定,多态性和动态代理对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL; DR 在合同订阅中,如何获取原始消息内容或原始发布的对象,而不是动态代理?

TL;DR On contract subscription, how can I get the raw message content or the original published object, rather than a dynamic proxy?

我在尝试创建基于MassTransit的模块化应用程序时遇到了麻烦.

I am having a bad time trying to create a modular application based on MassTransit.

我的想法是将Websocket服务器连接到队列,它从套接字读取事件并将其作为连接请求"插入队列中,并从队列中读取事件并将它们作为连接事件"发送到套接字".两者都有一个合同,该合同允许WS服务器知道事件将连接到哪个连接,而系统的其余部分则来自:

My idea is to have a Websocket server connected to queue, it reads events from the socket and inserts it in the queue as a "connection request", and reads events from the queue and send them to the sockets as "connection events". Both have a contract that allows the WS server know to which connection is the event going, and the rest of the system where is coming from:

public interface IConnectionRequest
{
    String ConnectionId { get; set; }
}

public interface IConnectionEvent
{
    String ConnectionId { get; set; }
}

有一个用于维护会话和其他数据的对象.该对象接受请求(例如动作请求或订阅请求)并作为请求的结果或仅因为状态已更改而推送事件.我想创建侦听特定事件或事件集并在状态上执行操作的对象,因此我创建了此合同:

There a object that maintain session and other data. This object accepts requests (like action requests or subscription requests) and push events as a result of the requests or just because the state changed. I want to create objects that listen for a particular event or set of events, and perform actions on the state, so I created this contract:

public interface IConnectionRequestHandler<T> : Consumes<T>.Selected
    where T : class, IConnectionRequest
{
}

例如,我想创建一个处理程序,该处理程序在服务器中创建实际的会话,并在会话准备就绪时回复连接通知.我创建了一个代表请求的对象,另外一个用于事件及其自身的处理程序.

For example, I want to create a handler that creates the actual session in the server, and replies to the connection notifying when the session is ready. I create an object that represents the request, other for the event and the handler it self.

public class CreateSessionRequest : IConnectionRequest
{
    public String ConnectionId { get; set; }
}

public class CreatedSessionEvent : IConnectionEvent
{
    public String ConnectionId { get; set; }
    public Guid SessionId { get; set; }
}

public class CreateSessionEventHandler : IConnectionRequestHandler<CreateSessionRequest>
{
    IServiceBus _bus;

    public CreateSessionEventHandler(IServiceBus bus)
    {
        _bus = bus;
    }

    public bool Accept(CreateSessionRequest message)
    {
        return true;
    }

    public void Consume(CreateSessionRequest message)
    {
        // do stuff, create the session
        var evt = new CreatedSessionEvent() { SessionId =Guid.NewGuid(), ConnectionId = message.ConnectionId };
        _bus.Publish(evt, evt.GetType());
    }
}

现在出于测试目的,我创建了模拟场景的代码.基本上,它创建通信总线并订阅请求处理程序:

Now for testing purposes, I create this code that emulates the scenario. Basically, it creates a communication bus and subscribes the request handler:

var bus = ServiceBusFactory.New(sbc =>
{
    sbc.ReceiveFrom("loopback://localhost/queue");
});

bus.SubscribeInstance<CreateSessionEventHandler>(new CreateSessionEventHandler(bus));

然后,我模拟Websocket服务器,编写从WS读取并将其发送到队列的部分:

Then, simulating the Websocket server, I write the part that reads from the WS and sends it to the queue:

IConnectionRequest e = new CreateSessionRequest() { ConnectionId = "myId" };
bus.Publish(e, e.GetType());

现在应该从队列中监听事件并将其转发到适当的连接的部分:

And now the part that is supposed to hear events from the queue and forward them to the appropiate connection:

bus.SubscribeHandler<IConnectionEvent>(evt => Console.WriteLine("Sending event '{0}' to connection: {1}",
                                                                evt.GetType().Name,  
                                                                evt.ConnectionId));

但是最后一部分不能按预期工作.我在订阅中获得的对象不是我的原始事件,它是动态代理DynamicImpl.IConnectionEvent,因此我无法在JSON中序列化此对象,因为它仅包含IConnectionEvent的成员.

But this last part does not work as expected. The object I get in the subscription is not my original event, it is a dynamic proxy DynamicImpl.IConnectionEvent, so I cannot serialize this object in JSON since it would only contain the members of IConnectionEvent.

如果我在订阅中指定了类型,它将起作用:

If I specify the type in the subscription, it works:

bus.SubscribeHandler<CreatedSessionEvent>(evt => Console.WriteLine("Sending event '{0}' to connection: {1}",
                                                                evt.GetType().FullName,  
                                                                evt.ConnectionId));

但这意味着对于每个新事件,我必须触摸websocket服务器以注册该新类型.

But then means that for each new event, I have to touch the websocket server to register that new type.

有办法避免这种情况吗?

Is there a way of avoiding this?

推荐答案

TL; DR-对于大多数序列化,MT仅支持合同中的数据.造成这种情况的原因很多,但是如果要使用非代理类型,则需要使用二进制序列化器.

TL;DR - MT only supports data on the contract for most serializes. There's a bunch of reasons for this but if you want non-proxy type then you need to use the binary serializer.

因此XML& JSON序列化(XML实际上只是在后台使用JSON序列化器,速度更快)会为所有请求生成一个代理.预订类型是您正在使用的合同,期望查询该对象以获取合同中未包含的更多详细信息会导致大量复杂性.我们建议您避免这样做.

So XML & JSON serialization (XML actually just uses the JSON serializer under the hood, oddly faster) generates a proxy for all requests if it can. The subscribed type is the contract you're using and expecting to interrogate the object for more details not in the contract leads to a ton of complexity. We suggest you avoid doing that.

因此,这意味着您需要进入Websocket服务器以获取预期要使用的每种消息.如果您唯一要做的就是转发消息,那么有人会做一个SingalR背板( https://github .com/mdevilliers/SignalR.RabbitMq 我认为是一个),它可能比MT消费者更适合.

So that would mean you would need to go to the websocket server for each type of message it was expected to consume. If the only thing you are doing is forwarding the message off, there's a SingalR backplane someone did (https://github.com/mdevilliers/SignalR.RabbitMq I think is one) that might be better fit than MT consumers.

这篇关于MassTransit:消息协定,多态性和动态代理对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆