2012-09-03 55 views
1

我有一個股票標準的ASP.NET MVC 3 Web應用程序。.NET中的事件調度

我有幾個交叉問題,我希望使用一些AOP,最顯着的事件調度模式。例如,我希望在發生事件時在控制器中「引發事件」,然後在我的應用程序(存儲庫,服務等)中散佈幾個「監聽者」,監聽此事件並採取相應的行動。

我還應該提到,我爲我的IoC容器使用了StructureMap - 所以如果事件調度程序對IoC容器使用(或可插入),而不是依靠它自己,那將是最好的。

有沒有人找到一個NuGet包來做到這一點,或者可以指向我的文章/問題,說明如何做到這一點?

回答

4

控制器應該是無狀態的。 Framework在請求處理後銷燬控制器對象,並在下一個請求到來時重新創建它。實際上,ASP.NET MVC爲每個請求創建單獨的控制器實例。在控制器中聲明事件並通過其他應用程序服務訂閱此事件可能會導致內存泄漏(GC不會銷燬用過的控制器,因爲將從其他活動對象中對控制器進行活動引用)。

而且記住,IIS可能會殺了你的web應用程序的進程如果將閒置或其他原因,所以你Web應用程序也應該是無狀態的

你也必須保持在該事件處理的腦海併發,

您可以使用事件發佈者 - 訂閱模式,但它應該被實現爲獨立的「代理人」,例如作爲Windows服務,這將聽某些端口並處理來自Web應用程序的請求。

0

我不認爲你的控制器應該引發事件,這應該是你的域邏輯完成域特定驗證後的事情。在完成驗證之前,你如何確定事情真的發生了,以確保它能正常工作?

但是,實現基於事件的簡單解決方案並不難。我會去這樣的:

public abstract class BaseEvent {} 

public class EventRouter { 
      private Dictionary<Type, List<Action<BaseEvent>>> _eventRoutes; 

    public EventRouter() 
    { 
     _eventRoutes= new Dictionary<Type, List<Action<BaseEvent >>>(); 
    } 

    public void Register<TEvent>(Action<TEvent> route) where TEvent : BaseEvent 
    { 
     List<Action<TEvent>> routes; 
     var type = typeof(BaseEvent); 
     if (_eventRoutes.TryGetValue(type, out routes).IsFalse()) 
     { 
      routes = new List<Action<TEvent>>(); 
      _eventRoutes.Add(type, routes); 
     } 
     routes.Add((y) => route(y as BaseEvent)); 
    } 

    public bool TryGetValue(Type commandType, out List<Action<TEvent>> handlers) 
    { 
     return _eventRoutes.TryGetValue(eventType, out handlers); 
    } 
} 

public class InMemoryEventDispatcher : IEventBus 
{ 
    private readonly IEventRouter _eventRouter; 

    public InMemoryEventBus(IEventRouter eventRouter) 
    { 
     _eventRouter = eventRouter; 
    } 

    public void PublishEvent<TEvent>(TEvent @event) where TEvent : BaseEvent 
    { 
     var eventType = @event.GetType(); 
     List<Action<TEvent>> eventHandlers; 
     if (_eventRouter.TryGetValue(eventType, out eventHandlers).IsTrue()) 
     { 
      foreach (var eventHandler in eventHandlers) 
      { 
       eventHandler(@event); 
      } 
     } 
    } 

    public void PublishEvents<TEvent>(IEnumerable<BaseEvent> events) where TEvent : BaseEvent 
    { 
     foreach (var @event in events) 
     { 
      PublishEvent(@event); 
     } 
    } 
} 

隨着那個準備好,你可以註冊你想要執行每個事件的動作。我沒有編譯它,但是應該這樣。

+0

@downvoter,請評論有什麼不對? –