9 Replies - 269 Views - Last Post: 16 July 2019 - 04:55 AM

#1 Yossu   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 01-November 18

How do I reduce the number of injected dependencies?

Posted 15 July 2019 - 07:47 AM

Not sure if it's relevant, but I'm using ASP.NET Core 2.2 (MVC), although I suspect the question applies equally to anywhere you use DI.

As part of a web site, we have an admin section. This is run from an Admin controller and provides admin facilities for all areas of the site. We inject various dependencies, includes repositories, services and so on.

The controller currently has 15 injected dependencies, which looks like a code smell to me. However, other than splitting the admin section down into multiple controllers (which I don't really want to do), I can't see how to avoid this.

Anyone able to advise? Thanks

Is This A Good Question/Topic? 0
  • +

Replies To: How do I reduce the number of injected dependencies?

#2 astonecipher   User is offline

  • Senior Systems Engineer
  • member icon

Reputation: 2906
  • View blog
  • Posts: 11,327
  • Joined: 03-December 12

Re: How do I reduce the number of injected dependencies?

Posted 15 July 2019 - 08:04 AM

Well, if you are using DI properly, it will only instantiate what it needs, no more. So if that is the count, that would be what it needs to create those object, no?
Was This Post Helpful? 0
  • +
  • -

#3 Yossu   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 01-November 18

Re: How do I reduce the number of injected dependencies?

Posted 15 July 2019 - 08:12 AM

It's not really a question of the cost of instantiation, as I think that would be negligible anyway, it's more that common wisdom (ie what I've read generally) seems to suggest that too many injected dependencies are a sign that your class has too many responsibilities.

Thanks
Was This Post Helpful? 0
  • +
  • -

#4 astonecipher   User is offline

  • Senior Systems Engineer
  • member icon

Reputation: 2906
  • View blog
  • Posts: 11,327
  • Joined: 03-December 12

Re: How do I reduce the number of injected dependencies?

Posted 15 July 2019 - 08:21 AM

Or that it is too complex, but you said it was a controller? As in an API controller? That is different than a class in my logic. Doing so in a class shows not enough abstraction, or not following SRP. A controller that sends different pieces to different classes is different, to me.


So, can you abstract it out? What DI system are you using?
Was This Post Helpful? 0
  • +
  • -

#5 Yossu   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 01-November 18

Re: How do I reduce the number of injected dependencies?

Posted 15 July 2019 - 09:50 AM

It's actually an MVC controller, but I have yet to see any major difference between API and MVC controllers to be honest. As I'm using ASP.NET Core, I'm using the built-in DI.

The site in question runs sales campaigns for companies. The site admins need to be able to maintain their customers, each customer's campaigns, each campaign's sales reps and sales. Each of those has its own list and add/edit actions, and needs a repository (customer repository, campaign repository, etc). Then there are common dependencies like a logger, a rendering engine that takes a Razor view and a view model and produces HTML for an email body, an email service and so on.

None of these individually are particularly complex, but by the time you put them all in one controller, we end up with 15 injected dependencies and over 1000 LOC (I know that's not necessarily an indicator of anything, I'm just adding it as an extra piece of information).

For example, here are some of the actions (this is C#, but I don't think that's relevant)...

    // Main campaign page, list all campaigns
    public async Task<IActionResult> Campaigns() {
      List<Campaign> campaigns = await _campaignRepository.GetAllAsync();
      List<CampaignViewModel> viewCampaigns = _mapper.Map<List<Campaign>, List<CampaignViewModel>>(campaigns);
      return View(viewCampaigns);
    }

    public async Task<IActionResult> NewCampaign() {
      List<Customer> customers = await _charityRepository.GetAllAsync();
      EditCampaignViewModel model = new EditCampaignViewModel {Customers = customers};
      return View(nameof(NewCampaign), model);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> NewCampaign(EditCampaignViewModel model) {
      if (!ModelState.IsValid) {
        return View(model);
      }
      Campaign existingCode = await _campaignRepository.GetCampaignByCodeAsync(model.Code.ToLower());
      if (existingCode != null) {
        ModelState.AddModelError("Code", "Already Exists");
        model.Customers = await _customerRepository.GetAllAsync();
        return View(model);
      }
      Campaign campaign = _mapper.Map<Campaign>(model);
      await _campaignRepository.InsertAsync(campaign);
      return RedirectToAction(nameof(Campaigns));
    }



There are similar actions for editing a campaign (GET and POST), as well as deleting one.

Rinse and repeat for each entity, and you end up with a lot of not very complex code with a lot of dependencies.

Don't know if that helps or confuses! Thanks for the reply.
Was This Post Helpful? 0
  • +
  • -

#6 astonecipher   User is offline

  • Senior Systems Engineer
  • member icon

Reputation: 2906
  • View blog
  • Posts: 11,327
  • Joined: 03-December 12

Re: How do I reduce the number of injected dependencies?

Posted 15 July 2019 - 10:06 AM

Based on the code, I would say the controller is muddied. There should be a separate controller for the Campaigns (I actually use to work for a company that did media buying), Customers, ect. The admin controller would be specific to admin functions; and the endpoints need to be set in the frontend to call the correct controller, rather than the admin controller, since a campaign is a separate entity and not something that the admin controller should handle.
Was This Post Helpful? 0
  • +
  • -

#7 Yossu   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 01-November 18

Re: How do I reduce the number of injected dependencies?

Posted 15 July 2019 - 10:35 AM

Hmm, I thought of that, but we already have a campaign controller (handles the campaigns on the public-facing part of the site), so it would mean having a CampaignAdmin controller (or similar), with the same for each entity. Ends up messy, albeit cleaner.
Was This Post Helpful? 0
  • +
  • -

#8 astonecipher   User is offline

  • Senior Systems Engineer
  • member icon

Reputation: 2906
  • View blog
  • Posts: 11,327
  • Joined: 03-December 12

Re: How do I reduce the number of injected dependencies?

Posted 15 July 2019 - 10:50 AM

Then you are breaking into a bad design. Shouldn't matter if it is for a nonAdmin or Admin user, the campaign functionality should still live in the proper controller and just restrict who has access to what methods within that controller a user can call.

Here's an example of the decorator used.
Was This Post Helpful? 1
  • +
  • -

#9 Yossu   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 01-November 18

Re: How do I reduce the number of injected dependencies?

Posted 15 July 2019 - 01:17 PM

Now there's an interesting way of looking at it. I'd always thought in terms of public vs private sections of the site. If I understand you correctly, you're saying that a controller should be responsible for all the actions related to one entity, whether public or private.

I like that idea, makes a lot of sense. We are already using attributes (including our own custom one) to restrict access to the admin actions, so that would stay the same irrespective of which controller they were on.

Thanks very much for the suggestion, I can see that this would clean the code up a lot, and reduce the number of dependencies needed.
Was This Post Helpful? 0
  • +
  • -

#10 Skydiver   User is online

  • Code herder
  • member icon

Reputation: 6992
  • View blog
  • Posts: 23,765
  • Joined: 05-May 12

Re: How do I reduce the number of injected dependencies?

Posted 16 July 2019 - 04:55 AM

Microsoft was not helping you either by making the base MVC project template have a separate admin controller and sub-area. It makes you believe that you should follow through with it.

In some ways separation by path makes things easier because the security can be put into the web.config to force authorization to happen before anything is accessed in the admin section. But as you've noticed, it can lead to having duplication of controllers across the admin and non-admin areas.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1