Numerous business logic services within my program need access to a common set of non-business logic services, such as email, printing, messaging (message boxes and prompts), and logging. I am planning on creating a facade to encapsulate EmailService, PrintService, MessageService, and LogService so that each business logic service just needs one constructor parameter to the facade class, instead of four parameters to each of the services.
So instead of
public BusinessLogicService(IEmailService emailService, IPrintService printService, IMessageService messageService, ILogService logService)
{
this.EmailService = emailService;
this.LogService = logService;
this.MessageService = messageService;
this.PrintService = printService;
}
I'll have this
public BusinessLogicService(ISomeFacade facade)
{
this.SomeFacade = facade;
}
My questions are:
Is this the correct usage of the facade pattern? If not, how should I be doing this?
I assume that having a standard set of services that are needed by a lot of business services is pretty common, so is there a standard naming convention for this sort of facade that encapsulates EmailService, PrintingService, MessagingService, LoggingService, and possibly some other non-business logic services that I need in the future?
What you've described is not facade but rather service locator (see for discussion on that pattern - Is ServiceLocator an anti-pattern?). Note that trouble coming up with the name is very good sign of creating IKitchenSink interface.
To be facade it must somehow simplify interaction with the services - maybe have one ArchveMessage call that will orchestrate working with all 4 services.
Number of constructor parameters generally does not matter* since one likely will be creating such objects with dependency injection framework anyway. Using DI framework may also take care of most "logging" responsibility by providing a way to log start/end/error cases for all method calls.
*) large number of injected dependencies indicate too many responsibilities of the class and need to be looked at from that point of view.
Related
I'm working on a domain model writing my software all DDD and stuff doing a great job, when I suddenly bump into the same problem I have been facing over and over again and now it's time to share some insights. The root of the problem lies in the uniqueness of data.
For example, let's say we're writing this awesome domain model for a user. Obviously the username is unique and just to be as flexible as possible we want the user to be able to change his name, so I implemented the following method:
public void SetUsername(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new UserException(UserErrorCode.UsernameNullOrEmpty,
"The username cannot be null or empty");
}
if (!Regex.IsMatch(value, RegularExpressions.Username))
{
throw new UserException(UserErrorCode.InvalidUsername,
"The username {value} does not meet the required ");
}
if (!Equals(Username, value))
{
Username = value;
SetState(TrackingState.Modified);
}
}
Again, this is all fine and fancy, but this function lacks the ability to check if the username is unique or not. So writing all these nice articles about DDD, this would be a nice use-case for a Domain Service. Ideally, I would inject that service using dependency injection but this ruins the constructor of my domain model. Alternatively, I can demand an instance of a domain service as a function argument like so: public void SetUsername(string value, IUsersDomainService service) and to be honest I don't see any solid alternatives.
Who has faced this problem and maybe came up with a nice rock-solid solution?
I agree with #TomTom. But as most times with software decisions, it depends, there is almost always a tradeoff. As a rule of thumb, you gain more by not injecting a domain service into an entity. This is a common question when one is starting with DDD and CQRS+ES. And has been thoroughly discussed in the CQRS mailing list here
However, there are some cases where the approach you suggested (known as method injection) might be beneficial it depends on the scenario. I’ll try and drive some analysis points next.
Consider the case where you want to make some validation before creating an entity. Let's think of a hypothetical and way oversimplified international banking context, with the following entity:
public class BankNote
{
private BankNote() {}
public static FromCurrency(
Currency currency,
ISupportedCurrencyService currencyService)
{
currencyService.IsAvailable(currency);
}
}
I am using the factory method pattern FromCurrency inside your entity to abstract the entity creation process and add some validation so that the entity is always created in the correct state.
Since the supported currencies might change overtime, and the logic of which currencies are supported is a different responsibility than the bank note issuing logic, injecting the ISupportedCurrencyService in the factory method gives us the following benefits:
By the way, the method dependency injection for domain services is suggested in the book: Hands-On Domain-Driven Design with .NET Core
By Alexey Zimarev. Chapter 5 "Implementing the Model" page 120
Pros
The BankNote is always created with a supported Currency, even if the currencies supported change overtime.
Since we are depending on an interface instead of a concrete implementation, we can easily swap and change the implementation without changing the entity.
The service is never stored as an instance variable of the class, so no risk of depending on it more than we need.
Cons
If we keep going this way we might add a lot of dependencies injected into the entity and it will become hard to maintain overtime.
We still are adding a loosely coupled dependency to the entity and hence the entity now needs to know about that interface. We are violating the Single Responsibility Principle, and now you would need to mock the ISupportedCurrencyService to test the factory method.
We can’t instantiate the entity without depending on a service implemented externally from the domain. This can cause serious memory leak and performance issues depending on the scenario.
Another approach
You can avoid all the cons if you call the service before trying to instantiate the entity. Say having a different class for the factory instead of a factory method, and make that separate factory use the ISupportedCurrencyService and only then call the entity constructor.
public class BankNoteFactory
{
private readonly ISupportedCurrencyService _currencyService;
private BankNoteFactory(
ISupportedCurrencyService currencyService)
=> _currencyService = currencyService;
public BankNote FromCurrency(
Currency currency)
{
if(_currencyService.IsAvailable(currency))
return new BanckNote(currency);
// To call the constructor here you would also need
// to change the constructor visibility to internal.
}
}
Using this approach you would end with one extra class and an entity that could be instantiated with unsupported currencies, but with better SRP compliance.
Im new in MVC pattern but im involved in a project which i am asked to implement repository pattern and unit of work,tons of examples online with 100 different implementations thats also a pain,because there is no clear way,any way,here is what i am doing and i would like you to give me a reason why should i use this damn pattern:
i have many controllers i instantiate the the model,and use it in my controller:
public CentralEntities DB = new CentralEntities();
i use it in my controller for example like this:
var turbineid = (from s in DB.MasterDatas
where s.name == turbinename
select new TrBineId
{
turbineID = s.m_turbine_id
}).Single();
TrBineId is my viewModel,any way the number of controllers are increasing and also in each controller i have many different LINQ,should i start with generic repository?
The damn reason to use repository pattern lies in implementing your solution with a clear separation of concerns and leverage domain I/O in a way that can be reused across your codebase.
You should start to revisit OOP and you'll need to double-check repository pattern.
At the end of the day, the need for certain patterns is already there, but it'll arise in your mind once you put the pieces in order.
I would start following some tutorial around the net about repository pattern to implement a proof-of-concept project and realize how it works.
Finally, Inversion of Control and Dependency Injection are concepts you'll need to manage to integrate your repositories and other patterns in your project to increase code composability and testability.
DISCLAMER: The following links are from my website about software architecture. You might want to check them as a possible reference implementation of repository pattern:
Repository
Agnostic repository
The repository pattern allows you to use the concept of Single responsibility principle, which mean (as an overview) one class = one role.
Your controler class is here for managing the request (Get, Post) and send back a response (FileResult, ActionResult...).
For the Data access (DAL, DAO) you will usually create a class per model entity (ClientRepository, CommandRepository), and you will create your methods for getting them (GetClients(), GetOneClientById(int id)...) within this class.
Edit for clarification after Matías comment:
This class will be called in your controller through his interface that you will also implement (with IOC or not).
You will then create a class instance of ClientRepository in your controller, but assigned to a reference of the interface type (IClientRepository).
**End Edit **
So we can imagin for Client Entity:
ClientController(All route for clients data)
IClientRepository (interface)
ClientRepository (Class which implement IClientRepository )
Then, in your controller you will call the repository like
IClientRepository clientRepo = new ClientRepository();
And then use the methods:
ICollection<Client> clients = clientRepo.YourMethod(int param1);
Advantages:
First of all, your code will be more clear and maintainable. Your DAO (DAL in .net) will keep the data access layer and you could use the GetAllClients method many time and you will not repeat yourself (DRY).
You can also apply easily some param on the method (like order, limit for pagination etc...)
It will be testable as well, I don't think that calling database in the controller can give you reasonable unit test results. You will also catch excption with a more "elegant way".
Small tip : When you will have more experience in the repo pattern, you could have a look at the Inversion of Control pattern
In the following example, the AccountService and ProductService are in an ASP.NET MVC app. The AccountWebAPI and ProductWebAPI are externally hosted API micro services.
1) Can I eliminate the ProductService and orchestrate the retrieving of the orders in the CustomerAccountController itself? This is because I consider the Controller as the Application layer/service which is mentioned in the DDD (Domain Driven Design).
2) Am I violating the n-layer architecture because the ProductService calls the AccountService which is the same layer?
3) Since AccountWebAPI and ProductWebAPI are micro services, do they have to be separated as AccountService and ProductService in the client application (MVC App) also to keep the Separation Of Responsibility? So the ProductService needs to be renamed as ProductAppService and ProductService should interact with ProductWebAPI only like AccountService talks to AccountWebAPI.
public class CustomerAccountController : Controller
{
IProductService _productService;
public CustomerAccountController(IProductService productService)
{
_productService = productService;
}
public IActionResult Index()
{
return View();
}
public IActionResult Account(int customerId)
{
var orders = _productService.GetOrders(customerId);
return View(orders);
}
}
public class ProductService
{
IAccountService _accountService;
IProductWebAPI _productWebAPI;
ProductService(IAccountService accountService, IProductWebAPI productWebAPI)
{
_accountService = accountService;
_productWebAPI = productWebAPI;
}
IList<Order> GetOrders(int customerId)
{
// Find the International Customer Number for CustomerId
object customer = _accountService.GetInternationCustomerInfo(customerId);
// Convert the string type to int
var modifiedCustomerNumber = Convert.ToInt32(customer.Id);
// Get the orders
return _productWebAPI.GetOrders(modifiedCustomerNumber);
}
}
public class AccountService
{
IAccountWebService _accountWebAPI;
CustomerService(IAccountWebService accountWebAPI)
{
_accountWebAPI = accountWebAPI;
}
object GetInternationCustomerInfo(int customerId)
{
return accountWebAPI.GetCustomer(customerId)
}
}
UPDATE: I realized that OrderService would be the appropriate service name for orders and not ProductService.
The LAYERS:
VIEW -- CONTROLLER -- SERVICE -- WebAPIs -- DOMAIN -- REPOSITORY
OrderView -- CustomerAccountController -- ProductService (calls AccountService in the same layer) -- ProductWebAPI -- ProductDomain -- ProductRepository
The names AccountService and ProductService imply that you are violating the Single Responsibility Principle, Open Closed Principle and Interface Segregation Principle. Together, those three principles are 60% of the SOLID principles.
The reasoning for this is explained in this article, but in short:
The Single Responsibility Principle is violated, because the methods in each class are not highly cohesive. The only thing that relates those methods is the fact that they belong to the same concept or entity.
The design violates the Open/Closed Principle, because almost every time [a method] is added to the system, an existing interface and its implementations need to be changed. Every interface has at least two implementations: one real implementation and one test implementation.
The Interface Segregation Principle is violated, because the interfaces [such as IProductService] are wide (have many methods) and consumers of those interfaces are forced to depend on methods that they don’t use.
The solution is to give each use case its own class. This design is explained in detail here and here.
I would even say that having Web API controllers with the same structure leads to the same kind of SOLID violation. In fact, if you apply the design given by the articles, you can completely remove all your Web API controllers, and replace them with a single piece of infrastructure logic that will be able to pass messages around. Such design is described here (the article mainly talks about WCF, but its applicable to Web API as well and a working example of Web API can be seen in the example project that the article links to).
1) Can I eliminate the ProductService and orchestrate the retrieving of the orders in the CustomerAccountController itself?
You could do that, but that means you would mix up delivery logic with applicative logic. It's not the worst SRP violation but that would remove the option of adding a second delivery mechanism (something else than Web API) for the same use case. It can be a valid tradeoff in some circumstances though.
2) Am I violating the n-layer architecture because the ProductService calls the AccountService which is the same layer?
Absolutely not. An architecture is a set of constraining technical decisions that were made. The only way you could violate an architecture would be to set up a second, parallel architecture that somehow breaks principles from the original one. Here, you wouldn't even violate the n-layer approach since nothing in it says that you shouldn't call someone in the same layer.
3) Since AccountWebAPI and ProductWebAPI are micro services, do they have to be separated as AccountService and ProductService in the client application (MVC App) also to keep the Separation Of Responsibility? So the ProductService needs to be renamed as ProductAppService and ProductService should interact with ProductWebAPI only like AccountService talks to AccountWebAPI.
Your question suggests that the use of microservices might not be a thought out, educated choice here. Microservices are separation of responsibility taken to the extreme. They should be independently deployable and share as few things as possible. I also suggest you model your subdomains and Bounded Contexts (big business areas) first. Microservices will naturally fall into one of the BCs.
I have a design problem with my poject that I don't know how to fix, I have a DAL Layer which holds Repositories and a Service Layer which holds "Processors". The role of processors is to provide access to DAL data and perform some validation and formatting logic.
My domain objects all have a reference to at least one object from the Service Layer (to retrieve the values of their properties from the repositories). However I face two cyclical dependencies. The first "cyclical dependency" comes from my design since I want my DAL to return domain objects - I mean that it is conceptual - and the second comes from my code.
A domain object is always dependent of at least one Service Object
The domain object retrieves his properties from the repositories by calling methods on the service
The methods of the service call the DAL
However - and there is the problem - when the DAL has finished his job, he has to return domain objects. But to create these objects he has to inject the required Service Object dependencies (As these dependencies are required by domain objects).
Therefore, my DAL Repositories have dependencies on Service Object.
And this results in a very clear cyclical dependency. I am confused about how I should handle this situation. Lastly I was thinking about letting my DAL return DTOs but it doesn't seem to be compatible with the onion architecture. Because the DTOs are defined in the Infrastructure, but the Core and the Service Layer should not know about Infrastucture.
Also, I'm not excited about changing the return types of all the methods of my repositories since I have hundreds of lines of code...
I would appreciate any kind of help, thanks !
UPDATE
Here is my code to make the situation more clear :
My Object (In the Core):
public class MyComplexClass1
{
MyComplexClass1 Property1 {get; set;}
MyComplexClass2 Property2 {get; set;}
private readonly IService MyService {get; set;}
public MyComplexClass1(IService MyService)
{
this.MyService = MyService;
this.Property1 = MyService.GetMyComplexClassList1();
.....
}
This is my Service Interface (In the Core)
public interface IService
{
MyComplexClass1 GetMyComplexClassList1();
...
}
This my Repository Interface (In the Core)
public interface IRepoComplexClass1
{
MyComplexClass1 GetMyComplexClassObject()
...
}
Now the Service Layer implements IService, and the DAL Layer Implements IRepoComplexClass1.
But my point is that in my repo, I need to construct my Domain Object
This is the Infrascruture Layer
using Core;
public Repo : IRepoComplexClass1
{
MyComplexClass1 GetMyComplexClassList1()
{
//Retrieve all the stuff...
//... And now it's time to convert the DTOs to Domain Objects
//I need to write
//DomainObject.Property1 = new MyComplexClass1(ID, Service);
//So my Repository has a dependency with my service and my service has a dependency with my repository, (Because my Service Methods, make use of the Repository). Then, Ninject is completely messed up.
}
I hope it's clearer now.
First of all, typically architectural guidance like the Onion Architecture and Domain Driven Design (DDD) do not fit all cases when designing a system. In fact, using these techniques is discouraged unless the domain has significant complexity to warrant the cost. So, the domain you are modelling is complex enough that it will not fit into a more simple pattern.
IMHO, both the Onion Architecture and DDD try to achieve the same thing. Namely, the ability to have a programmable (and perhaps easily portable) domain for complex logic that is devoid of all other concerns. That is why in Onion, for example, application, infrastructure, configuration and persistence concerns are at the edges.
So, in summary, the domain is just code. It can then utilize those cool design patterns to solve the complex problems at hand without worrying about anything else.
I really like the Onion articles because the picture of concentric barriers is different to the idea of a layered architecture.
In a layered architecture, it is easy to think vertically, up and down, through the layers. For example, you have a service on top which speaks the outside world (through DTOs or ViewModels), then the service calls the business logic, finally, the business logic calls down to some persistence layer to keep the state of the system.
However, the Onion Architecture describes a different way to think about it. You may still have a service at the top, but this is an application service. For example, a Controller in ASP.NET MVC knows about HTTP, application configuration settings and security sessions. But the job of the controller isn't just to defer work to lower (smarter) layers. The job is to as quickly as possible map from the application side to the domain side. So simply speaking, the Controller calls into the domain asking for a piece of complex logic to be executed, gets the result back, and then persists. The Controller is the glue that is holding things together (not the domain).
So, the domain is the centre of the business domain. And nothing else.
This is why some complain about ORM tools that need attributes on the domain entities. We want our domain completely clean of all concerns other than the problem at hand. So, plain old objects.
So, the domain does not speak directly to application services or repositories. In fact, nothing that the domain calls speaks to these things. The domain is the core, and therefore, the end of the execution stack.
So, for a very simple code example (adapted from the OP):
Repository:
// it is only infrastructure if it doesn't know about specific types directly
public Repository<T>
{
public T Find(int id)
{
// resolve the entity
return default(T);
}
}
Domain Entity:
public class MyComplexClass1
{
MyComplexClass1 Property1 {get; } // requred because cannot be set from outside
MyComplexClass2 Property2 {get; set;}
private readonly IService MyService {get; set;}
// no dependency injection frameworks!
public MyComplexClass1(MyComplexClass1 property1)
{
// actually using the constructor to define the required properties
// MyComplexClass1 is required and MyComplexClass2 is optional
this.Property1 = property1;
.....
}
public ComplexCalculationResult CrazyComplexCalculation(MyComplexClass3 complexity)
{
var theAnswer = 42;
return new ComplexCalculationResult(theAnswer);
}
}
Controller (Application Service):
public class TheController : Controller
{
private readonly IRepository<MyComplexClass1> complexClassRepository;
private readonly IRepository<ComplexResult> complexResultRepository;
// this can use IoC if needed, no probs
public TheController(IRepository<MyComplexClass1> complexClassRepository, IRepository<ComplexResult> complexResultRepository)
{
this.complexClassRepository = complexClassRepository;
this.complexResultRepository = complexResultRepository;
}
// I know about HTTP
public void Post(int id, int value)
{
var entity = this.complexClassRepository.Find(id);
var complex3 = new MyComplexClass3(value);
var result = entity.CrazyComplexCalculation(complex3);
this.complexResultRepository.Save(result);
}
}
Now, very quickly you will be thinking, "Woah, that Controller is doing too much". For example, how about if we need 50 values to construct MyComplexClass3. This is where the Onion Architecture is brilliant. There is a design pattern for that called Factory or Builder and without the constraints of application concerns or persistence concerns, you can implement it easily. So, you refactor into the domain these patterns (and they become your domain services).
In summary, nothing the domain calls knows about application or persistence concerns. It is the end, the core of the system.
Hope this makes sense, I wrote a little bit more than I intended. :)
I am currently weighing up the advantages and disadvantages between DI and SL. However, I have found myself in the following catch 22 which implies that I should just use SL for everything, and only inject an IoC container into each class.
DI Catch 22:
Some dependencies, like Log4Net, simply do not suit DI. I call these meta-dependencies and feel they should be opaque to calling code. My justification being that if a simple class 'D' was originally implemented without logging, and then grows to require logging, then dependent classes 'A', 'B', and 'C' must now somehow obtain this dependency and pass it down from 'A' to 'D' (assuming 'A' composes 'B', 'B' composes 'C', and so on). We have now made significant code changes just because we require logging in one class.
We therefore require an opaque mechanism for obtaining meta-dependencies. Two come to mind: Singleton and SL. The former has known limitations, primarily with regards to rigid scoping capabilities: at best a Singleton will use an Abstract Factory which is stored at application scope (ie. in a static variable). This allows some flexibility, but is not perfect.
A better solution would be to inject an IoC container into such classes, and then use SL from within that class to resolve these meta-dependencies from the container.
Hence catch 22: because the class is now being injected with an IoC container, then why not use it to resolve all other dependencies too?
I would greatly appreciate your thoughts :)
Because the class is now being injected with an IoC container, then why not use it to resolve all other dependencies too?
Using the service locator pattern completely defeats one of the main points of dependency injection. The point of dependency injection is to make dependencies explicit. Once you hide those dependencies by not making them explicit parameters in a constructor, you're no longer doing full-fledged dependency injection.
These are all constructors for a class named Foo (set to the theme of the Johnny Cash song):
Wrong:
public Foo() {
this.bar = new Bar();
}
Wrong:
public Foo() {
this.bar = ServiceLocator.Resolve<Bar>();
}
Wrong:
public Foo(ServiceLocator locator) {
this.bar = locator.Resolve<Bar>();
}
Right:
public Foo(Bar bar) {
this.bar = bar;
}
Only the latter makes the dependency on Bar explicit.
As for logging, there's a right way to do it without it permeating into your domain code (it shouldn't but if it does then you use dependency injection period). Amazingly, IoC containers can help with this issue. Start here.
Service Locator is an anti-pattern, for reasons excellently described at http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx. In terms of logging, you could either treat that as a dependency just like any other, and inject an abstraction via constructor or property injection.
The only difference with log4net, is that it requires the type of the caller that uses the service. Using Ninject (or some other container) How can I find out the type that is requesting the service? describes how you can solve this (it uses Ninject, but is applicable to any IoC container).
Alternatively, you could think of logging as a cross cutting concern, which isn't appropriate to mix with your business logic code, in which case you can use interception which is provided by many IoC containers. http://msdn.microsoft.com/en-us/library/ff647107.aspx describes using interception with Unity.
My opinion is that it depends. Sometimes one is better and sometimes another. But I'd say that generaly I prefer DI. There are few reasons for that.
When dependency is injected somehow into component it can be treated as part of its interface. Thus its easier for component's user to supply this dependecies, cause they are visible. In case of injected SL or Static SL that dependencies are hidden and usage of component is a bit harder.
Injected dependecies are better for unit testing cause you can simply mock them. In case of SL you have to setup Locator + mock dependencies again. So it is more work.
Sometimes logging can be implemented using AOP, so that it doesn't mix with business logic.
Otherwise, options are :
use an optional dependency (such as setter property), and for unit test you don't inject any logger. IOC container will takes care of setting it automatically for you if you run in production.
When you have a dependency that almost every object of your app is using ("logger" object being the most commmon example), it's one of the few cases where the singleton anti-pattern becomes a good practice. Some people call these "good singletons" an Ambient Context:
http://aabs.wordpress.com/2007/12/31/the-ambient-context-design-pattern-in-net/
Of course this context has to be configurable, so that you can use stub/mock for unit testing.
Another suggested use of AmbientContext, is to put the current Date/Time provider there , so that you can stub it during unit test, and accelerates time if you want.
This is regarding the 'Service Locator is an Anti-Pattern' by Mark Seeman.
I might be wrong here. But I just thought I should share my thoughts too.
public class OrderProcessor : IOrderProcessor
{
public void Process(Order order)
{
var validator = Locator.Resolve<IOrderValidator>();
if (validator.Validate(order))
{
var shipper = Locator.Resolve<IOrderShipper>();
shipper.Ship(order);
}
}
}
The Process() method for OrderProcessor does not actually follow the 'Inversion of Control' principle. It also breaks the Single Responsibility principle at the method level. Why should a method be concerned with instantiating the
objects(via new or any S.L. class) it needs to accomplish anything.
Instead of having the Process() method create the objects the constructor can actually have the parameters for the respective objects(read dependencies) as shown below. Then HOW can a Service Locator be any different from a IOC
container. AND it will aid in Unit Testing as well.
public class OrderProcessor : IOrderProcessor
{
public OrderProcessor(IOrderValidator validator, IOrderShipper shipper)
{
this.validator = validator;
this.shipper = shipper;
}
public void Process(Order order)
{
if (this.validator.Validate(order))
{
shipper.Ship(order);
}
}
}
//Caller
public static void main() //this can be a unit test code too.
{
var validator = Locator.Resolve<IOrderValidator>(); // similar to a IOC container
var shipper = Locator.Resolve<IOrderShipper>();
var orderProcessor = new OrderProcessor(validator, shipper);
orderProcessor.Process(order);
}
I have used the Google Guice DI framework in Java, and discovered that it does much more than make testing easier. For example, I needed a separate log per application (not class), with the further requirement that all my common library code use the logger in the current call context. Injecting the logger made this possible. Admittedly, all the library code needed to be changed: the logger was injected in the constructors. At first, I resisted this approach because of all the coding changes required; eventually I realized that the changes had many benefits:
The code became simpler
The code became much more robust
The dependencies of a class became obvious
If there were many dependencies, it was a clear indication that a class needed refactoring
Static singletons were eliminated
The need for session or context objects disappeared
Multi-threading became much easier, because the DI container could be built to contain just one thread, thus eliminating inadvertent cross-contamination
Needless to say, I am now a big fan of DI, and use it for all but the most trivial applications.
We've landed on a compromise: use DI but bundle top-level dependencies into an object avoiding refactoring hell should those dependencies change.
In the example below, we can add to 'ServiceDependencies' without having to refactor all derived dependencies.
Example:
public ServiceDependencies{
public ILogger Logger{get; private set;}
public ServiceDependencies(ILogger logger){
this.Logger = logger;
}
}
public abstract class BaseService{
public ILogger Logger{get; private set;}
public BaseService(ServiceDependencies dependencies){
this.Logger = dependencies.Logger; //don't expose 'dependencies'
}
}
public class DerivedService(ServiceDependencies dependencies,
ISomeOtherDependencyOnlyUsedByThisService additionalDependency)
: base(dependencies){
//set local dependencies here.
}
I know that people are really saying DI is the only good IOC pattern but I don't get this. I will try to sell SL a bit. I will use the new MVC Core framework to show you what I mean. First DI engines are really complex. What people really mean when they say DI, is use some framework like Unity, Ninject, Autofac... that do all the heavy lifting for you, where SL can be as simple as making a factory class. For a small fast project this is an easy way to do IOC without learning a whole framework for proper DI, they might not be that difficult to learn but still.
Now to the problem that DI can become. I will use a quote from MVC Core docs.
"ASP.NET Core is designed from the ground up to support and leverage dependency injection." Most people say that about DI "99% of your code base should have no knowledge of your IoC container." So why would they need to design from ground up if only 1% of code should be aware of it, didn't old MVC support DI? Well this is the big problem of DI it depends on DI. Making everything work "AS IT SHOULD BE DONE" takes a lot of work. If you look at the new Action Injection is this not depending on DI if you use [FromServices] attribute. Now DI people will say NO you are suppose to go with Factories not this stuff, but as you can see not even people making MVC did it right. The problem of DI is visible in Filters as well look at what you need to do to get DI in a filter
public class SampleActionFilterAttribute : TypeFilterAttribute
{
public SampleActionFilterAttribute():base(typeof(SampleActionFilterImpl))
{
}
private class SampleActionFilterImpl : IActionFilter
{
private readonly ILogger _logger;
public SampleActionFilterImpl(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<SampleActionFilterAttribute>();
}
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation("Business action starting...");
// perform some business logic work
}
public void OnActionExecuted(ActionExecutedContext context)
{
// perform some business logic work
_logger.LogInformation("Business action completed.");
}
}
}
Where if you used SL you could have done this with var _logger = Locator.Get();. And then we come to the Views. With all there good will regarding DI they had to use SL for the views. the new syntax #inject StatisticsService StatsService is the same as var StatsService = Locator.Get<StatisticsService>();.
The most advertised part of DI is unit testing. But what people and up doing is just testing there mock services with no purpose or having to wire up there DI engine to do real tests. And I know that you can do anything badly but people end up making a SL locator even if they don't know what it is. Where not a lot of people make DI without ever reading on it first.
My biggest problem with DI is that the user of the class must be aware of the inner workings of the class in other to use it.
SL can be used in a good way and has some advantages most of all its simplicity.
I know this question is a little old, I just thought I would give my input.
In reality, 9 times out of 10 you really don't need SL and should rely on DI. However, there are some cases where you should use SL. One area that I find myself using SL (or a variation, thereof) is in game development.
Another advantage of SL (in my opinion) is the ability to pass around internal classes.
Below is an example:
internal sealed class SomeClass : ISomeClass
{
internal SomeClass()
{
// Add the service to the locator
ServiceLocator.Instance.AddService<ISomeClass>(this);
}
// Maybe remove of service within finalizer or dispose method if needed.
internal void SomeMethod()
{
Console.WriteLine("The user of my library doesn't know I'm doing this, let's keep it a secret");
}
}
public sealed class SomeOtherClass
{
private ISomeClass someClass;
public SomeOtherClass()
{
// Get the service and call a method
someClass = ServiceLocator.Instance.GetService<ISomeClass>();
someClass.SomeMethod();
}
}
As you can see, the user of the library has no idea this method was called, because we didn't DI, not that we'd be able to anyways.
If the example only takes log4net as dependency, then you only need to do this:
ILog log = LogManager.GetLogger(typeof(Foo));
There is no point to inject the dependency as log4net provides granular logging by taking the type (or a string) as parameter.
Also, DI is not correlated with SL. IMHO the purpose of ServiceLocator is for resolve optional dependencies.
Eg: If the SL provides an ILog interface, i will write logging daa.
For DI, do you need to have a hard reference to the injected type assembly? I don’t see anyone talking about that. For SL, I can tell my resolver where to load my type dynamically when it needed from a config.json or similar. Also, if your assembly contains several thousand types and their inheritance, do you need thousands cascading call to the service collection provider to register them? That’s where I do see much talk about. Most are talking about the benefit of DI and what it is in general, when it comes to how to implement it in .net, they presented with an extension method for adding reference to a hard linked types assembly. That’s not very decoupling to me.