我想使用Entity Framework的IDbSet<>
接口实现通用存储库模式。
当我从Autofac询问IDbSet<T>
时,它应该解析IDbContext
然后调用其Set<T>
方法以返回IDbSet<T>
的具体类型
例如,它应该做这样的事情:
builder.Register<IDbSet<T>>(context => context.Resolve<IDbContext>().Set<T>());
我如何使用Autofac做到这一点?
最佳答案
似乎基于以下答案:https://stackoverflow.com/a/7997162/872395
唯一的解决方案是创建自定义IRegistrationSource
,在其中创建封闭式注册:
public class DbSetRegistrationSource : IRegistrationSource
{
public bool IsAdapterForIndividualComponents
{
get { return true; }
}
public IEnumerable<IComponentRegistration> RegistrationsFor(
Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
var swt = service as IServiceWithType;
if (swt == null || !swt.ServiceType.IsGenericType)
yield break;
var def = swt.ServiceType.GetGenericTypeDefinition();
if (def != typeof(IDbSet<>))
yield break;
// if you have one `IDBContext` registeration you don't need the
// foreach over the registrationAccessor(dbContextServices)
yield return RegistrationBuilder.ForDelegate((c, p) =>
{
var dBContext = c.Resolve<IDBContext>();
var m = dBContext.GetType().GetMethod("Set", new Type[] {});
var method =
m.MakeGenericMethod(swt.ServiceType.GetGenericArguments());
return method.Invoke(dBContext, null);
})
.As(service)
.CreateRegistration();
}
}
用法很简单:
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterSource(new DbSetRegistrationSource());
containerBuilder.RegisterType<DbContext>().As<IDBContext>();
var container = containerBuilder.Build();