What is the difference between a component and a service dependency?

I am going to preface this question with the statement: I know that the following is a bad design, but refactoring is currently not an option, ideally this should be done using sniffers.

I am working on updating the lock from 1.6 (I think) to 3.3, which, unfortunately, is associated with some syntax changes, now everything compiles for me, but some of my tests around the service container do not work.

I have a repository that has several implementations to provide various functions, the repository is used only in all different inline implementations, here are the basic information about the code:

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

Repository Method:

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

Base interface:

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

Implementations:

 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 } } 

And finally, here is the error I get in my test:

Castle.MicroKernel.Handlers.HandlerException: Cannot create the AccountRepositoryFeedEntryDecorator component because it has dependencies that must be satisfied.

'AccountRepositoryFeedEntryDecorator' expects the following dependencies: - The component "Shaw.Services.CustomerManagement.Host.Repositories.Sql.Decorators.AccountRepositoryAuthorizationDecorator" (through redefinition), which was registered but also expects dependencies.

'Shaw.Services.CustomerManagement.Host.Repositories.Sql.Decorators.AccountRepositoryAuthorizationDecorator expects the following dependencies: - The "AccountRepositoryFeedEntryDecorator" service, which has been registered but also waits for dependencies.

At first glance, it seems that there is some kind of cyclical dependence, but I can’t figure out how to do it.

So, the question is in two parts, what is the difference between the specification of the dependencies of the component and the service in the error message, any guesses about what is going wrong.

If that matters, this is the original registration before the upgrade:

 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>() 
+6
source share
1 answer

The decorator is registered in the order of registration, and you do not need to specify the dependencies, so this will work as you expected:

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

Permission for an instance of IAccountRepository will give AccountRepositoryFeedEntryDecorator , which will AccountRepositoryAuthorizationDecorator , etc.


As for your question, this page does a great job explaining the differences between services, components, and dependencies, as the terms are used in the library. Essentially:

  • A service is a contract of functionality, usually an interface or a delegate. It is abstract.
  • A component is an implementation of a service, usually a class. This is concrete.
  • Dependency is a service that uses a component.

In the error message, the first bit:

Castle.MicroKernel.Handlers.HandlerException: Cannot create the AccountRepositoryFeedEntryDecorator component because it has dependencies that must be satisfied.

Good, therefore, a component / class cannot be created because its dependencies cannot be satisfied. This dependency is the IAccountRepository decoratedRepository parameter in the constructor.

"AccountRepositoryFeedEntryDecorator" expects the following dependencies: - The component "AccountRepositoryAuthorizationDecorator" (through redefinition) that has been registered but also expects dependencies.

We are still talking about the same component / class, and it says that it tried to use the AccountRepositoryAuthorizationDecorator component / class to fulfill its dependency, but this class also has dependencies.

AccountRepositoryAuthorizationDecorator expects the following dependencies: - The AccountRepositoryFeedEntryDecorator service, which has been registered but also expects dependencies.

And we came to the first class, so there is a circular dependence. This is due to the disconnection between the name set in RepositoryRegistration and the name computed when passing the Dependency.OnComponent type. For the former, you use Type.Name (ie, “AccountRepositoryFeedEntryDecorator”), and for the latter, Windsor uses Type.FullName under covers (ie, “Your.Assembly.Name, AccountRepositoryFeedEntryDecorator”).

Due to the name mismatch, when Windsor tries to fulfill the dependency you specified, it will skip registration for it because it has a different name. As a result, he does everything possible without information and (I suppose) finds the first IAccountRepository , which is not the component itself - it can be inserted as a dependency. This happens again with this dependency, which is the first component we started working with, setting the circular dependency.

You could solve this by removing the Named registration part or passing typeof(AccountRepositoryAuthorizationDecorator).Name to Dependency.OnComponent instead of the type itself.

+6
source

Source: https://habr.com/ru/post/974711/


All Articles