代码之家  ›  专栏  ›  技术社区  ›  vtortola

MassTransit:消息契约、多态性和动态代理对象

  •  0
  • vtortola  · 技术社区  · 10 年前

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

    我在尝试基于MassTransit创建模块化应用程序时遇到了困难。

    我的想法是让一个Websocket服务器连接到队列,它从套接字中读取事件,并将其作为“连接请求”插入队列中,然后从队列中读取事件并将它们作为“连接事件”发送到套接字。两者都有一个契约,允许WS服务器知道事件正在进行到哪个连接,以及系统的其余部分来自何处:

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

    有一个对象维护会话和其他数据。此对象接受请求(如操作请求或订阅请求),并作为请求的结果或仅因为状态更改而推送事件。我想创建侦听特定事件或事件集的对象,并对状态执行操作,因此我创建了这个契约:

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

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

    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());
        }
    }
    

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

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

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

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

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

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

    但这最后一部分并不像预期的那样工作。我在订阅中获得的对象不是我的原始事件,它是一个动态代理 DynamicImpl.IConnectionEvent ,因此我无法在JSON中序列化此对象,因为它只包含 IConnectionEvent .

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

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

    但这意味着,对于每一个新事件,我都必须接触websocket服务器来注册新类型。

    有没有办法避免这种情况?

    1 回复  |  直到 10 年前
        1
  •  1
  •   Travis    10 年前

    TL;DR-MT只支持大多数序列化的合约数据。这有很多原因,但如果您想要非代理类型,则需要使用二进制序列化程序。

    所以XML&JSON串行化(XML实际上只是在后台使用JSON串行化器,速度出奇地快)为所有请求生成代理(如果可以的话)。订阅类型是您正在使用的合约,并且期望询问对象以了解更多细节,而合约中没有的细节会导致大量的复杂性。我们建议您避免这样做。

    因此,这意味着您需要为预期使用的每种类型的消息访问websocket服务器。如果你唯一要做的就是把消息转发出去,那么有人做了一个SingalR背板( https://github.com/mdevilliers/SignalR.RabbitMq 我认为是一种)可能比MT消费者更适合。