Pourquoi est-autofac un objet Mise au rebut avant la fin HttpRequest?
-
09-10-2019 - |
Question
J'écris un site Web ASP.NET MVC, en utilisant autofac pour l'injection de dépendance, et Lightspeed Mindscape comme ORM. Il y a une classe UserRepository, qui dépend d'un UnitOfWork LightSpeed ??et quels services le contrôleur d'ouverture de session.
Problème :. Le UnitOfWork se disposé avant la UserRepository est fini de l'utiliser
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);
}
...
Dans 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 (
La solution
Je suis en mesure de traquer le problème - c'est un Gotcha stupide mais subtile ... J'ai eu une classe CurrentUserService que je me 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 () , parce que le CurrentUserService dépend de IUserRepository qui autofac a été fidèlement injectait, mais l'élimination de la fin de la première demande.
Cela nous amène à la 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 il dépend.