C# asp.net的事件聚合器

C# asp.net的事件聚合器,c#,asp.net,events,aggregator,C#,Asp.net,Events,Aggregator,我的需求 我希望我们的内部标准产品在事情发生时触发不同的事件。 在不同定制解决方案的全球asax中,我想在需要时连接这些事件,并作出反应 现有模块 我一直在寻找asp.net的事件聚合器,但我不确定该使用什么。 我读过关于Prism的文章,但似乎它针对的是WPF/Silverlight,而不是asp.net 还有一个家伙,他似乎已经将聚合器移植到自己的版本中,独立于WPF: 问题 有人使用过asp.net事件聚合器吗?这是用于生产的,所以我不喜欢使用来自网络上随机人的家庭编码聚合器:) 先谢谢你

我的需求

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

现有模块

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

还有一个家伙,他似乎已经将聚合器移植到自己的版本中,独立于WPF:

问题

有人使用过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);
    }
}
}
在全局asax中注册事件处理程序:

aggregator.Register<EntityDeleted>((s, e) => {
// Do stuff here
});
编辑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; }
}
//
///EventAggregator的单元测试
/// 
[测试类]
公共类事件聚合测试
{
///测试在调用没有处理程序的事件时不会引发异常。
[测试方法]
public void emptyaggregator测试()
{
var aggregator=new EventAggregator();
Publish(这是一个新的TestEventOne(){Property=“p1”});
}
///使用单个已注册的处理程序测试聚合器。
[测试方法]
public void SingleListenerTest()
{
var aggregator=new EventAggregator();
int=0;
聚合器.寄存器((发送方,e)=>
{
主张平等(“p1”,即财产);
调用++;
});
aresequal(0,调用);
Publish(这是一个新的TestEventOne(){Property=“p1”});
Assert.AreEqual(1,调用);
}
///使用多个已注册的处理程序测试聚合器。
[测试方法]
public void multipleListenerTest()
{
var aggregator=new EventAggregator();
int=0;
int=0;
聚合器.寄存器((发送方,e)=>
{
主张平等(“p1”,即财产);
p16++;
});
聚合器.寄存器((发送方,e)=>
{
主张平等(“p1”,即财产);
p16++;
});
聚合器.寄存器((发送方,e)=>
{
主张平等(“p2”,即财产);
p2++;
});
aresequal(0,p1调用);
Publish(这是一个新的TestEventOne(){Property=“p1”});
aresequal(2个p1调用);
aresequal(0,p2调用);
Publish(这是新的TestEventTwo(){Property=“p2”});
aresequal(1,p2调用);
aresequal(2个p1调用);
}
}
/// 
///虚拟试验事件1
/// 
公共类TestEventTone:EventArgs
{
公共字符串属性{get;set;}
}
/// 
///虚拟试验事件2
/// 
公共类TestEventTwo:EventArgs
{
公共字符串属性{get;set;}
}
编辑3:


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

我也有类似的要求,为此,我使用了NServiceBus,它的开放源代码以及大型社区和优秀文档来获取更多信息,请尝试此链接


如果你想要一个简单的(单个cs文件)插入式EA,它比你的自制EA(上面的一个似乎不是线程安全的,不确定这对你来说是否是个问题),你可以看看。

我想我有资格成为“网络上的随机人”,但是您可以查看我的这个项目:。您是在寻找事件聚合器还是服务总线?例如,代码中的事件(EA)或业务中的事件(SB)?我想我是在寻找业务中的事件,例如,我希望在更新内容时收到通知,不管是谁更新的,比如说产品数据的用户更新。谢谢!我认为N服务总线可以做到这一点!:)我在包含我使用的解决方案的主要帖子中添加了一个编辑。谢谢你的评论。你是对的,我的例子不是线程安全的。我看到TinyMessenger使用发布和注册锁来确保线程安全。我将在我的示例中的相同情况下添加锁,并用这些锁更新主帖。我有点喜欢这样的事实,上面的课程非常简单,涵盖了我的需求。
aggregator.Publish(this, new EntityDeleted());
/// <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; }
}