0

Please see the code below, which I took from Jimmy Bogards Wicked domain models:

public class OfferAssignmentService
    {
        private readonly IMemberRepository _memberRepository;
        private readonly IOfferTypeRepository _offerTypeRepository;
        private readonly IOfferValueCalculator _offerValueCalculator;
        private readonly IOfferRepository _offerRepository;

        public OfferAssignmentService(
            IMemberRepository memberRepository,
            IOfferTypeRepository offerTypeRepository,
            IOfferValueCalculator offerValueCalculator,
            IOfferRepository offerRepository
            )
        {
            _memberRepository = memberRepository;
            _offerTypeRepository = offerTypeRepository;
            _offerValueCalculator = offerValueCalculator;
            _offerRepository = offerRepository;
        }

        public void AssignOffer(Guid memberId, Guid offerTypeId)
        {
            // Retreive
            var member = _memberRepository.GetById(memberId);
            var offerType = _offerTypeRepository.GetById(offerTypeId);

            // Delegate to business objects
            var offer = member.AssignOffer(offerType, _offerValueCalculator);

            // Save
            _offerRepository.Save(offer);
        }
    }

Why are the repositories injected into the service? Say I have an app, which has four clients (mobile; WPF; MVC4; Win Forms), then all these clients have to create instances of these repositories and pass them to the service. Why does the service not just create them i.e. in one place.

I am obviously missing something here.

Update

If I create the repositories in the Serivce layer then their are four dependencies i.e. one for _memberRepository; one for _offerTypeRepository; one for _offerValueCalculator and one for _offerRepository. If I create all these instances in the four clients then I am creating 16 dependencies i.e. 4*4. I realise I am missing something fundamental here.

