title: NHibernate + ASP.NET MVC: model binder's session is closed
body: <p>I use custom model binder to bind Order/OrderItem in my actions. This model binder uses ServiceLocator.Current.GetInstance(); where ICart in turn depends on IOrderRepository (not sure if this matters).</p>
  
  <p>Now, everything works fine when I create first order item. And when I create the second one. Then I try to display the order which now contains two order items. This is done using </p>
  
  <pre><code>  public ActionResult Show(Order order) {}
  </code></pre>
  
  <p>where order is bound by my custom binder. I trace its BindModel and see, that after the call to</p>
  
  <pre><code>  order = cart.GetOrder(id);
  </code></pre>
  
  <p>order items are OK - i.e. I add the to Watch window, view properties, Products, and they're all OK.</p>
  
  <p>However, when the control flow comes to the Show(Order order) action method, the order's first item has invalid Products - accessing them results in following error (the famous one):</p>
  
  <p>NHibernate.LazyInitializationException: Initializing [Orders.Core.OrderItem#5440c233-fb7e-4dc9-8aec-9c8c0115808b]-failed to lazily initialize a collection of role: Orders.Core.OrderItem.Products, no session or session was closed</p>
  
  <p>I can now see this in the Watch window when viewing order.Items[0].Products.</p>
  
  <p>The weird thing, is that the second order item is still OK! So if it goes like</p>
  
  <ul>
  <li>HTTP request ... My Model Binder - get order using orderRepository.Get(id) - session is OK for both order items ... </li>
  <li>mvc does its magic </li>
  <li>action method Show(Order order) &lt;- here session for order.Items [0].Products is lost, while for Items[1] is not</li>
  </ul>
  
  <p>If I add another item to the order, then in the Show(), only Item[2].Products are correct, both Item[0] and Item[1] Products are bad (no session).</p>
  
  <p>What's going on here?</p>
  
  <p>I use Sharp Architecture and Session per request. I actually verified that EndRequest is not called between model binder getting its order and Show() receiving incorrect one.</p>
  
  <p>UPDATE: some code (important lines)</p>
  
  <pre><code>public class Cart : ICart
  {
        public Cart(IOrderRepository orderRepository, ICurrentUser currentUser, IUserSessionStorage storage) {}
        public Order GetOrder(Guid id)
        {
           return orderRepository.Get(id);
        }
  }
  
  public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
    var cart = ServiceLocator.Current.GetInstance&lt;ICart&gt;();
    //Guid guidId = new Guid(id_value_from_context);
    var order = cart.GetOrder(guidId); // here order is OK completely
    return order;
  }
  </code></pre>
  
  <p>OrderRepository is S#arp Architecture repository and uses WebSessionStorage class, which only closes Session at the EndRequest handler. As I said I've verified it is NOT get called between order is OK and order is not.</p>
  
  <p>Update: I wonder if this can be because of additional manual transaction around orderRepository.Save(order). Will investigate tomorrow, but found something similar here on SO.</p>
  
  <p>UPDATE: Moreover, this happens only after this:</p>
  
  <pre><code>cart.Save(item);
  return RedirectToAction&lt;OrdersController&gt;(c =&gt; c.Show(item.Order));
  </code></pre>
  
  <p>When I then go to the address bar and press "Enter" to reload the page, it works correctly. So it's one-time issue.</p>
  
  <p>What's funny, there's no such bug if I do:</p>
  
  <pre><code>return RedirectToAction("Show", "Orders", new { order = item.Order });
  </code></pre>
  
  <p>So it's something with MvcContrib trying to deal with order in TempData, I'd say... </p>
  
  <p>I found that I have this on controllers:</p>
  
  <pre><code>   [PassParametersDuringRedirect]
     public class OrdersController
  </code></pre>
  
  <p>and thought that my order parameter comes from TempData instead of ModelBinder... though model binder did fire, too. But when I removed the attribute, the problems did not disappear. So it's something with RedirectToController&lt;> from MvcContrib but I have no idea why this happens.</p>