我在我们的解决方案中使用NServiceBus v4.3,MVC4,RavenDB 2.5和StructureMap 2.6.4.
我在StructureMap下遇到类似问题的问题,在这个问题的回答中我要求MVC控制器使用不同的生命周期,NServiceBus Handler在我的Web项目中使用RavenDB的IDocumentSession.
特别是在我的情况下,如果我使用HybridHttpOrThreadLocalScoped(如上面的答案建议Windsor)生命周期,会话没有被妥善处理,我很快就达到了30个事务限制错误.如果我使用HttpContext生命周期,则不会调用Web项目中的NSB事件处理程序.
在我的控制器中,会话被包含在通过MVC ActionFilter应用的工作单元中.我也使用处理程序中的UoW,因为我的注册表已连线以从UoW检索会话.代码是这样的:
RavenDbWebRegistry.cs
public sealed class RavenDbWebRegistry : Registry { public RavenDbWebRegistry() { // register RavenDB document store ForSingletonOf().Use(() => { var documentStore = new DocumentStore { ConnectionStringName = "RavenDB", Conventions = { IdentityPartsSeparator = "-", JsonContractResolver = new PrivatePropertySetterResolver(), }, }; documentStore.Initialize(); return documentStore; }); For ().HybridHttpOrThreadLocalScoped().Add(ctx => { var uow = (IRavenDbUnitOfWork)ctx.GetInstance (); return uow.DocumentSession; }); For ().HybridHttpOrThreadLocalScoped().Use (); } }
Web项目处理程序示例:
public class SiteCreatedEventHandler : IHandleMessages{ public IBus Bus { get; set; } public IUnitOfWork Uow { get; set; } public IDocumentSession DocumentSession { get; set; } public void Handle(ISiteCreatedEvent message) { try { Debug.Print(@"{0}{1}", message, Environment.NewLine); Uow.Begin(); var site = DocumentSession.Load (message.SiteId); Uow.Commit(); //invoke Hub and push update to screen var context = GlobalHost.ConnectionManager.GetHubContext (); //TODO make sure this SignalR function is correct context.Clients.All.displayNewSite(site, message.CommandId); context.Clients.All.refreshSiteList(); } catch (Exception ex) { Uow.Rollback(); } } }
ActionFilter的用法:
[RavenDbUnitOfWork] public ViewResult CreateNew(int? id) { if (!id.HasValue || id.Value <= 0) return View(new SiteViewModel { Guid = Guid.NewGuid() }); var targetSiteVm = MapSiteToSiteViewModel(SiteList(false)).FirstOrDefault(s => s.SiteId == id.Value); return View(targetSiteVm); }
WebRegistry(在我的MVC项目中设置NSB)
public sealed class WebRegistry : Registry { public WebRegistry() { Scan(x => { x.TheCallingAssembly(); x.Assembly("IS.CommonLibrary.ApplicationServices"); x.LookForRegistries(); }); IncludeRegistry(); FillAllPropertiesOfType (); FillAllPropertiesOfType (); FillAllPropertiesOfType (); FillAllPropertiesOfType >(); FillAllPropertiesOfType >(); FillAllPropertiesOfType (); FillAllPropertiesOfType (); FillAllPropertiesOfType (); //NServiceBus ForSingletonOf ().Use( NServiceBus.Configure.With() .StructureMapBuilder() .DefiningCommandsAs(t => t.Namespace != null && t.Namespace.EndsWith("Command")) .DefiningEventsAs(t => t.Namespace != null && t.Namespace.EndsWith("Event")) .DefiningMessagesAs(t => t.Namespace == "Messages") .RavenPersistence("RavenDB") .UseTransport () .DefineEndpointName("IS.Argus.Web") .PurgeOnStartup(true) .UnicastBus() .CreateBus() .Start(() => NServiceBus.Configure.Instance .ForInstallationOn () .Install()) ); //Web For ().Use(() => HttpContext.Current == null ? null : new HttpContextWrapper(HttpContext.Current)); For ().Use(GetModelBinders()); For ().Use (); For ().Use (); For ().Use (); For ().Use (); For ().Use (); For ().Use (); For ().Use (); IncludeRegistry (); }
我已经尝试使用我能想到的每种可能的组合配置我的注册表无济于事.
鉴于StructureMap混合生命周期不能像我期望的那样工作,我必须做些什么来实现正确的行为?
UoW对RavenDB是否必要/有益?我喜欢它(从我之前的NHibernate UoW ActionFilter中调整过它),因为它管理Controller Actions中会话的生命周期,但我对其他方法持开放态度.
理想情况下,我想要的是 - 在Web项目中 - 为控制器和处理程序分配完全不同的IDocumentSessions,但是无法以任何方式解决这个问题.