【问题标题】:Castle Windsor DI installer: dependency factory method has nested dependency on ApiController propertyCastle Windsor DI 安装程序:依赖工厂方法具有对 ApiController 属性的嵌套依赖
【发布时间】:2015-03-09 17:03:42
【问题描述】:

我正在尝试使用 Castle Windsor 实施 DI。目前我有一个像这样重载构造函数的控制器(这是这里描述的反模式: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;
    }
}

我正在尝试摆脱第一个构造函数,让 Castle Windsor 处理存储服务依赖项的解析。

我像这样创建了一个 Castle Windsor 安装程序类:

public class StorageServiceInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<IStorageService>()
                     .UsingFactoryMethod(
                         () => StorageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity)));
    }
}

问题在于User(类型为IPrincipal)是ApiController 上的一个属性,因此安装程序无法访问它。我怎样才能做到这一点?


更新:

@PatrickQuirk 似乎暗示有更好的方法可以使用 Castle Windsor 做到这一点,而根本不需要工厂。

我的 StorageServiceFactory 如下所示:

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 合并到 Windsor 的依赖解析中并完全避免使用工厂?还是我还需要它?

我喜欢@PatrickQuirk 的解决方案,只是为了依赖注入而必须为工厂创建包装器和相应的包装器接口似乎很奇怪。理想情况下,我会让 api 控制器的构造函数接受 IStorageService 作为参数,这似乎更直观/与实际需要设置的字段一致。

【问题讨论】:

    标签: asp.net-web-api dependency-injection inversion-of-control castle-windsor ioc-container


    【解决方案1】:

    我认为多个构造函数并不像对 StorageServiceFactory 的隐藏依赖那样严重,但我在很大程度上同意你的方法。

    将工厂对象传递给类并让它创建存储服务,而不是工厂方法:

    public class MyController : ApiController
    {
        protected IStorageService StorageService;
    
        protected MyController(IStorageServiceFactory storageServiceFactory)
        {
            StorageService = storageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
        }
    }
    

    然后定义你的工厂接口和实现:

    public interface IStorageServiceFactory
    {
        IStorageService Create(ClaimsIdentity claimsIdentity);
    }
    
    public class StorageServiceFactoryImpl : IStorageServiceFactory
    {
        public IStorageService Create(ClaimsIdentity claimsIdentity)
        {
            return StorageServiceFactory.CreateStorageService(claimsIdentity);
        }
    }
    

    这样,您有一个构造函数,并且对存储服务工厂的依赖是明确的。


    关于您的更新:

    ...为了依赖注入而必须为工厂创建一个包装器和相应的包装器接口似乎很奇怪。

    嗯,这就是依赖注入的意义所在。

    我建议的包装器解决了两个问题:它消除了从类内部调用静态方法的需要(隐藏依赖项),并允许延迟解析(因为您的依赖项依赖于要创建的成员数据)。

    如果您有办法将创建 IStorageService 的依赖项更改为不依赖于您提供给它的类的成员,那么您可以直接传入一个(提供你可以告诉温莎如何创建一个)。

    【讨论】:

    • 感谢您的建议!我想你可能是在暗示没有工厂有更好的方法来做到这一点?请看我上面的更新。
    • 我并不是说没有工厂也能做到;您需要实例化对象以获取创建存储服务所需的信息。我看不到使用工厂的方法,除非您将创建存储服务的要求更改为不依赖类的实例数据。
    • 感谢您的更新。现在这没有任何意义。我同意从类内部调用静态方法是不好的,这就是我试图摆脱的。我只是希望有一种方法可以解决 CW 安装程序的嵌套依赖关系,但听起来好像没有办法做到这一点。
    • 没有办法做到这一点,只是因为依赖依赖于类本身的数据。我希望很清楚,在调用类的构造函数之前,您无法访问类的数据(如 User)。
    • 好的,有道理。我是 IOC 容器的新手,所以我不确定是否有一些在幕后实现的回调机制允许这样做。您的解决方案似乎有效。再次感谢!
    猜你喜欢
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2012-09-08
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多