【问题标题】:What is the difference between a Component and a Service dependency?组件和服务依赖有什么区别?
【发布时间】:2014-09-02 19:52:09
【问题描述】:

我将在这个问题的开头声明:我知道以下是糟糕的设计,但重构目前不是一种选择,理想情况下应该使用拦截器来完成。

我正在努力将城堡从 1.6(我认为)升级到 3.3,不幸的是这涉及到一些语法更改,我现在已经编译了所有内容,但是我围绕服务容器的一些测试不起作用。

我有一个存储库,它有几个实现来提供不同的功能,该存储库只用于内联所有不同的实现,这里是代码的基础:

温莎城堡注册:

RepositoryRegistration<IAccountRepository, AccountRepositoryFeedEntryDecorator>()
    .DependsOn(Dependency.OnComponent("decoratedRepository", typeof(AccountRepositoryAuthorizationDecorator))),
RepositoryRegistration<AccountRepositoryAuthorizationDecorator>()
    .DependsOn(Dependency.OnComponent("decoratedRepository", typeof(AccountRepositoryMaskingDecorator))),
RepositoryRegistration<AccountRepositoryMaskingDecorator>()
    .DependsOn(Dependency.OnComponent("decoratedRepository", typeof(AccountRepository))),
RepositoryRegistration<AccountRepository>());

RepositoryRegistration 方法:

private static ComponentRegistration<TRepository> RepositoryRegistration<TRepository, TConcreteRepository>()
    where TConcreteRepository : TRepository where TRepository : class
{
    return Component
               .For<TRepository>()
               .ImplementedBy<TConcreteRepository>()                    
               .Named(typeof(TConcreteRepository).Name);
}

基本接口:

public interface IAccountRepository
{
    string Create(Account account);
    void Update(Account account);
    Account Get(string accountId);
}

实现:

public class AccountRepositoryFeedEntryDecorator : IAccountRepository
{
    private readonly IAccountRepository decoratedRepository;
    public AccountRepositoryFeedEntryDecorator(
        IAccountRepository decoratedRepository)
    {
        this.decoratedRepository = decoratedRepository;
    }

    string Create(Account account)
    {
        //Add Entry To Feed
        return decoratedRepository.Create(account);
    };

    void Update(Account account)
    {
        //Add Entry To Feed
        return decoratedRepository.Udpate(account);
    }
    Account Get(string accountId);
    {
        //Add Entry To Feed
        return decoratedRepository.Get(accountId);
    }
}

public class AccountRepositoryAuthorizationDecorator : IAccountRepository
{
    private readonly IAccountRepository decoratedRepository;
    public AccountRepositoryAuthorizationDecorator(
        IAccountRepository decoratedRepository)
    {
        this.decoratedRepository = decoratedRepository;
    }

    string Create(Account account)
    {
        //Ensure User Is Authorized
        return decoratedRepository.Create(account);
    };

    void Update(Account account)
    {
        //Ensure User Is Authorized
        return decoratedRepository.Udpate(account);
    }
    Account Get(string accountId);
    {
        //Ensure User Is Authorized
        return decoratedRepository.Get(accountId);
    }
}

public class AccountRepositoryMaskingDecorator : IAccountRepository
{
    private readonly IAccountRepository decoratedRepository;
    public AccountRepositoryMaskingDecorator(
        IAccountRepository decoratedRepository)
    {
        this.decoratedRepository = decoratedRepository;
    }

    string Create(Account account)
    {
        //Mask Sensitive Information
        return decoratedRepository.Create(account);
    };

    void Update(Account account)
    {
        //Mask Sensitive Information
        return decoratedRepository.Udpate(account);
    }
    Account Get(string accountId);
    {
        //Mask Sensitive Information
        return decoratedRepository.Get(accountId);
    }
}

public class AccountRepository : IAccountRepository
{       
    string Create(Account account)
    {
        //Create account and return details
    };

    void Update(Account account)
    {
        //Update account and return details
    }
    Account Get(string accountId);
    {
        //Return Account
    }
}

最后这是我在测试中遇到的错误:

Castle.MicroKernel.Handlers.HandlerException : 无法创建组件“AccountRepositoryFeedEntryDecorator”,因为它需要满足依赖关系。

'AccountRepositoryFeedEntryDecorator' 正在等待以下依赖项: - 已注册但也在等待依赖项的组件“Shaw.Services.CustomerManagement.Host.Repositories.Sql.Decorators.AccountRepositoryAuthorizationDecorator”(通过覆盖)。

'Shaw.Services.CustomerManagement.Host.Repositories.Sql.Decorators.AccountRepositoryAuthorizationDecorator' 正在等待以下依赖项: - 服务“AccountRepositoryFeedEntryDecorator”已注册但也在等待依赖项。

