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

时间:2014-08-20 11:36:31

标签: .net serialization masstransit dynamic-proxy event-driven-design

  

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

我正在尝试基于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 个答案:

答案 0 :(得分:1)

TL; DR - MT仅支持大多数序列化合同的数据。这有很多原因,但如果你想要非代理类型,那么你需要使用二进制序列化器。

所以XML&amp; JSON序列化(XML实际上只是在引擎盖下使用JSON序列化程序,奇怪地更快)如果可能的话为所有请求生成代理。订阅类型是您正在使用的合约,并且期望查询对象以获取更多细节而不是合同导致大量复杂性。我们建议你避免这样做。

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