c# - 如何将一个接口的多个实现注入到一个实现中
问题描述
我正在尝试将实现的集合注入IResourceService
到另一个实现中,IResourceService
以便第一个实现能够在它无法对资源进行操作的情况下重定向到正确的服务。到目前为止,我尝试过的每一个实现都导致了循环依赖——所以我要么想知道如何解决这个问题,要么想知道如何设计它以使其不成问题。
我正在创建许多控制器,它们都照顾不同的资源。我将简化这个问题的情况 - 但实际上我有一个PetController
能够对所有提供 Id 的宠物进行简单操作的方法。因此,例如导航到/pet/1234
将为您提供宠物详细信息的摘要以及它是什么类型的宠物。
然后,我为每种宠物类型设置了多个控制器,DogController
即. 所有这些都继承自实际上正在完成所有繁重工作的 a。在您执行操作但 PetId 1234 实际上对应于仓鼠的场景中,我希望返回适当的响应(获取时重定向、更新时冲突等)。CatController
HamsterController
BasePetController
/dog/1234
DogController
所以我有这样的事情:
BasePetController : IResourceController
{
BasePetController(IResourceController[] resourceControllers){}
abstract Type SupportedResourceType { get; }
}
DogController : BasePetController
{
DogController(IResourceController[] resourceControllers) : base(resourceControllers) {}
Type SupportedResourceType => typeof(Dog);
}
然后将其添加到 DI 中,如下所示:
services.AddSingleton<IResourceController, DogController>();
services.AddSingleton<IResourceController, CatController>(); // etc.
这会导致循环依赖,因为DogController
需要自身才能有效地创建自己。
我试图注入一个ResourceControllerSelector
来进一步分离这个冲突,但没有骰子。
我想要的是控制器去(在伪代码中)
If (can't update dog because it isn't a dog) {
controller = getResourceControllerForPet()
action = controller.GetActionForUpdateOperation()
return information for the user to go to the correct action
}
我认为各个宠物控制器应该负责知道它是否可以处理特定资源 - 而不是另一个服务知道所有这些信息+要调用哪些操作等。但无法弄清楚如何为每个宠物控制器提供能够自己和/或在 API 层中获取这些信息,而无需创建循环依赖。
对此的任何帮助将不胜感激。无论是帮助解决依赖注入问题,还是设计所需的服务,甚至是 API 本身。
添加ResourceControllerSelector
where resourceControllers
is an 的实现IEnumerable<IResourceController>
。
public IResourceController SelectController(Type resourceType)
{
EnsureArg.IsNotNull(resourceType, nameof(resourceType));
return this.resourceControllers.SingleOrDefault(x => x.SupportedResourceType == resourceType)
?? throw new ArgumentOutOfRangeException(nameof(resourceType), resourceType, "No resource controller has been configured to handle the provided resource.");
}
解决方案
我认为这个问题已经分歧,有问题本身(这是我第一次尝试解决我遇到的问题),然后是我遇到的问题。所以我想我会用我学到的东西来更新这个问题。
回答问题
简短的回答是这对于 ASP.Net 标准依赖注入是不可能的,它不够先进。但是,使用 Autofac 和/或 SimpleInjector 之类的东西,您可以进行条件注入或上下文驱动注入。在这个世界上,您可以说注入所有不符合特定条件的接口实现。因此,如果实现与您目前尝试创建的匹配,您可以说不要注入。我没有在愤怒中尝试过,但理论上这可以解决问题
解决我的问题
我想要这样做的原因是,SeeOther
如果您尝试DogController
在仓鼠上执行操作,我可以返回准确的 (303) 响应。在我看来,这意味着注入其他控制器,以便它可以查询它们的信息(即找到正确操作的 actionName 和 controllerName)。然而另一种方法是使用反射和属性来表示控制器负责什么。所以我改为使用这样的东西:
我像这样装饰每个资源控制器: [ResourceController(Type = typeof(Dog), ControllerName = "Dog")] public class DogController : BasePetController
然后我在这里有一个助手类SeeOtherResultResolver
,它会扫描存储库中的正确控制器,然后扫描正确的HttpGet
或HttpDelete
etc 属性。
private static readonly IDictionary<string, Type> AttributeMap
= new Dictionary<string, Type>
{
{ "GET", typeof(HttpGetAttribute) },
{ "DELETE", typeof(HttpDeleteAttribute) },
{ "PUT", typeof(HttpPutAttribute) },
};
public string ResolveForSeeOtherResult(IUrlHelper urlHelper, object resource, object routeValues = null)
{
string scheme = urlHelper.ActionContext.HttpContext.Request.Scheme;
var httpAttribute = AttributeMap[urlHelper.ActionContext.HttpContext.Request.Method];
var resourceControllerTypes = resource.GetType().Assembly.GetTypes()
.Where(type => type.IsDefined(typeof(ResourceControllerAttribute), false));
foreach (var type in resourceControllerTypes)
{
var resourceControllerAttribute = type.GetCustomAttributes(false).OfType<ResourceControllerAttribute>().Single();
if (resourceControllerAttribute.Value == resource.GetType())
{
var methodInfo = type.GetMethods().Where(x => x.IsDefined(httpAttribute, false)).Single();
var result = urlHelper.Action(methodInfo.Name, resourceControllerAttribute.ControllerName, routeValues, scheme);
return result;
}
}
var errorMessage = string.Format(ErrorMessages.UnrecognisedResourceType, resource.GetType());
throw new InvalidOperationException(errorMessage);
}
感谢大家的帮助。我真的很感激,你让我意识到我在叫错树了!
推荐阅读
- android - Android Studio 不会自动导入 androidx.lifecycle.observe
- gnuplot - csv 文件数据的移动平均值显示 gnuplot 中的初始错误
- reactjs - 背景图像数据未正确通过 graphql Gatsby 查询
- macos - 在苹果汇编程序中加载 x64 上的立即地址
- javascript - 是否可以创建相同 html 元素的无限循环,从顶部滚动到底部并具有类似门户的效果?
- c++ - 如何以内存泄露的形式创建信息泄漏?(源代码)
- pip - simpletraj(setup.py)的构建轮...错误
- javascript - 选中的复选框在第一时间不起作用
- android - OnClickListener 仅适用于第一个 ViewHolder
- python - 具有均匀间隔颜色的颜色条的不均匀(不规则)间隔数据