Asp.net mvc 4 使用NServiceBus和MVC的StructureMap管理RavenDB IDocumentSession生命周期

Asp.net mvc 4 使用NServiceBus和MVC的StructureMap管理RavenDB IDocumentSession生命周期,asp.net-mvc-4,ravendb,nservicebus,structuremap,Asp.net Mvc 4,Ravendb,Nservicebus,Structuremap,我在我们的解决方案中使用了NServiceBus v4.3、MVC4、RavenDB 2.5和StructureMap 2.6.4 我在StructureMap下遇到了类似的问题,如中所述,我要求MVC控制器和NServiceBus处理程序在Web项目中使用RavenDB的IDocumentSession具有不同的生命周期 具体地说,在我的例子中,如果我使用HybridHttpOrthReadLocalScope(正如上面针对Windsor的回答所建议的那样)生命周期,那么会话没有得到正确的处理

我在我们的解决方案中使用了NServiceBus v4.3、MVC4、RavenDB 2.5和StructureMap 2.6.4

我在StructureMap下遇到了类似的问题,如中所述,我要求MVC控制器和NServiceBus处理程序在Web项目中使用RavenDB的IDocumentSession具有不同的生命周期

具体地说,在我的例子中,如果我使用HybridHttpOrthReadLocalScope(正如上面针对Windsor的回答所建议的那样)生命周期,那么会话没有得到正确的处理,我很快就遇到了30事务限制错误。如果使用HttpContext生命周期,则不会调用Web项目中的NSB事件处理程序

在我的控制器中,会话被包装在通过MVC ActionFilter应用的工作单元中。我还使用处理程序中的UoW,因为我的注册表连接到从UoW检索会话。守则如下:

RavenDbWebRegistry.cs

public sealed class RavenDbWebRegistry : Registry
{
    public RavenDbWebRegistry()
    {
        // register RavenDB document store
        ForSingletonOf<IDocumentStore>().Use(() =>
        {
            var documentStore = new DocumentStore
            {
                ConnectionStringName = "RavenDB",
                Conventions =
                {
                    IdentityPartsSeparator = "-", 
                    JsonContractResolver = new PrivatePropertySetterResolver(),
                },

            };
            documentStore.Initialize();

            return documentStore;
        });


        For<IDocumentSession>().HybridHttpOrThreadLocalScoped().Add(ctx =>
        {
            var uow = (IRavenDbUnitOfWork)ctx.GetInstance<IUnitOfWork>();
            return uow.DocumentSession;
        });

        For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<WebRavenDbUnitOfWork>();            

    }
}
公共密封类RavenDbWebRegistry:注册表
{
公共RavenDbWebRegistry()
{
//注册RavenDB文档存储
ForSingletonOf()。使用(()=>
{
var documentStore=新的documentStore
{
ConnectionStringName=“RavenDB”,
惯例=
{
IdentityPartsParator=“-”,
JsonContractResolver=新的PrivatePropertySetterResolver(),
},
};
初始化();
返回文件存储;
});
For().HybridHttpOrthReadLocalScope().Add(ctx=>
{
var uow=(IRavenDbUnitOfWork)ctx.GetInstance();
返回uow.DocumentSession;
});
For().HybridHttpOrthReadLocalScope().Use();
}
}
Web项目处理程序示例:

public class SiteCreatedEventHandler : IHandleMessages<ISiteCreatedEvent>
{
    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<Site>(message.SiteId);
            Uow.Commit();

            //invoke Hub and push update to screen
            var context = GlobalHost.ConnectionManager.GetHubContext<AlarmAndNotifyHub>();

