Question

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).

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

  public ActionResult Show(Order order) {}

where order is bound by my custom binder. I trace its BindModel and see, that after the call to

  order = cart.GetOrder(id);

order items are OK - i.e. I add the to Watch window, view properties, Products, and they're all OK.

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):

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

I can now see this in the Watch window when viewing order.Items[0].Products.

The weird thing, is that the second order item is still OK! So if it goes like

  • HTTP request ... My Model Binder - get order using orderRepository.Get(id) - session is OK for both order items ...
  • mvc does its magic
  • action method Show(Order order) <- here session for order.Items [0].Products is lost, while for Items[1] is not

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).

What's going on here?

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.

UPDATE: some code (important lines)

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<ICart>();
  //Guid guidId = new Guid(id_value_from_context);
  var order = cart.GetOrder(guidId); // here order is OK completely
  return order;
}

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.

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.

UPDATE: Moreover, this happens only after this:

cart.Save(item);
return RedirectToAction<OrdersController>(c => c.Show(item.Order));

When I then go to the address bar and press "Enter" to reload the page, it works correctly. So it's one-time issue.

What's funny, there's no such bug if I do:

return RedirectToAction("Show", "Orders", new { order = item.Order });

So it's something with MvcContrib trying to deal with order in TempData, I'd say...

I found that I have this on controllers:

   [PassParametersDuringRedirect]
   public class OrdersController

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<> from MvcContrib but I have no idea why this happens.

Was it helpful?

Solution 2

Oh my god, I've put [PassParametersDuringRedirect] on my BaseController. I really did it, during the time when I experimented with MvcContrib, and just forgot about it. And it came back and bite me so bad, I've lost several hours trying to solve this.

So, the problem is me being stupid, and the lesson learned, is that one should never do system-wide attributes/behavior, since this is no better than global variables in sense of side-effects.

OTHER TIPS

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

means you session was closed before you request the product. are you sure that nothing closes your session ? maybe you can post some code ?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top