Почему autofac удаляет объект до завершения HttpRequest?
Я пишу веб-сайт ASP.NET MVC, используя автофак для внедрения зависимостей и Lightspeed от Mindscape в качестве ORM. Есть класс UserRepository, который зависит от скорости световой скорости UnitOfWork и который обслуживает контроллер входа в систему.
Проблема: UnitOfWork удаляется до того, как UserRepository завершит его использование.
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);
}
...
В Global.asax подключение зависимостей выполняется следующим образом:
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));
Учитывая вышеупомянутые регистрации, почему бы autofac избавился от UnitOfWork (
1 ответ
Мне удалось отследить проблему - это глупая, но тонкая ошибка... У меня был класс CurrentUserService, который я регистрировал следующим образом:
builder.Register(c => new CurrentUserService(
c.Resolve<HttpSessionState>(),
c.Resolve<IUserRepository>(),
c.Resolve<IMembershipService>())
).As<ICurrentUserService>()
.CacheInSession();
Проблема в CacheInSession (), потому что CurrentUserService зависит от IUserRepository, который autofac верно вводил, но затем удалял в конце первого запроса.
Это выявляет что-то очевидное, но тонкое, чтобы знать об этом при подключении инъекций зависимости:
Убедитесь, что у иждивенцев высшего порядка всегда такой же или более короткий срок службы, что и у служб, от которых они зависят. В моем случае решением было изменить приведенный выше код:
builder.Register(c => new CurrentUserService(
c.Resolve<HttpSessionState>(),
c.Resolve<IUserRepository>(),
c.Resolve<IMembershipService>())
).As<ICurrentUserService>()
.InstancePerLifetimeScope();
.... который не позволяет CurrentUserService переиграть экземпляр, от которого он зависит.