Managing RavenDB IDocumentSession lifecycles with StructureMap for NServiceBus and MVC

旧时模样 提交于 2019-12-05 08:34:44
Dominic Zukiewicz

Firstly, RavenDB already implements unit of work by the wrapping IDocumentSession, so no need for it. Opening a session, calling SaveChanges() and disposing has completed the unit of work

Secondly, Sessions can be implemented in a few ways for controllers.

The general guidance is to set up the store in the Global.asax.cs. Since there is only 1 framework that implements IDocumentSession - RavenDB, you might as well instantiate it from the Global. If it was NHibernate or Entity Framework behind a repository, I'd understand. But IDocumentSession is RavenDB specific, so go with a direct initialization in the Application_Start.

public class Global : HttpApplication
{
   public void Application_Start(object sender, EventArgs e)
   {
      // Usual MVC stuff

      // This is your Registry equivalent, so insert it into your Registry file 
      ObjectFactory.Initialize(x=> 
      {
         x.For<IDocumentStore>()
          .Singleton()
          .Use(new DocumentStore { /* params here */ }.Initialize());
   }

   public void Application_End(object sender, EventArgs e)
   {
      var store = ObjectFactory.GetInstance<IDocumentStore>();

      if(store!=null)
         store.Dispose();
   }
}

In the Controllers, add a base class and then it can open and close the sessions for you. Again IDocumentSession is specific to RavenDB, so dependency injection doesn't actually help you here.

public abstract class ControllerBase : Controller
{
   protected IDocumentSession Session { get; private set; }

   protected override void OnActionExecuting(ActionExecutingContext context)
   {
      Session = ObjectFactory.GetInstance<IDocumentStore>().OpenSession();
   }

   protected override void OnActionExecuted(ActionExecutedContext context)
   {
      if(this.IsChildAction)
         return;

      if(content.Exception != null && Session != null)
         using(context)
            Session.SaveChanges();
   }
}

Then from there, inherit from the base controller and do your work from there:

public class CustomerController : ControllerBase
{
   public ActionResult Get(string id)
   {
      var customer = Session.Load<Customer>(id);

      return View(customer);
   }

   public ActionResult Edit(Customer c)
   {
      Session.Store(c);

      return RedirectToAction("Get", c.Id);
   }
 }

Finally, I can see you're using StructureMap, so it only takes a few basic calls to get the Session from the DI framework:

public class SiteCreatedEventHandler : IHandleMessages<ISiteCreatedEvent>
{
    public IBus Bus { get; set; }
    public IUnitOfWork Uow { get; set; }
    public IDocumentSession DocumentSession { get; set; }

    public SiteCreatedEventHandler()
    {
       this.DocumentSession = ObjectFactory.GetInstance<IDocumentStore>().OpenSession();
    }

    public void Handle(ISiteCreatedEvent message)
    {
       using(DocumentSession)
       {
          try
          {
             Debug.Print(@"{0}{1}", message, Environment.NewLine);

             ///// Uow.Begin(); // Not needed for Load<T>

             var site = DocumentSession.Load<Site>(message.SiteId);

             //// Uow.Commit(); // Not needed for Load<T>

             // 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(); // Not needed for Load<T>
         }            
      }
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!