w0051977
  • 15,099
  • 32
  • 152
  • 329
  • You're basically asking "whats the point of dependency injection." –  May 30 '17 at 20:04
  • Perhaps depending on where the service is used, it should use a different implementation of each repository? The service doesn't care how the repositories are implemented, only that they correctly implement the interfaces that it requires. Plus, if you want to unit test this service, you need an easy way to swap out different repositories without using an actual repository. – mason May 30 '17 at 20:04
  • 1
    Possible duplicate of [Why does one use dependency injection?](https://stackoverflow.com/questions/14301389/why-does-one-use-dependency-injection) –  May 30 '17 at 20:06
  • @Amy, I do understand the benefits of dependency injection (I use it a lot). – w0051977 May 30 '17 at 20:06
  • 2
    If you understood the benefits, then you wouldn't be asking this question. It's okay to not understand, that's fine. But it's clear by what you're asking that you don't. – mason May 30 '17 at 20:07
  • Then why are you asking why they inject the services? –  May 30 '17 at 20:08
  • @Mason, I have updated the question in an attempt to explain my confusion. – w0051977 May 30 '17 at 20:11
  • Your update has not explained anything further. You don't understand why we use Dependency Injection. You can read the question Amy linked to, you can do some research, [watch some videos](https://channel9.msdn.com/Events/TechEd/NorthAmerica/2014/DEV-B412) etc. – mason May 30 '17 at 20:12
  • "Service" is as useless a term as "Manager". What does this code do, where does it live? Where do you think the duplication of dependencies comes from? If this "service layer" actually lives inside the client, and you create two totally separate applications using this service internally, why do you find it strange that you need to initialize this service twice? – CodeCaster May 30 '17 at 20:14
  • "If I create all these instances in the four clients then I am creating 16 dependencies i.e. 4*4." Okay? What is the issue with that? –  May 30 '17 at 20:17
  • @Amy, 4 dependencies is better than 16. – w0051977 May 30 '17 at 20:24
  • @w0051977 Why? Because 4 is a smaller number? If you have a different implementation of each dependency for each client type, then 16 is perfectly reasonable. – mason May 30 '17 at 20:25
  • @w0051977 Why is 4 dependencies better than 16? –  May 30 '17 at 20:26
  • @Amy, "a different implementation of each dependancy". That is the light bulb moment. Thank you. Thanks also to Mason who said it above as well. – w0051977 May 30 '17 at 20:27
  • Even if they were the same implementation used on each of the clients, it's useful for unit testing. You can mock things easier with interfaces. – mason May 30 '17 at 20:31
  • @Amy, why would a mobile client require a different implementation of a repository e.g. _memberrepository to say a web client? I now understand why repositories are injected, however I am trying to understand a scenario when this happens. – w0051977 May 30 '17 at 20:31
  • An MVC site may store member data in an MS SQL Server. A mobile client may store data in a JSON file, or SQLite etc. – mason May 30 '17 at 20:35
  • @w0051977 hypothetical situation: your boss comes up to your desk, sips his coffee, and says "heeeey, woo51977, i need this mobile client to support A/B testing. Half of them will use the existing repository. The other half will use the new HypotheticalRepository. Don't modify the existing repository. Don't touch the other mobile clients. Just this one. Oh, and I'm gonna need you to come in on Saturday." –  May 30 '17 at 20:37
  • @Mason, thanks. That is great. – w0051977 May 30 '17 at 20:37
  • @Mason, if you would like to post and answer then please do so that I can allocate credit. – w0051977 May 30 '17 at 20:38
  • @Amy, "Don't modify the existing repository". That is very helpful. Thank you. If you would like to post an answer then please do so that I can give some credit. – w0051977 May 30 '17 at 20:42
  • I'm still gonna need you to come in on Saturday. –  May 30 '17 at 20:44
  • @Amy, please see Scot Hansens' answer below. Does this not contradict your argument (I could be wrong). – w0051977 May 30 '17 at 20:55
  • @Mason, Please see the comment above. – w0051977 May 30 '17 at 20:55
  • I'm really just taking a stab at what I think the OP means. @Amy and others may be interpreting the question differently. We may be answering totally different questions so I don't think there's any contradiction. – Scott Hannen May 30 '17 at 20:56
  • I don't think so? What do you think is contradictory? –  May 30 '17 at 20:56
  • @Amy, because Scot Hansen says: "the clients shouldn't be responsible for "knowing" about all of the dependencies " and you say they should. I think Mason understands (see his comment under Scot Hansens' answer). Thanks again. – w0051977 May 30 '17 at 21:00
  • @w0051977 the `OfferAssignmentService` doesn't have to know how its dependencies are implemented. Those are configured elsewhere, at the top level of the application. –  May 30 '17 at 21:01
  • I understand. @Amy is talking about the class level. As she says, `OfferAssignmentService` doesn't know about the implementation of its dependencies. That's the whole idea of dependency inversion. I'm referring to a different level. There is going to be a configuration class the *does* define all of the specifics of each dependency for your container. The client doesn't need to know all of those details any more than `OfferAssignmentService` does. – Scott Hannen May 30 '17 at 21:16
  • @Scott Hannen, what level are you talking? – w0051977 May 30 '17 at 21:26
  • The level at which the client configures its dependency on `OfferAssignmentService`. – Scott Hannen May 30 '17 at 21:52

1 Answers1

1

Your individual clients shouldn't be responsible for knowing how to configure these dependencies in detail. If your client depends on OfferAssignmentService then it shouldn't be responsible for knowing about all of the dependencies for that class, like the repositories, and the dependencies of those repositories, etc. If that code is duplicated wherever OfferAssignmentService is used then that can be improved.

Ideally there would be a single configuration class which serves as the composition root for this service layer, and that class would be referenced and used by clients to configure the dependencies for your service. The specifics vary depending on the container you're using. For example, with Windsor I would create a class that inherits from AbstractFacility. My client would simply do this:

container.AddFacility<OfferAssignmentServiceFacility>();

That facility would handle configuring all of the dependencies with my container.

In Unity it would be a class that inherits from UnityContainerExtension, and very similar to Windsor, you would do

container.AddNewExtension<OfferAssignmentServiceExtension>();

What they have in common is that they pass the container to the configuration class, allowing that class to configure the container with the dependencies it needs.

If you don't mind your service being tightly coupled to a container framework you can put that code directly in your service library. I like to make my libraries container-agnostic (they don't need one particular brand of DI container to work.) So I'll put the facility or extension in a separate library.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
  • Hannen, thanks. That is what I thought. I was experimenting with Castle Windsor WCF earlier today. However, your answer seems to contradict what Amy and Mason said in the comments under my OP. – w0051977 May 30 '17 at 20:54
  • 1
    I find your answer confusing, particularly your opening paragraph. Where should the DI container be configured, if not for in the client application? – mason May 30 '17 at 20:57
  • The client would execute the configuration, but the detailed code for configuring all of the dependencies doesn't need to be in the client. It could be either in the service assembly or in a separate assembly. The client is just executing a statement that performs the configuration. The two sample statements in my answer would be executed by the client. But the code for the facility or container extension would be somewhere else. I'll clarify my answer. – Scott Hannen May 30 '17 at 20:59
  • I still find your answer confusing. Generally the top level application is responsible for setting up the DI container, specifying how dependencies should be resolved. That contradicts your opening paragraph. – mason May 31 '17 at 13:19
  • The top level is responsible for making it happen, but not for knowing how it's done. If I have a WCF service or API that depends on a library, the dependencies for the library have to be set up in the composition root of my app. But that doesn't mean that my app is going to contain the details. My app will say `container.AddFacility()`. That way my app can depend on the service without having to contain details about how the dependencies of that service are set up. – Scott Hannen May 31 '17 at 15:48