Is it correct to pass dependencies to a class that does not use it itself, but passes it to some internally used classes

It is this blog that bothers me: http://ayende.com/blog/124929/your-ctor-says-that-your-code-is-headache-inducing-explanation

Say I have a class library that provides access control services. I don’t want to use any IoC container in the library itself, so that it can be easily tested (so that everything is entered, but there is no container. It results in the library itself). (WCF and other websites using this library will use some container to embed dependencies in the constructor.)

Say my main class is as follows:

public class UserAccessManagement { private readonly IUserRepository _repo; private readonly IHashProvider _hash; private readonly ITokenEncryptor _tokenEnc; public UserAccessManagement(IUserRepository repo, IHashProvider hash, ITokenEncryptor tokenEnc) { _repo = repo; _hash = hash; _tokenEnc = tokenEnc; } public void GrantAccess(string username, string resource) { User user = repo.FindUser(username); new AccessGateKeeper(user.SpnTicket, _hash, _tokenEnc) .GrantAccess(resource); } } 

As you can see, the hash and tokenEnc are not actually used by the class, but must be passed to the constructor, because inside it must pass it to the gate. The specific implementation of the gatekeeper should be an internal and closed class for security reasons, so it cannot be entered into the constructor itself, which would solve the problem.

This way you get a lot of dependencies introduced through the constructor, although this does not necessarily mean that the class itself does too much. The blog says it's awful. Is there a better or more correct way to deal with these three requirements:

  • AccessGateKeeper must be internal and private.
  • Missing IoC in the class library for testing.
  • Do not want to use property / method injection, as it is less reliable.
+4
source share
1 answer

The rule of not taking a dependency is to simply pass it correctly, but from the point of view of your public API, this is not what you are doing. Since AccessGateKeeper is internal, it is not part of the public API - it is an implementation detail . This could be a private helper function of the UserAccessManagement class.

Thus, from a public point of view, the UserAccessManagement class UserAccessManagement not accept the dependency "just pass it". Instead, you can say that the UserAccessManagement class requires IUserRepository , IHashProvider and ITokenEncryptor .

However, from a support point, the current implementation is closely related to UserAccessManagement and AccessGateKeeper , which may or may not be a problem. However, if this is a problem, you might consider porting the desired behavior to the interface. Mechanical extraction may look like this:

 public interface IAccess { void Grant(object ticket, string resource) } 

Using this interface, you can change the implementation of UserAccessManagement to:

 public class UserAccessManagement { private readonly IUserRepository _repo; private readonly IAccess _access; public UserAccessManagement(IUserRepository repo, IAccess access) { _repo = repo; _access = access; } public void GrantAccess(string username, string resource) { User user = repo.FindUser(username); _access.Grant(user.SpnTicket, resource); } } 

An IAccess implementation might look like this:

 public class Access : IAccess { private readonly IHashProvider _hash; private readonly ITokenEncryptor _tokenEnc; public Access(IHashProvider _hash, ITokenEncryptor _tokenEnc) { _hash = hash; _tokenEnc = tokenEnc; } public void Grant(object ticket, string resource) { new AccessGateKeeper(ticket, _hash, _tokenEnc) .GrantAccess(resource); } } 
+5
source

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


All Articles