使用 Autofac ASP.Net Core 5 注册动态通用存储库
Registering dynamic generic repository with Autofac ASP.Net Core 5
我正在尝试创建一个包装器存储库,它将能够使用基于类型的通用存储库。
到目前为止我有:
启动:
builder.RegisterAssemblyTypes(Assembly.Load("Data"))
.Where(t => t.Namespace.Contains("Repositories"))
.As(t => t.GetInterfaces().FirstOrDefault(i => i.Name == "I" + t.Name))
.InstancePerLifetimeScope();
builder.RegisterType<GenericRepositoryLong<EventRegistrationActivity>>()
.As<IGenericRepositoryLong<ILongEntity>>()
.Keyed<IGenericRepositoryLong<ILongEntity>>(ActivityType.EventRegistration)
.AsSelf()
.InstancePerLifetimeScope();
builder.Register<Func<ActivityType, IGenericRepositoryLong<ILongEntity>>>(c =>
{
var componentContext = c.Resolve<IComponentContext>();
return (activityType) =>
{
var repo = componentContext.ResolveKeyed<IGenericRepositoryLong<ILongEntity>>(activityType);
return repo;
};
});
ActivityRepository
基本上是一个处理缓存数据一致性的包装存储库。它还应该使用通用存储库来保存实体。通用存储库在注入时运行良好,但在我尝试以下操作时它不起作用:
public class ActivityRepository: IActivityRepository
{
private readonly Func<ActivityType, IGenericRepositoryLong<ILongEntity>> ActivityRepoFac;
public ActivityRepository(Func<ActivityType, IGenericRepositoryLong<ILongEntity>> activityRepoFac)
{
ActivityRepoFac = activityRepoFac;
}
public async Task CreateActivityAsync(IFeedActivity activity, ActivityType activityType)
{
var repo = ActivityRepoFac(activityType);
...repo code here
}
}
ActivityType
是一个简单的 enum,我得到的错误是:
The type
'Infra.DataProvider.GenericRepositoryLong`1[Domain.Entities.Activities.EventRegistrationActivity]'
is not assignable to service
'Infra.DataProvider.IGenericRepositoryLong`1[[Domain.ILongEntity, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
我正在尝试做的事情是否可行,如果可行,我是否遗漏了什么?
另外,这是一个好习惯吗?
如有任何帮助,我们将不胜感激。
这里没有足够的内容来果断地说出发生了什么,但例外情况很能说明问题。
这里的注册是您需要测试的重要部分,甚至没有所有的键控和额外设置。就是这样:
builder.RegisterType<GenericRepositoryLong<EventRegistrationActivity>>()
.As<IGenericRepositoryLong<ILongEntity>>();
异常是说你不能将 GenericRepositoryLong<EventRegistrationActivity>
转换为 IGenericRepositoryLong<ILongEntity>
。
换句话说,如果你这样做,它不会编译:
IGenericRepositoryLong<ILongEntity> repo =
new GenericRepositoryLong<EventRegistrationActivity>();
我实际上没有看到 GenericRepositoryLong<T>
或 IGenericRepositoryLong<T>
实体的定义,所以我不能肯定地说,但这就是例外情况。
通常这是因为接口是这样声明的:
public interface IGenericRepositoryLong<T>
并且它缺少 proper variance keyword 表示您要执行的操作。我猜你可能想要
public interface IGenericRepositoryLong<out T>
我会尝试在完全不涉及 Autofac 的单元测试中对此进行故障排除。如果您要手动创建所有类型和属性并自己连接它们,它是否可行?试图弄清楚 同时 还尝试注册事物并排列 Autofac 语法可能会导致混淆,例如“是 Autofac 这样做,还是我的代码中有什么?”
最后,与问题无关,我确实注意到您同时注册了 AsSelf
和 Keyed
,这看起来很奇怪。我的意思是,您实际上可能希望 也 能够直接解析 GenericRepositoryLong<T>
,但考虑到您所展示的设置以及它与 activity 的紧密耦合输入,您可能 不 想要它。拥有它不会 伤害 任何东西,但如果您不小心解决了一些您不打算解决的问题,这仅仅是因为您添加了太多 services/registrations,它也会导致混乱。
我正在尝试创建一个包装器存储库,它将能够使用基于类型的通用存储库。
到目前为止我有:
启动:
builder.RegisterAssemblyTypes(Assembly.Load("Data"))
.Where(t => t.Namespace.Contains("Repositories"))
.As(t => t.GetInterfaces().FirstOrDefault(i => i.Name == "I" + t.Name))
.InstancePerLifetimeScope();
builder.RegisterType<GenericRepositoryLong<EventRegistrationActivity>>()
.As<IGenericRepositoryLong<ILongEntity>>()
.Keyed<IGenericRepositoryLong<ILongEntity>>(ActivityType.EventRegistration)
.AsSelf()
.InstancePerLifetimeScope();
builder.Register<Func<ActivityType, IGenericRepositoryLong<ILongEntity>>>(c =>
{
var componentContext = c.Resolve<IComponentContext>();
return (activityType) =>
{
var repo = componentContext.ResolveKeyed<IGenericRepositoryLong<ILongEntity>>(activityType);
return repo;
};
});
ActivityRepository
基本上是一个处理缓存数据一致性的包装存储库。它还应该使用通用存储库来保存实体。通用存储库在注入时运行良好,但在我尝试以下操作时它不起作用:
public class ActivityRepository: IActivityRepository
{
private readonly Func<ActivityType, IGenericRepositoryLong<ILongEntity>> ActivityRepoFac;
public ActivityRepository(Func<ActivityType, IGenericRepositoryLong<ILongEntity>> activityRepoFac)
{
ActivityRepoFac = activityRepoFac;
}
public async Task CreateActivityAsync(IFeedActivity activity, ActivityType activityType)
{
var repo = ActivityRepoFac(activityType);
...repo code here
}
}
ActivityType
是一个简单的 enum,我得到的错误是:
The type
'Infra.DataProvider.GenericRepositoryLong`1[Domain.Entities.Activities.EventRegistrationActivity]'
is not assignable to service
'Infra.DataProvider.IGenericRepositoryLong`1[[Domain.ILongEntity, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
我正在尝试做的事情是否可行,如果可行,我是否遗漏了什么? 另外,这是一个好习惯吗?
如有任何帮助,我们将不胜感激。
这里没有足够的内容来果断地说出发生了什么,但例外情况很能说明问题。
这里的注册是您需要测试的重要部分,甚至没有所有的键控和额外设置。就是这样:
builder.RegisterType<GenericRepositoryLong<EventRegistrationActivity>>()
.As<IGenericRepositoryLong<ILongEntity>>();
异常是说你不能将 GenericRepositoryLong<EventRegistrationActivity>
转换为 IGenericRepositoryLong<ILongEntity>
。
换句话说,如果你这样做,它不会编译:
IGenericRepositoryLong<ILongEntity> repo =
new GenericRepositoryLong<EventRegistrationActivity>();
我实际上没有看到 GenericRepositoryLong<T>
或 IGenericRepositoryLong<T>
实体的定义,所以我不能肯定地说,但这就是例外情况。
通常这是因为接口是这样声明的:
public interface IGenericRepositoryLong<T>
并且它缺少 proper variance keyword 表示您要执行的操作。我猜你可能想要
public interface IGenericRepositoryLong<out T>
我会尝试在完全不涉及 Autofac 的单元测试中对此进行故障排除。如果您要手动创建所有类型和属性并自己连接它们,它是否可行?试图弄清楚 同时 还尝试注册事物并排列 Autofac 语法可能会导致混淆,例如“是 Autofac 这样做,还是我的代码中有什么?”
最后,与问题无关,我确实注意到您同时注册了 AsSelf
和 Keyed
,这看起来很奇怪。我的意思是,您实际上可能希望 也 能够直接解析 GenericRepositoryLong<T>
,但考虑到您所展示的设置以及它与 activity 的紧密耦合输入,您可能 不 想要它。拥有它不会 伤害 任何东西,但如果您不小心解决了一些您不打算解决的问题,这仅仅是因为您添加了太多 services/registrations,它也会导致混乱。