组件和服务依赖项之间有什么区别?

时间:2014-09-02 19:52:10

标签: c# castle-windsor

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

我正在努力将城堡从1.6(我认为)升级到3.3,遗憾的是它涉及一些语法更改,我现在已经编译了所有内容,但我对服务容器的一些测试无效。

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

Castle Windsor注册:

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>()

1 个答案:

答案 0 :(得分:7)

装饰器注册按注册顺序进行,并且您不需要指定依赖项,因此这将按照您的预期运行:

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”),而后者使用Type.FullName封面(即“Your.Assembly.Name,AccountRepositoryFeedEntryDecorator”)。

由于命名不匹配,当Windsor尝试实现您指定的依赖项时,它将错过其注册,因为它具有不同的名称。因此,它可以在没有信息的情况下做到最好,并且(我假设)找到第一个IAccountRepository - 这不是组件本身 - 它可以作为依赖项插入。这种依赖性再次发生,这是我们开始的第一个组件,给出了循环依赖。

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