问题描述
我想与温莎城堡来实现DI。目前,我有这样的构造函数重载(这是这里描述的反模式控制器:的):
I am trying to implement DI with Castle Windsor. Currently I have a controller with overloaded constructors like this (this is an antipattern as described here: https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=97):
public class MyController : ApiController
{
protected IStorageService StorageService;
protected MyController()
{
StorageService = StorageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
}
protected MyController(IStorageService storageService)
{
StorageService = storageService;
}
}
我试图摆脱第一个构造函数,并有温莎城堡处理存储服务依赖的分辨率。
I am trying to get rid of the first constructor and have Castle Windsor handle the resolution of the storage service dependency.
我创建了一个温莎城堡安装程序类是这样的:
I created a Castle Windsor installer class like this:
public class StorageServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IStorageService>()
.UsingFactoryMethod(
() => StorageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity)));
}
}
问题是,用户
(其类型为的IPrincipal
)是一个属性上 ApiController
,所以它不是从安装程序访问。我怎样才能使这项工作?
The problem is that User
(which has type IPrincipal
) is a property on ApiController
, so it's not accessible from the installer. How can I make this work?
更新:
@PatrickQuirk似乎暗示有更好的方式来做到这一点使用温莎城堡,而无需一个工厂都没有。
@PatrickQuirk seems to be implying that there is a better way to do this using Castle Windsor without needing a factory at all.
我StorageServiceFactory看起来是这样的:
My StorageServiceFactory looks like this:
public static class StorageServiceFactory
{
public static IStorageService CreateStorageService(ClaimsIdentity identity)
{
if (identity == null)
{
return null;
}
Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier);
if (providerKeyClaim == null || string.IsNullOrEmpty(providerKeyClaim.Value))
{
return null;
}
StorageProviderType storageProviderType;
string storageProviderString = identity.FindFirstValue("storage_provider");
if (string.IsNullOrWhiteSpace(storageProviderString) || !Enum.TryParse(storageProviderString, out storageProviderType))
{
return null;
}
string accessToken = identity.FindFirstValue("access_token");
if (string.IsNullOrWhiteSpace(accessToken))
{
return null;
}
switch (storageProviderType)
{
// Return IStorageService implementation based on the type...
}
}
}
有没有纳入选择正确的方式 IStorageService
进入温莎的依赖分辨率和完全避免的工厂?或者,我还需要它吗?
Is there a way to incorporate selecting the correct IStorageService
into Windsor's dependency resolution and avoid the factory altogether? Or do I still need it?
我喜欢@ PatrickQuirk的解决方案,但它似乎很奇怪必须创建为厂家的包装和相应的包装接口仅仅依赖注入的缘故。理想的情况是我必须的API控制器的构造参加一个IStorageService作为一个参数,它看起来更直观/与实际需要设置该领域是一致的。
I like @PatrickQuirk's solution, except that it seems odd to have to create a wrapper and corresponding wrapper interface for the factory just for the sake of dependency injection. Ideally I'd have the api controller's constructor take in an IStorageService as a parameter, which seems more intuitive/consistent with the field that actually needs to be set.
推荐答案
我不认为多个构造既是一种罪过作为 StorageServiceFactory
隐藏依赖是的,但我用你的方法大部分同意。
I don't think the multiple constructors is as much of a sin as the hidden dependency on StorageServiceFactory
is, but I agree with your approach for the most part.
而不是一个工厂方法,传递一个工厂对象到类,并让它创建存储服务:
Instead of a factory method, pass a factory object into the class and have it create the storage service:
public class MyController : ApiController
{
protected IStorageService StorageService;
protected MyController(IStorageServiceFactory storageServiceFactory)
{
StorageService = storageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
}
}
,然后定义你的工厂接口和实现:
And then define your factory interface and implementation:
public interface IStorageServiceFactory
{
IStorageService Create(ClaimsIdentity claimsIdentity);
}
public class StorageServiceFactoryImpl : IStorageServiceFactory
{
public IStorageService Create(ClaimsIdentity claimsIdentity)
{
return StorageServiceFactory.CreateStorageService(claimsIdentity);
}
}
这样,你有一个构造函数,并在存储服务工厂的依赖关系是明确的。
This way, you have a single constructor and the dependency on the storage service factory is explicit.
关于你提到的更新:
...这似乎很奇怪,有创建工厂的包装和相应的包装接口仅仅依赖注入的缘故。
嗯,这是一种依赖注入的地步。
Well, that's kind of the point of dependency injection.
我建议该包装是解决两个问题:它消除了需要从你的类中(隐藏的依赖)调用一个静态方法,并允许延迟分辨率(因为你的依赖依靠会员的数据被创建)。
The wrapper I propose is solving two problems: it removes the need to call a static method from inside your class (hiding a dependency), and allows for delayed resolution (because your dependency relies on member data to be created).
如果你有办法来改变创建一个 IStorageService
的不依赖依赖你给它的类的成员上的然后的,你可以传递一个直接(前提是你能告诉温莎如何创建一个)。
If you have a way to change the dependencies of creating an IStorageService
to not rely on a member of the class you're giving it to, then you could pass one in directly (provided you can tell Windsor how to create one).
这篇关于温莎城堡DI安装程序:依赖工厂方法嵌套在ApiController房地产依赖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!