乍一看,似乎发生了某种循环依赖,但我看不出是如何发生的。

所以问题分为两部分,错误信息中的组件和服务依赖规范有什么区别,有什么问题的猜测。

如果这里重要的是升级前的原始注册:

RepositoryRegistration<IAccountRepository, AccountRepositoryFeedEntryDecorator>()
    .ServiceOverrides(new { decoratedRepository = typeof(AccountRepositoryAuthorizationDecorator).Name }),
RepositoryRegistration<AccountRepositoryAuthorizationDecorator>()
    .ServiceOverrides(new { decoratedRepository = typeof(AccountRepositoryMaskingDecorator).Name }),
RepositoryRegistration<AccountRepositoryMaskingDecorator>()
    .ServiceOverrides(new { decoratedRepository = typeof(AccountRepository).Name }),
RepositoryRegistration<AccountRepository>()

【问题讨论】:

    标签: c# castle-windsor


    【解决方案1】:

    装饰器注册按注册顺序进行,您不需要指定依赖项,所以这会像您期望的那样工作:

    container.Register(
        RepositoryRegistration<IAccountRepository, AccountRepositoryFeedEntryDecorator>(),
        RepositoryRegistration<IAccountRepository, AccountRepositoryAuthorizationDecorator>(),
        RepositoryRegistration<IAccountRepository, AccountRepositoryMaskingDecorator>(),
        RepositoryRegistration<IAccountRepository, AccountRepository>()
    );
    

    解析IAccountRepository 的实例将产生一个AccountRepositoryFeedEntryDecorator,它装饰一个AccountRepositoryAuthorizationDecorator 等。


    关于您的问题,this page 很好地解释了服务、组件和依赖项之间的差异,因为这些术语在库中使用。本质上:

    • 服务 是某种功能契约,通常是接口或委托。它是抽象的。
    • 组件 是服务的实现,通常是一个类。它是具体的。
    • 依赖是组件使用的服务。

    在您的错误信息中,第一位是:

    Castle.MicroKernel.Handlers.HandlerException : 无法创建组件“AccountRepositoryFeedEntryDecorator”,因为它需要满足依赖关系。

    好的,因此无法创建 组件/,因为它的依赖项无法满足。它的依赖是构造函数中的IAccountRepository decoratedRepository 参数。

    “AccountRepositoryFeedEntryDecorator”正在等待以下依赖项: - 组件“AccountRepositoryAuthorizationDecorator”(通过覆盖)已注册但也在等待依赖项。

    我们仍在谈论同一个组件/类,它表示它正在尝试使用组件/类AccountRepositoryAuthorizationDecorator 来满足其依赖关系,但该类也具有依赖关系。

    “AccountRepositoryAuthorizationDecorator”正在等待以下依赖项: - 服务“AccountRepositoryFeedEntryDecorator”已注册但也在等待依赖项。

    我们已经来到了第一类,所以有一个循环依赖。这是因为RepositoryRegistration 中设置的名称与将类型传递给Dependency.OnComponent 时计算的名称之间存在脱节。对于前者,您使用的是Type.Name(即“AccountRepositoryFeedEntryDecorator”),而对于后者,Windsor 使用的是Type.FullName(即“Your.Assembly.Name, AccountRepositoryFeedEntryDecorator”)。

    由于命名不匹配,当 Windsor 尝试满足您指定的依赖项时,它将错过注册,因为它具有不同的名称。结果,它在没有信息的情况下尽其所能,并且(我假设)找到第一个IAccountRepository——这不是组件本身——它可以作为依赖项插入。这种依赖再次发生,这是我们开始使用的第一个组件,提供循环依赖。

    您可以通过删除注册的Named 部分,或者将typeof(AccountRepositoryAuthorizationDecorator).Name 传递给Dependency.OnComponent 而不是类型本身来解决此问题。

    【讨论】:

    • 嗨帕特里克,我刚刚尝试了这个解决方案,但现在我收到一个错误,首先抱怨它指向服务,然后说还有其他匹配的组件并继续具有相同的'循环'依赖问题。
    • 我回头一看,这看起来完全是一个完全不同的注册问题。
    • @Phaeze Ah 好的,如果它是相关的,请随时更新您的问题,否则它可能完全作为一个新问题有意义。
    • OK 解决了另一个问题,我的所有测试现在都通过了。而且我的注册码也干净多了。感谢您指出这一点。
    • @Phaeze 在这一点上有点学术,但请参阅更新的答案。
    猜你喜欢
    • 2012-02-11
    • 1970-01-01
    • 1970-01-01
    • 2014-12-09
    • 2015-11-13
    • 2019-01-11
    • 1970-01-01
    • 1970-01-01
    • 2011-05-12
    相关资源
    最近更新 更多