Autofac 注册嵌套类型?
Autofac register nested type?
假设我有这四种类型(带有构造函数)。
public class MyDbContext : IDataContextAsync
{
public class MyDataContext() { }
}
public class UnitOfWork : IUnitOfWorkAsync
{
public UnitOfWork(IDataContextAsync dataContext)
{
_dataContext = dataContext;
}
}
public class Repository<TEntity> : IRepositoryAsync<TEntity>
{
public Repository(IDataContextAsync context, IUnitOfWorkAsync unitOfWork)
{
_context = context;
_unitOfWork = unitOfWork;
}
}
public class AccountService : IAccountService
{
private readonly IUnitOfWorkAsync _uow;
private readonly IRepositoryAsync<Account> _repository;
public AccountService(IUnitOfWorkAsync uow, IRepositoryAsync<Account> repository)
{
_uow = uow;
_repository = repository;
}
}
我尝试像这样在我的容器中注册它们(顺便说一句,我正在使用 WCF)。
var builder = new ContainerBuilder();
builder.RegisterType<MyDbContext>().As<IDataContextAsync>();
builder.RegisterType<UnitOfWork>().As<IUnitOfWorkAsync>();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepositoryAsync<>));
builder.RegisterAssemblyTypes(typeof(AccountService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.As(t => t.GetInterfaces().FirstOrDefault(
i => i.Name == "I" + t.Name));
Container = builder.Build();
注入到 AccountService 的容器生成的 unitOfWork 实例似乎与容器实例化存储库时创建的 unitOfWork 实例不同。如何确保使用相同的实例实例化存储库?例如,这是在没有容器的情况下通常如何实例化对象的方式。
var context = new MyDbContext();
_uow = new UnitOfWork(context);
_repository = new Repository<Account>(context, _uow);
AccountService service = new AccountService(_uow, _repository);
如您所见,_uow
和用于创建存储库的 _uow
参数是同一个实例。当 Autofac 实例化对象时情况并非如此,我似乎无法弄清楚如何 "tie them together".
默认情况下 Autofac 范围是每个依赖项。这意味着每次 Autofac 需要解析依赖项时,它都会 return 一个新实例。
如果您希望每个生命周期或请求都有一个通用实例,则必须使用适当的范围注册您的类型。
var builder = new ContainerBuilder();
builder.RegisterType<MyDbContext>()
.As<IDataContextAsync>()
.InstancePerLifetimeScope();
builder.RegisterType<UnitOfWork>()
.As<IUnitOfWorkAsync>()
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepositoryAsync<>))
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(typeof(AccountService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.As(t => t.GetInterfaces().FirstOrDefault(i => i.Name == "I" + t.Name))
.InstancePerLifetimeScope();
Container = builder.Build();
有关详细信息,请参阅 Autofac 文档中的 Instance Scope。
顺便说一句,Autofac 与 WCF 的集成似乎不支持每个请求的生命周期
Due to WCF internals, there is no explicit support in WCF for per-request lifetime dependencies.
此限制与 WCF 具有自己的实例范围这一事实有关。建议使用 InstanceContextMode.PerCall
以确保 WCF 为每个 WCF 调用请求一个新的服务实例。您可以使用 ServiceBehavior
属性
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService : IMyService
{ }
我阅读了 AutofacInstanceContext.cs 的源代码,似乎为每个 WCF 调用创建了一个新的 LifetimeScope。因此,您可以将依赖项注册为 InstancePerLifetimeScope
,它应该可以工作。
假设我有这四种类型(带有构造函数)。
public class MyDbContext : IDataContextAsync
{
public class MyDataContext() { }
}
public class UnitOfWork : IUnitOfWorkAsync
{
public UnitOfWork(IDataContextAsync dataContext)
{
_dataContext = dataContext;
}
}
public class Repository<TEntity> : IRepositoryAsync<TEntity>
{
public Repository(IDataContextAsync context, IUnitOfWorkAsync unitOfWork)
{
_context = context;
_unitOfWork = unitOfWork;
}
}
public class AccountService : IAccountService
{
private readonly IUnitOfWorkAsync _uow;
private readonly IRepositoryAsync<Account> _repository;
public AccountService(IUnitOfWorkAsync uow, IRepositoryAsync<Account> repository)
{
_uow = uow;
_repository = repository;
}
}
我尝试像这样在我的容器中注册它们(顺便说一句,我正在使用 WCF)。
var builder = new ContainerBuilder();
builder.RegisterType<MyDbContext>().As<IDataContextAsync>();
builder.RegisterType<UnitOfWork>().As<IUnitOfWorkAsync>();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepositoryAsync<>));
builder.RegisterAssemblyTypes(typeof(AccountService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.As(t => t.GetInterfaces().FirstOrDefault(
i => i.Name == "I" + t.Name));
Container = builder.Build();
注入到 AccountService 的容器生成的 unitOfWork 实例似乎与容器实例化存储库时创建的 unitOfWork 实例不同。如何确保使用相同的实例实例化存储库?例如,这是在没有容器的情况下通常如何实例化对象的方式。
var context = new MyDbContext();
_uow = new UnitOfWork(context);
_repository = new Repository<Account>(context, _uow);
AccountService service = new AccountService(_uow, _repository);
如您所见,_uow
和用于创建存储库的 _uow
参数是同一个实例。当 Autofac 实例化对象时情况并非如此,我似乎无法弄清楚如何 "tie them together".
默认情况下 Autofac 范围是每个依赖项。这意味着每次 Autofac 需要解析依赖项时,它都会 return 一个新实例。
如果您希望每个生命周期或请求都有一个通用实例,则必须使用适当的范围注册您的类型。
var builder = new ContainerBuilder();
builder.RegisterType<MyDbContext>()
.As<IDataContextAsync>()
.InstancePerLifetimeScope();
builder.RegisterType<UnitOfWork>()
.As<IUnitOfWorkAsync>()
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepositoryAsync<>))
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(typeof(AccountService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.As(t => t.GetInterfaces().FirstOrDefault(i => i.Name == "I" + t.Name))
.InstancePerLifetimeScope();
Container = builder.Build();
有关详细信息,请参阅 Autofac 文档中的 Instance Scope。
顺便说一句,Autofac 与 WCF 的集成似乎不支持每个请求的生命周期
Due to WCF internals, there is no explicit support in WCF for per-request lifetime dependencies.
此限制与 WCF 具有自己的实例范围这一事实有关。建议使用 InstanceContextMode.PerCall
以确保 WCF 为每个 WCF 调用请求一个新的服务实例。您可以使用 ServiceBehavior
属性
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService : IMyService
{ }
我阅读了 AutofacInstanceContext.cs 的源代码,似乎为每个 WCF 调用创建了一个新的 LifetimeScope。因此,您可以将依赖项注册为 InstancePerLifetimeScope
,它应该可以工作。