            //TODO make sure this SignalR function is correct
            context.Clients.All.displayNewSite(site, message.CommandId);
            context.Clients.All.refreshSiteList();            
        }
        catch (Exception ex)
        {                
            Uow.Rollback();
        }            
    }
}
公共类SiteCreatedEventHandler:IHandleMessages
{
公共IBus总线{get;set;}
公共IUnitOfWork{get;set;}
公共IDocumentSession DocumentSession{get;set;}
公共无效句柄(ISiteCreatedEvent消息)
{
尝试
{
Print(@“{0}{1}”,消息,环境,换行符);
Uow.Begin();
var site=DocumentSession.Load(message.SiteId);
提交();
//调用中心并将更新推送到屏幕
var context=GlobalHost.ConnectionManager.GetHubContext();
//t确保此信号器功能正确
context.Clients.All.displayNewSite(site,message.CommandId);
context.Clients.All.refreshSiteList();
}
捕获(例外情况除外)
{                
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);
    }
[RavenDbUnitOfWork]
public ViewResult CreateNew(int?id)
{
如果(!id.HasValue | | id.Value s.SiteId==id.Value);
返回视图(targetSiteVm);
}
WebRegistry(在我的MVC项目中设置NSB)

公共密封类WebRegistry:注册表
{
公共网站注册处()
{
扫描(x=>
{
x、 装配件();
x、 程序集(“IS.CommonLibrary.ApplicationServices”);
x、 查找注册表();
});
IncludeRegistry();
FillAllPropertiesOfType();
FillAllPropertiesOfType();
FillAllPropertiesOfType();
FillAllPropertiesOfType();
FillAllPropertiesOfType();
FillAllPropertiesOfType();
FillAllPropertiesOfType();
FillAllPropertiesOfType();
//N服务总线
ForSingletonOf()。使用(
NServiceBus.Configure.With()
.StructureMapBuilder()
.DefiningCommandsAs(t=>t.Namespace!=null&&t.Namespace.EndsWith(“命令”))
.DefiningEventsAs(t=>t.Namespace!=null&&t.Namespace.EndsWith(“事件”))
.DefiningMessagesAs(t=>t.Namespace==“消息”)
.RavenPersistence(“RavenDB”)
.UseTransport()
.DefineEndpointName(“IS.Argus.Web”)
.PurgeOnStartup(正确)
.UnicastBus()
.CreateBus()
.Start(()=>NServiceBus.Configure.Instance
.ForInstallationOn()的
.Install())
);
//网
For().Use(()=>HttpContext.Current==null?null:newhttpcontextwrapper(HttpContext.Current));
For()。使用(GetModelBinders());
For().Use();
For().Use();
For().Use();
For().Use();
For().Use();
For().Use();
For().Use();
IncludeRegistry();
}
我尝试过使用我能想到的所有可能的组合来配置我的注册表,但都没有用

鉴于StructureMap混合生命周期并不像我预期的那样工作,我必须做些什么来实现正确的行为

UoW对RavenDB是否必要/有益?我喜欢它(从我早期的NHibernate UoW ActionFilter中改编而来),因为它在控制器操作中管理我的会话生命周期的方式,但我对其他方法持开放态度


理想情况下,我想要的是一种在Web项目中为控制器和处理程序分配完全不同的IDocumentSessions的方法,但一直无法找到任何方法。

首先,RavenDB已经通过包装
IDocumentSession
实现了工作单元,因此不需要它。打开一个会话,调用
SaveChanges()
和disposing已完成工作单元

其次,可以通过几种方式为控制器实现会话

一般的指导是在
Global.asax.cs
中设置存储。由于只有一个框架实现了
IDocumentSession
-RavenDB,您还可以从
Global
中实例化它。如果它是存储库后面的NHibernate或实体框架,我可以理解。但是IDocumentSession是RavenDB
public sealed class WebRegistry : Registry
{
    public WebRegistry()
    {
        Scan(x =>
        {
            x.TheCallingAssembly();
            x.Assembly("IS.CommonLibrary.ApplicationServices");
            x.LookForRegistries();
        });

        IncludeRegistry<RavenDbWebRegistry>();

        FillAllPropertiesOfType<IUnitOfWork>();
        FillAllPropertiesOfType<IDocumentSession>();
        FillAllPropertiesOfType<StatusConversionService>();
        FillAllPropertiesOfType<IStateRepository<TieState>>();
        FillAllPropertiesOfType<IStateRepository<DedState>>();
        FillAllPropertiesOfType<ITieService>();
        FillAllPropertiesOfType<IDedService>();
        FillAllPropertiesOfType<IHbwdService>();

        //NServiceBus
        ForSingletonOf<IBus>().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<ActiveMQ>()
            .DefineEndpointName("IS.Argus.Web")
            .PurgeOnStartup(true)
            .UnicastBus()
            .CreateBus()
            .Start(() => NServiceBus.Configure.Instance
            .ForInstallationOn<Windows>()
            .Install())
        );


        //Web             
        For<HttpContextBase>().Use(() => HttpContext.Current == null ? null : new HttpContextWrapper(HttpContext.Current));
        For<ModelBinderMappingDictionary>().Use(GetModelBinders());
        For<IModelBinderProvider>().Use<StructureMapModelBinderProvider>();
        For<IFilterProvider>().Use<StructureMapFilterProvider>();
        For<StatusConversionService>().Use<StatusConversionService>();
        For<ITieService>().Use<TieService>();
        For<IDedService>().Use<DedService>();
        For<IHbwdService>().Use<HbwdService>();
        For<ISiteService>().Use<SiteService>();

        IncludeRegistry<RedisRegistry>();
    }