我想使用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();

10-04 21:35