2010-11-14 47 views
3

J'écris un site Web ASP.NET MVC, en utilisant autofac pour l'injection de dépendance, et Lightspeed de Mindscape en tant qu'ORM. Il existe une classe UserRepository, qui dépend d'une unité LightSeed UnitOfWork et qui gère le contrôleur Logon.Pourquoi autofac dispose-t-il un objet avant la fin de HttpRequest?

Problème: Le UnitOfWork est éliminé avant que UserRepository ne l'utilise.

public class UserRepository : IUserRepository 
    { 
    private readonly BluechipModelUnitOfWork _unitOfWork; 

    public UserRepository(BluechipModelUnitOfWork unitOfWork) 
    { 
     _unitOfWork = unitOfWork; 
    } 
    public Principal GetPrincipal(string name) 
    { 
     // This line throws an ObjectDisposedException - UnitOfWork is already disposed. 
     return _unitOfWork.Principals.FirstOrDefault(p => p.Name == name); 
    } 
    ... 

En Global.asax, le câblage de la dépendance se fait comme suit:

public class MvcApplication : HttpApplication, IContainerProviderAccessor 
{ 
    private static void RegisterAutofac() 
    { 
     var builder = new ContainerBuilder(); 

     // Register the lightspeed context as a singleton 
     builder.RegisterInstance(new LightSpeedContext<BluechipModelUnitOfWork>("LightSpeedBluechip")) 
      .As<LightSpeedContext<BluechipModelUnitOfWork>>() 
      .SingleInstance(); 

     // Register the unit of work constructor so that a new instance is bound to each HttpRequest 
     builder.Register(c => c.Resolve<LightSpeedContext<BluechipModelUnitOfWork>>().CreateUnitOfWork()) 
      .As<BluechipModelUnitOfWork>() 
      .InstancePerLifetimeScope(); 

     // Register user repository to be one instance per HttpRequest lifetime 
     builder.Register(c => new UserRepository(c.Resolve<BluechipModelUnitOfWork>())) 
      .As<IUserRepository>() 
      .InstancePerLifetimeScope(); 

     builder.Register(c => new CurrentUserService(
            c.Resolve<HttpSessionState>(), 
            c.Resolve<IUserRepository>(), 
            c.Resolve<IMembershipService>()) 
      ).As<ICurrentUserService>() 
      .CacheInSession(); 

     builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>(); 
     builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired().InjectActionInvoker(); 
     builder.RegisterModelBinders(Assembly.GetExecutingAssembly()); 

     // Set the container provider up with registrations.  
     _containerProvider = new ContainerProvider(builder.Build()); 

     // Set the controller factory using the container provider.  
     ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(_containerProvider)); 

Compte tenu des inscriptions ci-dessus, pourquoi autofac être l'élimination UnitOfWork (

Répondre

2

j'ai pu traquer le problème - c'est un gotcha stupide mais subtile ... J'avais une classe de CurrentUserService que j'enregistrais comme suit:

builder.Register(c => new CurrentUserService(
            c.Resolve<HttpSessionState>(), 
            c.Resolve<IUserRepository>(), 
            c.Resolve<IMembershipService>()) 
      ).As<ICurrentUserService>() 
      .CacheInSession(); 

Le problème est CacheInSession(), car CurrentUserService dépend de IUserRepository, qu'autofac injectait fidèlement, mais dont il disposait à la fin de la première requête.

Cela met en lumière quelque chose évidente, mais subtile pour être au courant au moment du câblage des injections de dépendance:

Assurez-vous que charge d'ordre supérieur ont toujours la même ou moins vivant que les services dont ils dépendent. Dans mon cas, la solution était de changer le code ci-dessus:

 builder.Register(c => new CurrentUserService(
            c.Resolve<HttpSessionState>(), 
            c.Resolve<IUserRepository>(), 
            c.Resolve<IMembershipService>()) 
      ).As<ICurrentUserService>() 
      .InstancePerLifetimeScope(); 

.... qui empêche la CurrentUserService de l'extérieur vivant l'instance dont elle dépend.