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 服务器来注册该新类型。
有没有办法避免这种情况?