Агрегатор событий для asp.net

Мои потребности

Я хотел бы, чтобы наш собственный стандартный продукт вызывал различные события, когда что-то происходит. В глобальном asax для различных пользовательских решений, я хотел бы подключиться к этим событиям, когда это необходимо, и реагировать.

Существующие модули

Я искал агрегатор событий для asp.net, но я не совсем уверен, что использовать. Я читал о Prism, но похоже, что он предназначен для WPF/Silverlight, а не для asp.net.

Тогда есть этот парень, который, кажется, перенес агрегатор в свою собственную версию, независимую от WPF: http://weblogs.asp.net/rashid/archive/2009/03/05/use-event-aggregator-to-make-your-application-more-extensible.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:

Спасибо Стивену Роббинсу за то, что он указал, что агрегатор не является потокобезопасным, я добавил блокировку в методы публикации и регистрации.

2 ответа

Решение

У меня было похожее требование, и для этого я использовал NServiceBus с открытым исходным кодом, большим сообществом и отличной документацией, чтобы получить больше информации, попробуйте эту ссылку

http://docs.particular.net/

Если вы хотите простое (одиночный CS-файл) падение в EA, которое дает вам немного больше, чем домашнее свернутое (приведенное выше не выглядит поточно-ориентированным, не уверен, что это проблема для вас), вы можете взять посмотрите на TinyMessenger.

Другие вопросы по тегам