How to inject a dependency in a library without using service location - c#

Let's say a dev has created a library that exposes a class ScheduledAction
All this class does is execute a method at a specified interval.
So you would use this way:
var scheduledAction = new ScheduledAction(methodToCall, 10000);
scheduledAction.Start();
Every 10 seconds, the methodToCall is executed.
Now let's say dev of the library decided that ScheduledAction will catch and log exceptions thrown by methodToCall.
To do this it needs a logger. As this is a library, the dev doesn't want to force the use of any particular logging library and or implementation. This should be controlled and configured by the application consuming the library.
This is a very simple example to illustrate the point.
While researching on this, I noticed a common approach is to expose some sort of contract for logging (via an interface) and the consuming application has to supply an implementation, which is "injected" via some sort of initialization method that the library exposes.
However logging may not be the only dependency a library needs from a consuming application.
I'm struggling to find concrete examples/best practices for such situations, in particular when building an application that uses an IoC container, like an Asp.NET Core Web App.
All the services are added to the container at startup. I would then need to "initialize" the above mentioned library passing in implementations of the required services, requesting them explicitly, which is pretty much using the container like a service locator and more importantly the instances passed to the library cannot be swapped later (I'm thinking of cases where the IoC container creates object based on options/configuration which may change even at run-time).

You have a few options available:
Expose an ILogger interface on the same lib assembly/package, and a Logger class. Have the Logger class expose a static method to set the internal logger instance to some class that implements it.
Instead of setting up an implementation of ILogger, one could just assign an Action to be executed by the static Logger class.
The important is to have this behavior exposed through an interface, so the ScheduleAction class can be easily tested.
Then, on the ScheduleAction class, just check if the Logger has the actual logger set, and call it when an exception occurs.

Related

C#: ILogger vs static Log instance

This is more an architectural question:
Do you use ILogger (and pass it in the constructor via DI) or do you prefer a static class Log?
We use ILogger a lot but it really seems to clatter the code especially when it is passed via constructor. If not passed via constructor and just every time created, then I really do not see a benefit if using the interface.
So how do you handle this? I am especially interested in the arguments behind it - not just saying "static" or "interface".
Thx
Using a static instance of anything is a bad idea for different reasons, depending on your use case.
- They are difficult to mock in a unit test so your logger is always writing logs even when they are not needed.
- Lack of mocking also means you cannot write tests to ensure an error log is written in appropriate situations.
- They cannot be replaced at runtime to allow injection of different loggers. This can be important if you are releasing a library for others to use. I define a standard logger interface and log everything to that, then allow clients to inject their own logger as long as it implements my interface.
- If you use the default static Log implementation provided by the vendor, you are locked into their interface meaning you cannot hide or change the surface area of the logger. Changing loggers becomes a MUCH bigger effort if the syntax of the new logger changes.
So that leaves you with some kind of injection. Personally I prefer having all dependencies in the constructor, even if it becomes verbose, because it’s easy to see all dependencies a particular class has. If you are trying to avoid a big constructor you can look into Property Injection. This requires an attribute on a property of the class, but still gives you all the advantages of injecting the dependencies. If you put the injected property on a base class it will be available for all children automatically.
BTW, I’m not a fan of the Ambient Context described above because it’s basically a single purpose DI container, and you must have a concrete reference to multiple ambient service containers. If the easy access of this pattern appeals to you, look into Service Location which is the same idea but more flexible.
If ILogger is really a cross-cutting concern, which is used everywhere and thus just causes to pollute every instance with a new constructor parameter, then what you need is to you use a special way of dependency injection called AmbientContext.
Basically it provides you a singleton Context property, which can be accessed from anywhere in the business scope and contains the "global" dependencies such as logging, time service, etc., whatever you need.
But please note that it doesn't mean you can throw out your ILogger and use a static Log class with a hardcoded implementation. Ambient context is also a way of dependency injection so its dependencies should be resolved.

The Dependency Inversion Principle with .NET Framework classes

I'm trying to understand SOLID principles, in particular The Dependency Inversion Principle.
In this is SO answer it is explained very well.
I think I have understood that I can't create any instance of a class inside my class. Is it right?
But if I have to save to disk some content, can I create an instance of System.IO.File or do I have to inject it?
I don't understand where is the limit, if I can't instance my own classes or if I can't either instance .NET Framework classes (or whatever other framework).
UPDATE:
I think File is a bad example because is declared as static.
By the way, does this principle apply to static classes?
The S of SOLID stands for SRP (Single Responsibility Principle). You won't violate it by using System.IO.File inside a class directly, once you keep that class with one single responsibility.
It's a good idea trying to abstract the purpose behind using System.IO.File. Let's suppose you need it to generate a log. Then you would probably do something like:
public interface IMyLogger
{
void GenerateLog(IEnumerable<string> content);
}
public class FileLogger: IMyLogger
{
public void GenerateLog(IEnumerable<string> content)
{
System.IO.File.WriteAllLines("C:/Log", content);
}
}
Maybe it's not just a log, it's something more important, like generating a file so other system/app (even external) read it and do some job.
If you are trying to use a DDD approach, the interface could belong to your domain, and the implementation could belong in the application. Then you register your interface as a service and inject it.
The class which needs an IMyLogger actually doesn't need to know how is the log being generated, it just needs the job to be done.
You can apply the same idea when you need to send an email inside some business logic in your domain. Instead of making a connection to an Exchange inside your domain directly, create an interface INotifier and a MailNotifier implementing it to be injected.
Somewhere down the chain of dependencies you will need to use the concrete class directly. Even if you use a DI framework like Ninject, the framework itself will create an instance of the concrete type, so it will not be injected into the framework (which wouldn't make sense, of course).
You can only abstract something away to a certain level. It will vary from project to project - you have to ask yourself if you need another level of abstraction (be it for modularity, unit testing etc.). I think this is very important - you want to be pragmatic, not create layers upon layers of abstractions just for the sake of it.
By the way, does this principle apply to static classes?
Yes, it does. But with static classes you have to introduce a wrapper, which will delegate calls to the static class, because a static class cannot implement interfaces.
There is no point in applying a principle just for the sake of it. Think in a pragmatic way.
If you want to unit-test a method that uses hard coded file accesses, your unit tests will access these files. This is usually not desired as you must set up or clean up these files. To avoid this, you would inject a service which wraps these file accesses. This allows you to replace the real service with a fake one during the unit tests. This fake service can provide hard coded test data for read accesses and dump written data to memory for later analysis or simply do nothing. Btw.: NSubstitute can create fake services at runtime easily.
The injection of services allows you to achieve Unit Test Isolation. E.g. you can test some logic without depending on correct file handling or database accesses or the correct functioning of other services. Injecting a service is just one way to do it. You could also just specify a method parameter as IEnumerable<string> with the content of the file instead. Events can also be used for decoupling. Instead of writing to a log, you could raise a log event.
Most DI frameworks allow you to specify the lifetime of objects. One of these options is Singleton, which means that the DI container will always return the same instance of a requested service. This allows you to wrap static classes in a service that behaves statically.

Where should I store Logger code to reduce dependencies?

I'm using Log4Net to handle logging in my WPF application.
Currently, the logger is configured with the rest of the front-end code. I have to pass a reference to the Service layer and the Repository layer if I want to be able to use the logger in these layers (I'll actually be using StructureMap for this). This means the back-end has a dependency on the front-end and I don't like that.
I'm wondering how best to handle this? Should I configure the logger in the Repository layer?
log4net LogManager.GetLogger(string name) will return an existing logger instance if it has already been created (e.g., in another layer), so there is no need to pass logger objects around.
You do need to be aware of multiple threads/processes trying to write to the same log file at the same time. You can use the log4net MinimalLock, or try this third party solution. Neither is ideal (the codeproject one is inefficient and still hits concurrency problems). I have ended up writing my own (which unfortunately is not publicly available).
Logging is a common cross-cutting concern that I have seen handled in several different ways. The simplest method is to create a static class that lives in a common assembly that is shared by all the layers.
However, since you are using StructureMap for your IoC, a better solution would be to configure StructureMap to inject your logger class (which might be configured as a singleton, depending on your needs) into each instance created. I personally prefer property injection for such cross-cutting concern classes, so that constructors don't get cluttered, but that's a matter of preference.

how to write libraries without forcing users to use the library's IOC container

The short question is:
Given a library warrants using a particular IOC container for its internals, when an application consumes that library, given the app warrants using an IOC container for wiring its dependencies, given if the the two containers are different, how can they play well together?
The scenario is, the application has classes defined that depend on types from the library. So when the application container attempts to build such a class, it needs to know how to resolve the type that lives in the library.
Here's the long winded question:
This question does seem to have been asked in different shapes and form before on SO, but I can't seem to find the answer I need so I am going to have a go at it with a hypothetical _over_simplified_ concrete example.
We want to write a library for logging that users can include as a package in their solution to get logging functionality out of the box.
The public interfaces the library exposes are..
public interface ILogger {}
public interface ITarget {}
Concrete implementations are
internal class Logger: ILogger { public Logger(ITarget target) {}}
internal class FileTarget : ITarget {}
Requirements are if the user includes our package and defines a class with a property of type ILogger or has a ctor argument of type ILogger then our library is responsible for injecting a concrete implementation for that interface into the user defined class. By default that injected logger will go to the file system for logging because the default implementation of an ITarget injected into the ILogger implementation is a FileTarget by our library.
If the user decides to write a class implementing the ITarget interface then our library will use that to inject into the Logger class and not use its default FileTarget implementation.
SO what I wish to demonstrate, is their is a bi-directional dependency here.
Our library depends on the user's assemblies, since it needs to scan the user's assemblies to load any extension points (i.e. an ITarget implementation) and inject those into its own objects ahead of any default implementations.
The user's assemblies depends on the library, since if the user chooses to define a class with an ILogger interface as a dependency, then that user object should get a concrete reference to that interface provided at runtime by our library.
The easy solution is if the user and our library are both using the same IOC container, then problem is solved. But this is a strong assumption. What I wish to do is
Use an IOC container with the library that caters best to the library's requirement, in my case its Ninject.
At run time somehow provide a mechanism for the user to call via some API into my library that will ensure Ninject is fired up and it scans the user's assemblies, and wires everything taking into account all extension points.
So far so good, its perfectly achievable, but here comes the tricky part.
if the user is also using Ninject, then problem automatically solved, since Ninject already knows how to resolve Interfaces living in our library. But what if the user decides to use his/her choice of IOC container?
I almost want to define some sort of child container functionality in the library with an interface like such
public interface IDependencyResolvingModule { T Get<T>(); []T GetAll<T>(); }
and provide an implementation that uses our library's choice of container (i.e. Ninect) to resolve the type requested in the two methods define above.
I want the user's IOC container to have some functionality where if it can't resolve a dependency (i.e. an ILogger), it should hook into the IDependencyResolvingModule implementation and ask for the dependency.
This way our library gets to use its choice of IOC Container, and the user's code has a way to resolve dependencies that its IOC container has no clue about. Wouldn't this solution work if IOC containers out there some how provided functionality to register singleton instances of any IDependencyResolverModules found in assemblies in the executing assembly's dir and when they can't resolve a type, ask any of the singleton modules?
But barring a solution that requires every other IOC container to accommodate, how else can this be solved? SO the problem in a few lines is, when a third party assembly chooses to use an IOC container for its internals, what is an easy solution such that this library can simply provide a mechanism for an IOC container sitting outside to hook into and resolve dependencies that live in the library.
I see few possible approaches here:
Write default registrator for all of the popular IoC containers. Each of them should be placed in the separate assembly. Then developer can choose the one he needs and configure his container with it.
Define your own factory abstraction and write default implementation that will return the default logger. Let developer to substitute implementation of that factory. For example, with adapter for his favorite container. This approach is most container-agnostic, because developer can just use the default factory implementation. But this way has nothing to do with auto-wiring.
The lazy variation of the first approach. Write small manual about configuring a container to work with default implementations. Then developer could configure the container himself.
Combine all previous solutions to satisfy every developer. :)
EDIT: added example of integration of two containers
var allPublicInterfacesFromLibrary = typeof(AnyLibraryType)
.Assembly.GetTypes()
.Where(t => t.IsInterface && t.IsPublic);
foreach (var libraryInterface in allPublicInterfacesFromLibrary)
{
var local = libraryInterface; //to prevent closure
applicationContainer.Register(
Component.For(libraryInterface)
//delegate resolving
.UsingFactoryMethod(k => libraryContainer.Resolve(local))
//delegate lifetime management
.LifestyleTransient()
);
}

Manually implementing IoC with a Windows Service

I am brand new to IoC and thus have been following the examples provided by Jeffery Palermo in his posts at http://jeffreypalermo.com/blog/the-onion-architecture-part-1/ and in his book hosted here https://github.com/jeffreypalermo/mvc2inaction/tree/master/manuscript/Chapter23
Most important to note is that I am not using a pre-rolled IoC container, mostly because I want to understand all the moving parts.
However, I am creating a windows service rather than an ASP.NET MVC webapp so I am little bogged down on the startup portion. Specifically, in the web.config he registers an IHttpModule implementation INSIDE the infrastructure project as the startup module and then uses a post-build event to copy the necessary dlls into the website directory to get around having a direct dependency in the web project itself.
I don't think I have this type of luxury in a true windows service, so how do I achieve something similar, should I have a small startup project which has dependencies to both the Infrastructure and Core, or is there another method to get around the compile-time restrictions of the windows service?
Thanks in advance.
Based on the tags of this question (c#) I'm assuming that you'll implement the Windows Service by deriving from ServiceBase. If so, the OnStart method will be your Composition Root - this is where you compose the application's object graph. After you've composed the object graph, composition is over and the composed object graph takes over.
In OnStop you can decommission the object graph again.
There's nothing stopping you from implementing the various components of the resolved object graph in separate assemblies. That's what I would do.
I think you missunderstood the role of an IoC framework.
To answer your question
but doesn't the reference imply dependency?
Yes it does, but on an other level. IoC is about dependencies between classes.
Instead of using new Something() in your class you provide a constructor which requires all dependent interfaces. This way the class has no control which implementation is passed to it. This is inversion of control. The IoC Container is just an aid to help managing the dependencies in a nice manner.
Say you have a ICustomerNotificationService interface with an implementation like
public class MailNotificationService : INotificationService
{
IMailerService _mailer;
ICustomerRepository _customerRepo;
IOrderRepository _orderRepo;
public MailNotificationService(IMailerService mailer,
ICustomerRepository customerRepo,
IOrderRepository oderRepo)
{
// set fields...
}
public void Notify(int customerId, int productId)
{
// load customer and order, format mail and send.
}
}
So if your application requests an instance of ICustomerNotificationServcie the container figures out which concrete implementations to take and tries to satisfy all dependencies the requested class has.
The advantage is that you can easily configure all dependencies in your bootstrapping logic and be able to change the behaviour of your application very easily.
For example when testing you start the application with an IMailerService implementation which writes the mails to a file and in production mode a real mail service is wired. This would not be possible if you newed up say a MailerService in your constructor instead of taking it as a parameter.
A good IoC container can handle much more, for you like lifetime management, singletons, scanning assemblies for Types you want to register and many more. We based our entire plugin system on Structure Map for example.
You may want to take a look at this blog article and its second part.

Categories