我有一个股票标准的ASP.NET MVC 3 Web应用程序。
我有几个跨领域的问题,我希望使用一些AOP,最明显的是事件调度员模式。
例如,我希望在发生某些事情时在我的控制器中“举起一个事件”,然后在我的应用程序(存储库,服务等)中散布几个“听众”,这些“侦听器”会监听此事件并采取相应的行动。
我还应该提一下,我正在为我的IoC容器使用StructureMap - 所以最好是事件调度程序使用(或可插入)IoC容器,而不是依赖它自己。
有没有人找到这样做的NuGet软件包,或者可以指出我的文章/问题说明如何做?
答案 0 :(得分:4)
控制器应该是无状态的。框架在处理请求后销毁控制器对象,并在下一个请求到来时重新创建它。实际上,ASP.NET MVC为每个请求创建单独的控制器实例。在控制器中声明事件并由其他应用程序服务订阅此事件可能会导致内存泄漏(GC不会破坏使用的控制器,因为将从其他活动对象中对控制器进行活动引用)。
另请注意, IIS可能会扼杀您的网络应用程序的进程,如果它会闲置或出于其他原因,那么您的 Web应用程序也应该是无状态的
您还必须牢记事件处理的并发性,
您可以使用事件发布者 - 订阅者模式,但它应该作为单独的“代理”实现,例如作为Windows服务,它将侦听某些端口并处理来自Web应用程序的请求。
答案 1 :(得分: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);
}
}
}
准备就绪后,您可以注册要为每个事件执行的操作。我没有编译它,但应该这样。