6

我的需求

我希望我们的内部标准产品在发生事情时触发不同的事件。在不同自定义解决方案的全局 asax 中,我想在需要时连接这些事件并做出反应。

现有模块

我一直在寻找 asp.net 的事件聚合器,但我不确定该使用什么。我读过关于 Prism 的文章,但似乎它针对的是 WPF/Silverlight 而不是 asp.net。

然后是这个家伙,他似乎已经将聚合器移植到他自己的版本中,独立于 WPF:http ://weblogs.asp.net/rashid/archive/2009/03/05/use-event-aggregator-to-使您的应用程序更可扩展.aspx

问题

有没有人体验过使用 asp.net 的事件聚合器?这是用于生产用途,所以我不喜欢使用网络上随机人提供的一些家庭编码聚合器:)

先感谢您。

编辑 1: 看起来, NServiceBus 有点矫枉过正。我创建了一个可以解决问题的 EventAggregator 类。

班上:

/// <summary>
/// A event aggregator.
/// </summary>
public class EventAggregator
{
/// <summary>The object to use when locking.</summary>
private readonly object _lock = new object();
/// <summary>Holder of registered event handlers</summary>
private readonly Dictionary<Type, List<object>> _handlers = new Dictionary<Type, List<object>>();
/// <summary>Registers the specified handler.</summary>
/// <typeparam name="T"></typeparam>
/// <param name="handler">The handler.</param>
public void Register<T>(EventHandler<T> handler) where T : EventArgs
{
    lock (_lock)
    {
        if (!_handlers.ContainsKey(typeof (T)))
            _handlers.Add(typeof (T), new List<object>());
        _handlers[typeof (T)].Add(handler);
    }
}
/// <summary>Publishes the specified event.</summary>
/// <typeparam name="T"></typeparam>
/// <param name="sender">The sender.</param>
/// <param name="eventToPublish">The event to publish.</param>
public void Publish<T>(object sender, T eventToPublish) where T : EventArgs
{
    lock (_lock)
    {
        if (!_handlers.ContainsKey(typeof (T)))
            return; // No listers for event
        foreach (EventHandler<T> handler in _handlers[typeof (T)])
            handler.Invoke(sender, eventToPublish);
    }
}
}

一个事件类:

public class EntityDeleted : EventArgs
{
}

在全局 asax 中注册事件处理程序:

aggregator.Register<EntityDeleted>((s, e) => {
// Do stuff here
});

引发事件:

aggregator.Publish(this, new EntityDeleted());

编辑2:

这是我对感兴趣的人的单元测试:

/// <summary>
/// Unit tests for EventAggregator
/// </summary>
[TestClass]
public class EventAggregatorTest
{
    /// <summary>Tests that no exceptions are thrown when calling an event with no handlers.</summary>
[TestMethod]
public void EmptyAggregatorTest()
{
    var aggregator = new EventAggregator();
    aggregator.Publish(this, new TestEventOne() { Property = "p1" });
}
/// <summary>Tests the aggregator using a single, registered handler.</summary>
[TestMethod]
public void SingleListenerTest()
{
    var aggregator = new EventAggregator();
    int calls = 0;
    aggregator.Register<TestEventOne>((sender, e) =>
    {
        Assert.AreEqual("p1", e.Property);
        calls ++;
    });
    Assert.AreEqual(0, calls);
    aggregator.Publish(this, new TestEventOne(){Property = "p1"});
    Assert.AreEqual(1, calls);
}

/// <summary>Tests the aggregator using multiple registered handlers.</summary>
[TestMethod]
public void MultipleListenersTest()
{
    var aggregator = new EventAggregator();
    int p1Calls = 0;
    int p2Calls = 0;
    aggregator.Register<TestEventOne>((sender, e) =>
    {
        Assert.AreEqual("p1", e.Property);
        p1Calls++;
    });
    aggregator.Register<TestEventOne>((sender, e) =>
    {
        Assert.AreEqual("p1", e.Property);
        p1Calls++;
    });
    aggregator.Register<TestEventTwo>((sender, e) =>
    {
        Assert.AreEqual("p2", e.Property);
        p2Calls++;
    });
    Assert.AreEqual(0, p1Calls);
    aggregator.Publish(this, new TestEventOne() { Property = "p1" });
    Assert.AreEqual(2, p1Calls);
    Assert.AreEqual(0, p2Calls);
    aggregator.Publish(this, new TestEventTwo() { Property = "p2" });
    Assert.AreEqual(1, p2Calls);
    Assert.AreEqual(2, p1Calls);
}
}

/// <summary>
/// Dummy test event 1
/// </summary>
public class TestEventOne : EventArgs
{
    public string Property { get; set; }
}
/// <summary>
/// Dummy test event 2
/// </summary>
public class TestEventTwo : EventArgs
{
    public string Property { get; set; }
}

编辑 3:

感谢 Steven Robbins 指出聚合器不是线程安全的,我在 Publish 和 Register 方法中添加了锁定。

4

2 回答 2

2

我有类似的要求,为此我使用了 NServiceBus 它的开源与大型社区和出色的文档来获取更多信息,请尝试此链接

http://docs.particular.net/

于 2011-10-21T12:13:50.443 回答
1

如果您想在 EA 中添加一个简单的(单个 cs 文件),它可以为您提供比您的家庭滚动的多一点(上面的那个似乎不是线程安全的,不确定这是否对您来说是个问题),您可以采取看看TinyMessenger

于 2011-10-24T10:49:46.913 回答