c# - MassTransit 消息消费者永远看不到子类类型

标签 c# events inheritance subclass masstransit

这个问题涉及事件(基类事件和子类事件)和事件处理程序。我正在处理现有代码,它似乎没有按照作者预期的方式工作。我很难理解为什么它不起作用,所以我想在尝试修复现有代码之前了解发生了什么。

我发现了以下问题,这可能表明也可能不表明我需要为子类型事件创建一个额外的事件处理程序:

C#: Raising an inherited event

如果制作一个额外的事件处理程序确实是解决方案,我仍然想了解为什么会这样。这是我在这里的第一个问题,我确实试图寻找我的问题的答案/解释,但如果它仍然是我应该很容易找到的东西,我深表歉意。一个严厉的“RTFM!”在这一点上,有教育联系对我来说没问题:)

我们有 2 个事件类,一个基本类型和一个子类型。子类型事件的存在是为了处理删除事件。

public class BaseTypeEvent
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    public BaseTypeEvent()
    { }

    public BaseTypeEvent(SomeRandomThing item)
    {
        Id = item.Id;
        Name = item.Name;
    }
}

public class SubTypeEvent : BaseTypeEvent
{
    public DateTimeOffset Deleted { get; set; }

    public SubTypeEvent()
    {
        Deleted = DateTimeOffset.UtcNow;
    }
}

这些事件的用法似乎失败了:

public class UsageClass
{   
    public UsageClass(IEventBusService eventBusService)
    {
        eventBusService.MyBaseTypeEvents += HandleMethod;
    }

    private void HandleMethod(BaseTypeEvent e)
    {
        if(e is SubTypeEvent)
        {
            //code that deals with deletion events
            //execution never actually gets here
        }

        //code that deals with events that are not deletion events
     }
}

事件的声明在 IEventBusService 和 EventBusService 中:

public delegate void MyEventHandler(BaseTypeEvent e);

public interface IEventBusService
{
    public event MyEventHandler MyBaseTypeEvents;

    void PublishStuff(BaseTypeEvent e);
}

public class EventBusService : IEventBusService, IDisposable 
{
    public void Initialize()
    {
        //Bus is MassTransit
        Bus.Initialize(sbc =>
            {
                sbc.Subscribe(subs => subs.Handler<BaseTypeEvent>(OnBaseTypeEvent));
            }
    }

    private void OnBaseTypeEvent(BaseTypeEvent e)
    {
        if (MyBaseTypeEvents == null) return;
        try
        {
            MyBaseTypeEvents(e);
        }
        catch (Exception e)
        {
            //some logging
        }
    }

    public event MyEventHandler MyBaseTypeEvents;

    public void PublishStuff(BaseTypeEvent e)
    {
        //some logging

        //publish e to the event bus of our choice (MassTransit)
        Bus.Instance.Publish(e);
    }
}

最后是我们发送删除事件的地方(尝试删除我在上面巧妙命名为 SomeRandomThing 的项目):

eventBusService.PublishStuff(new SubTypeEvent
    {
        Id = id,
        Deleted = DateTimeOffset.UtcNow
    });

所以问题是:在用上面最后一行代码发送删除事件后,UsageClass 中检查传入事件是否属于 SubTypeEvent 类型的 if 语句实际上永远不会为真。 UsageClass的HandleMethod中e的类型为BaseTypeEvent。

编辑:

在这种情况下,我决定去掉子类型。我们现在不再有 BaseTypeEvent 和 SubTypeEvent,只有 EventTypeA 和 EventTypeB。一个处理创建和更新,另一个处理删除(我们需要的信息比创建和更新要少得多)。

public delegate void MyEventAHandler(EventTypeA e);
public delegate void MyEventBHandler(EventTypeB e);

void PublishStuffForA(EventTypeA e);
void PublishStuffForB(EventTypeB e);

等等。

我在 EventbusService 的 Initialize 方法中额外订阅了 MassTransit,并在需要它们的各种 UsageClass 中创建了额外的处理程序:

sbc.Subscribe(subs => subs.Handler<EventTypeA>(OnEventTypeA));
sbc.Subscribe(subs => subs.Handler<EventTypeB>(OnEventTypeB));

public UsageClass(IEventBusService eventBusService)
{
    eventBusService.MyEventTypeAEvents += HandleMethodForA;
    eventBusService.MyEventTypeBEvents += HandleMethodForB;
}

等等。

我现在不再需要检查传入事件是否属于特定类型,我只需分别处理两种类型。也许是逃避,但它确实有效。

我犹豫是否要将此作为我自己问题的答案,因为@Glubus 的评论以及@Travis 的评论回答了我的问题。仍然认为这个小的编辑文章可能会让每个人都知道我做了什么作为解决方案:)

编辑 2:

有用的信息来源:

Derived types are not published to consumers in MassTransit

MassTransit message mis-typing

MassTransit: Message contracts, polymorphism and dynamic proxy objects

https://groups.google.com/forum/#!searchin/masstransit-discuss/polymorphism/masstransit-discuss/q_M4erHQ7OI/FxaotfIzI7YJ

最佳答案

所以我可以告诉你一个简短的答案:

Using polymorphism in messaging contracts introduces coupling.

作为 MassTransit 开发人员,我们认为这是个坏主意。它仍然是可能的,但不是开箱即用的。您必须使用二进制序列化或客户序列化程序。默认情况下,序列化管道仅在消费者中填充该类型的代理。

关于c# - MassTransit 消息消费者永远看不到子类类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37855885/

相关文章:

c# - 使用 Json.NET 序列化器对某些属性进行驼峰式大小写,但对其他属性不进行驼峰式大小写

jquery - 监控单选按钮未被选中的情况

JavaScript/FullCalendar - 将事件附加到事件渲染

c++ - 意外地能够从基类ctor调用派生类虚函数

c++ - 值到类型运行时映射

c# - 当应用程序是 C# 中的任务栏时,如何监听快捷方式

c# - 无法从线程任务 <bool> 转换为系统操作

c++ - 错误是因为函数在类中是纯虚拟的?

c# - 在 C# 中寻找后缀树实现?

mysql - 如何在没有 URL 的情况下使用 JSON 编码数组?