developer9969
developer9969

Reputation: 5236

Why pass a parameters of multiple services to mvc controller?

I'm new to asp.net mvc world mostly a windows developer moving to web. Be nice...

I found ridiculous when I look at many examples of asp.net mvc web applications that the pass to their controllers a list of services

Like this

public CustomerController(ICustomerService customerService,
                IAnotherService anotherService,
                IYetAnotherService yetAnotherService,
                IYetAgainAnotherService yetAgainAnotherService,
                etc...

Would not be better to do something like

public CustomerController(IServices services)
{
}

public interface IServices 
{
    ICustomerService  CustomerService{get;set;}
    IAnotherServiceService  AnotherService{get;set;}
    IYetAnotherServiceService  YetAnotherServiceService{get;set;}       
}

Am I missing the obvious?

As anybody implemented the way I suggest in mvc4 or mvc5. I know mvc6 does it. But I cannot use mvc6 at work.

Any samples using DI?

Thanks

Upvotes: 1

Views: 1171

Answers (3)

alltej
alltej

Reputation: 7285

When you have code in the API controllers that look like this:

public CustomerController(ICustomerService customerService,
                IAnotherService anotherService,
                IYetAnotherService yetAnotherService,
                IYetAgainAnotherService yetAgainAnotherService,
...

That can be a code-smell and is an opportunity to refactor. But this does not mean the original code was a bad design. What I mean is in the API layer, we try not to clutter it with too many services that the controller is dependent on. Instead you can create a facade service. So in your example above, you refactor it to look like this:

public CustomerController(IServices services)
{
}

public interface IServices 
{
    ICustomerService  CustomerService{get;set;}
    IAnotherServiceService  AnotherService{get;set;}
    IYetAnotherServiceService  YetAnotherServiceService{get;set;}       
}

Which is good and then you can move the IServices to your service/business layer. The concrete implementation of that in the service/business layer will look like this:

public class AConcreteService:IServices {
public AConcreteService(ICustomerService cs, IAnotherServiceService as,  IYetAnotherServiceService yas)
{
         ...
}

public List<Customer> GetCustomers(){
   return _cs.GetCustomers();
}

public List<string> GetAnotherServiceData(){
   return _as.AnotherServiceData();
}

public List<string> GetYetAnotherServiceData(){
   return _yas.YetAnotherServiceData();
}
...

So that code will end up looking like your original code when implemented directly in the controller but is now in the service/business layer. This time it will be easy to unit test in the service class and the API layer will look much cleaner.

Upvotes: 0

Steven
Steven

Reputation: 172666

What you're missing here is the fact that constructors with many parameters is a code smell often caused by that class having to many responsibilities: it violates the Single Responsibility Principle.

So instead of packaging the services to inject into a 'container' class that allows those services to be accessible using a public property, consider the following refactorings:

  • Divide the class into multiple smaller classes.
  • Extract logic that implements cross-cutting concerns (such as logging, audit trailing, validation, etc, etc)out of the class and apply those cross-cutting concerns using decorators, global filters (MVC) or message handlers (Web API). A great pattern for your business logic is the command/handler pattern.
  • Extract logic that uses multiple dependencies out of the class and hide that logic behind a new abstraction that does not expose the wrapped dependencies. This newly created abstraction is called an Aggregate Service.

Upvotes: 3

Darin Dimitrov
Darin Dimitrov

Reputation: 1038890

I agree that for readability sake, even if you have multiple existing services which are also used in other applications, you could always wrap them in another class to avoid passing a long list of dependencies to the controllers.

Upvotes: 0

Related Questions