I am trying to figure out how to get a new lifetime scope each time I resolve an instance from the container. I would like to do this without the depending component needing to know about Autofac.
I'm creating a .NET Core server application (console app) which has a "master server" (IMasterServer) component and zero or more "session server" (ISessionServer) components. Both the master and the session servers have their own IMessageBroker dependency. The master server will create a new session server whenever it gets a message from the message broker.
The catch is that each session server instance needs its own IMessageBroker, and I don't think I can use InstancePerDependency() because other sub-components of ISessionServer will also need to access the IMessageBroker so the message broker needs to be single instance within the scope of a session. So my thinking is that when the master server spawns a new session, it should do so within a new lifetimescope, and I can register the IMessageBroker dependency using InstancePerLifetimeScope().
So, the question is, how can I inject an ISessionServer factory into IMasterServer such that each time that factory is called, a new lifetime scope is created for the resulting ISessionServer instance? And how can this be done such that none of the components need to know about Autofac?
These two SO questions both suggest using the Owned<T> relationship:
Can I create an implicit Lifetime scope within a factory?
Is it possible to create a new scope whenever a component is resolved?
However, unless I'm missing something, that means that the component into which the dependency will be injected (IMasterServer in my case) needs to know about Autofac, because its ctor signature must include the Owned<T> type.
What I have so far:
using Autofac.Features.OwnedInstances;
class MasterServer : IMasterServer
{
private IMessageBroker mMessageBroker;
private Func<Owned<ISessionServer>> mSessionServerFactory;
public Master(
Func<string, IServerMessageBroker> messageBrokerFactory,
Func<Owned<ISessionServer>> sessionServerFactory
)
{
mMessageBroker = messageBrokerFactory("master");
mSessionServerFactory = sessionServerFactory;
}
}
class SessionServer : ISessionServer
{
private IMessageBroker mMessageBroker;
private string mId;
public SessionServer(
Func<string, IMessageBroker> messageBrokerFactory
)
{
mId = Guid.NewGuid().ToString();
mMessageBroker = messageBrokerFactory(mId);
}
}
You can see that the MasterServer concrete class needs to use the Autofac.Features.OwnedInstances namespace in order to define the session factory using the Owned<T> relationship type.
How can I use Autofac to create a new lifetime scope each time ISessionServer is resolved through the factory injected into the MasterServer, without the components needing to know anything about the specific DI container in use?
I always felt that letting Autofac-specific code slip onto factory classes is the less of two evils.
So, if I was in you, I would just use the Owned<T> class, call it a day and move on. It's an excellent solution and keeps all the disposing of every component automagical as always with Autofac.
Just remember to call Dispose or your owned SessionServer when needed, or you will leak resources.
AFAICT the Autofac approach doesn't let you write 100% DI free code. So you need to reference it, someway, somewhere.
A single reference to include Owned<T> seems a pretty acceptable trade off.
Let me point out a problem in your design (or in the part you included): there is no simple way to link a ISessionServer into a disposable scope.
E.g: you expose a factory class, and then the SessionServer is out on his own.
Managing scopes in this way becomes hard.
A cleaner approach is to use a Disposable into a using statement:
using (var sessionServer = sessionFactory.GetServer())
{
// do something with sessionServer.
}
Related
I want to use same technology to access my database both from ASP.NET MVC and WPF and decided to use EF Core.
In ASP.NET I can inject DbContext(UnitOfWork, AppBLL etc) into Controller and its lifecycle is scoped to request/response operation. As I understood the scope is created behind the scenes using ASP.NET middleware pipeline.
In WPF however scope must be defined based on the app use case which is completely logical since some times there is need for long operation (for example using DbSet.Local.ToObservableCollection() and DataGrid) and sometimes operation is more trivial (for example update one entity).
I want to achieve somewhat similar behavior to ASP.NET MVC in WPF, basically I want to inject DbContext into ViewModel constructor and then each method to be its own scope thus have different short-lived DbContext each method call.
I use Microsoft.Extensions.DependencyInjection and CommunityToolkit.MVVM for DI and add DbContext using AddDbContext. This makes it scoped but without defining the scopes it is effectively singleton. I do not want to define scope with using(var scope = ...) and GetRequiredService each time I make a db operation since it will pollute my code.
As I said I want it to be sleek like in ASP.NET.
So I tried aspect oriented programming with PostSharp but feels kinda dull to add attributes to each method that uses DbContext also there are concerns about testability.
I tried implementing abstract class which has methods to which lambda with operation is passed and lambda is created inside a using(var scope = ...) expression and thus uses scoped DbContext. At the disposal of the scope DbContext is automatically disposed with it.
These approaches however are still distant from ASP.NET mechanism and
I want DbContext lifecycle to be managed smarter.
If I define DbContext as transient then it is only created on injection into ViewModel and not re-created for methods.
By the way, do I understand correctly that in ASP.NET when DbContext is injected into Controller it is disposed right after the construction, since the scope is finished?
EDIT:
Here is a link to example project Github repository
https://github.com/anguzo/ef-core-in-wpf-example
WpfApp project is example of the problem - you can't update same entity twice since it's already being tracked.
Other WPF projects demonstrate different solutions to this problem I came up with.
The closest to the ASP.NET behavior is using PostSharp custom attribute. It requires attribute to be applied to ViewModel class and modifies each method(excluding "special methods": getters, setters and consturctors).
I am still lost since official Microsoft documentation and other materials on the Internet do not describe proper solution to this problem.
The dependency injection container is an instance class.
With mvc there is a request pipeline that provides the parameters of anything instantiated by it from that container.
The difference between mvc and wpf is that with wpf you don't have that pipeline so you need to provide the container instance somehow whenever you instantiate a class you want anything injected to.
It's covered pretty well here:
https://learn.microsoft.com/en-us/windows/communitytoolkit/mvvm/ioc
You do not want everything to be a singleton and you do not want to resolve the entire object graph as you crank up your application.
As you spotted, that's impractical anyhow because you want some things to be transient.
Passing the DI container around is a nuisance. You might have any number of layers down to your dbcontext.
What is usual is to make the injection container available throughout the app.
In the code there, they've added a property to App to stash that instance in:
public sealed partial class App : Application
{
public App()
{
Services = ConfigureServices();
this.InitializeComponent();
}
/// <summary>
/// Gets the current <see cref="App"/> instance in use
/// </summary>
public new static App Current => (App)Application.Current;
/// <summary>
/// Gets the <see cref="IServiceProvider"/> instance to resolve application services.
/// </summary>
public IServiceProvider Services { get; }
App.Services is your dependency injection container. The magic bag you grab your instances out of.
Where these services are registered they're all singletons there, but your dbcontext should be
services.AddTransient<IMyDbContext, MyDbContext>();
And your repository would take an IMyDbContext in it's constructor which would be supplied out the container.
You need to reference that container exposed by App to resolve an instance:
var repo = App.Current.Services.GetService<IRepository>();
Because it's on App.Current, everywhere in your code will be able to reference it. So long as you have a regular wpf entry point.
Your repository would get an instance of dbcontext via injection and you'd so whatever you're doing with that repository. Once it goes out of scope the repository and dbconnection would be ready for garbage collection so long as they're both Transient.
Transients will be disposed after they go out of scope. Hence if you pass a transient dbcontext down from a mvc controller then it will stay in scope until the response is sent from the controller. It's only going to be torn down after the controller's returned it's result and goes out of scope.
The aspect of the code which I would change is to add an abstracted facade around the di container. You want to be able to moq whatever grabs a class instance out that container if you use it within any classs. If you use app.current in unit testing then you need to instantiate an application object.
What Andy outlines is pretty much what I use, it's commonly referred to as a Service Locator pattern, and has a bit of a reputation as an anti-pattern, but for WPF it is pretty effective if you have some discipline within your team about where and how it is allowed to be used.
I'd recently written a quick snippet on using the ServiceLocator pattern and lazy dependency properties with Autofac which can provide some ideas on how the pattern can be applied:
private readonly IContainerScope _scope;
private ISomeDependency? _someDependency = null;
public ISomeDependecy SomeDependency
{
get => _someDependency ??= _scope.Resolve<ISomeDependency>()
?? throw new ArgumentException("The SomeDependency dependency could not be resolved.");
set => _someDependency = value;
}
public SomeClass(IContainer container)
{
if (container == null) throw new ArgumentNullException(nameof(container));
_scope = container.BeginLifetimeScope();
}
public void Dispose()
{ // TODO: implement proper Dispose pattern.
_scope.Dispose();
}
This gives you a pattern gives you a default lifetime scope for the life of a top-level dependency which could be a MVVM ViewModel, and/or navigation provider, etc. so your dependencies can be managed by Transient, Singleton, or PerLifeTimeScope. (Suited to something like the EF DbContext) So for instance when a form is loaded the DbContext instance can be resolved for the lifetime of that form.
I call the pattern a lazy property pattern as the actual dependency is resolved only if/when it is accessed via the property. The advantage of this is when writing unit tests with classic constructor injection, you need to mock every dependency for every test, where with "lazy" properties you use the Setter for just the dependencies you need. The initialization of the class under test accepts a mocked container that simply throws an exception to fail the test if it's Resolve<T> method is called. (No need to build a functional mock container for tests to resolve mocked dependencies or other such complexity)
The caveat of this pattern, and one suggestion to work with the team on to check is that the _scope reference should only be accessed from the dependency properties, not willy-nilly through the code to resolve dependencies ad-hoc. For instance if a new dependency is needed, declare the property accessor to resolve via the scope rather than just writing a _scope.Resolve<NewDependency>() in the code. While you can still test around such code, you'd need to set up your tests to provide a _scope capable of resolving a Mock, which is honestly messy. Following the property pattern makes testing a lot simpler to provide the expected dependency via the Setter and getting an exception/failure if an unexpected dependency happens to get accessed.
It's not proper-C#-Lazy, though I do use a proper Lazy dependency pattern for injected dependencies, and web projects where the lifetime scope is conveniently managed:
private readonly Lazy<ISomeDependency>? _lazySomeDependency = null;
private ISomeDependency? _someDependency = null;
public ISomeDependency SomeDependency
{
get => _someDependency ??= _lazySomeDependency?.Value
?? throw new ArgumentException("SomeDependency dependency was not provided.");
set => _someDependency = value;
}
public SomeClass(Lazy<ISomeDependency>? someDependency = null)
{
_lazySomeDependency = someDependency;
}
Autofac does support lazy initialization so this pattern means that for normal execution, Autofac provides the properties as Lazy references which will resolve if/when they are accessed. For unit tests, you just initialize with an empty constructor and use the Setters to set the dependencies you expect to actually be used. The above example with 1 dependency doesn't really demonstrate the value of that, but picture a test suite for a class that has 8 or 12 dependencies where a method under test will likely only touch a couple of them.
Like the below code, I have to use the factory/func way of registration with container as I don't know the value of "userId" property ahead of time but only during runtime. This is working & no issues with functionality aspects.
container.AddSingleton<IBLogic, BLogic>(); //explicitly registration 'BLogic' service object
container.AddSingleton<Func<string, IDBCache>>
(p=> (userId) => new IDBCache(userId, p.GetService<IBLogic>()));
Since here I'm using "new IDBCache", as per the link framework does not dispose of the services automatically.
Questions:
To make framework to dispose of the services automatically, is there any way out?
container.AddSingleton<Func<string, IDBCache>>
(p=> (userId) => new IDBCache(userId, p.GetService()));
Since I'm just registering the definition of func/factory not the service object(like 'BLogic') as such, does AddSingleton provides any advantage over using 'AddScoped' or 'AddTransisent' like below?
container.AddTransisent<Func<string, IDBCache>>
(p=> (userId) => new IDBCache(userId, p.GetService<IBLogic>()));
There's no easy fix for this. MS.DI doesn't contain a RegisterForDisposal method that you can call. You will have to create a separate wrapper that implements disposable to which you can hook your created instances. For instance:
services.AddSingleton<IBLogic, BLogic>();
services.AddScoped<DisposeWrapper>();
services.AddScoped<Func<string, IDBCache>>(p => (userId) =>
{
var cache = new IDBCache(userId, p.GetRequiredService<IBLogic>());
p.GetRequiredService<DisposeWrapper>().Add(cache);
return cache;
});
Where the DisposeWrapper looks like this:
public sealed class DisposeWrapper : List<IDisposable>, IDisposable
{
public void Dispose()
{
// Dispose in reverse order as creation.
for (int i = this.Count - 1; i >= 0; i--) this[i].Dispose();
}
}
Such implementation, however, comes with quite some caveats, because DisposeWrapper should be registered using the same scope as you want to cache your IDBCache. That's why in the example above, I registered both DisposeWrapper and the factory as Scoped.
Registering DisposeWrapper as Singleton, means that created IDBCache instances will only get disposed when the application ends. If you create many IDBCache instances during the lifetime of the application, it will cause a memory leak. This is unlikely a good idea in your scenario.
Registering both as transient, on the other hand, could still (confusingly) cause memory leaks, because the factory could be injected into a singleton, causing it (and its DisposeWrapper) to become a Captive Dependency.
Because of the complications of this design, I recommend changing your design.
If you redesign IDBCache in such way that runtime data isn't required during object construction, you can allow IDBCache to be registered in the container without factory (e.g. AddTransient<IDBCache>()) which allows it to be disposed normally by the container. This will remove all above-introduced complexity.
I am using Ninject
I have a class which I am using to hold & build some cached data if needed. It is set up in my Niject binding as follows
kernel.Bind<IConsistencyCheckCacheHelper>().To<ConsistencyCheckCacheHelper>().InSingletonScope();
The Class has some required dependencies injected into it the first time that the class is created, then that same instance is inject every time.
But in the case that the data needs to be rebuild I need run time dependency injected.
I am using this as a application wide cache,
Any ideas how to do this?
The Class has some required dependencies injected into it the first time that the class is created, then that same instance is inject every time.
The class has been registered with Ninject as a singleton. That means that the first time Ninject resolves an IConsistencyCheckCacheHelper it will create an instance of ConsistencyCheckCacheHelper, and then it will use that same instance over and over again.
So Ninject isn't injecting the same instance of a dependency into ConsistencyCheckCacheHelper over and over. It's only creating one instance of ConsistencyCheckCacheHelper, so whatever instance of the dependency gets injected into it won't change either.
If you want the dependency within used by ConsistencyCheckCacheHelper to change each time it's resolved then you can't register it as a singleton. You would need to use a different scope.
.InTransientScope() (the default) means that every time a type is resolved a new instance is created.
.InRequestScope() means that a new instance is created for every web request.
It's still a tiny bit more complicated than that. For example, if ConsistencyCheckCacheHelper is registered as transient, a new instance is created each time. But if it depends on something else and that dependency is registered as a singleton, each new instance of ConsistencyCheckCacheHelper will receive the same singleton instance of that dependency.
It's often recommended that we start off with transient dependencies. Unless we specifically need to reuse an instance, the cost of creating new objects likely isn't that great. For a web application, InRequestScope is likely safe. I'd only use singleton scope if I'm sure that I can safely reuse one instance of that class along with one instance if its dependencies and their dependencies and so on.
Ninject object scopes
This may not be the best way to do this but it works, Create 2 Interfaces that represent the same class
public interface DepInterfaceOne
{
int MethodWithCachedData();
void InfoRequiredForAtRunTime(object RunTimeObject);
}
public interface DepInterfaceTwo: IConsistencyCheckCacheHelper
{
}
And Set up your binding in this way
kernel.Bind<DepInterfaceOne>().To<DepInterfaceOneClass>().InSingletonScope();
kernel.Bind<DepInterfaceOneTwo>().ToMethod(a =>
{
DepInterfaceOne toReturn = kernel.Get<DepInterfaceOne>();
toReturn.InfoRequiredForAtRunTime(HttpContext.Current.Session["InfoRequired"]);
return toReturn;
});
In ASP.NET Core 2 Web Api, I want to use dependency injection to inject httpClientA instance of HttpClient to ControllerA, and an instance httpClientB of the HttpClient to ControllerB.
The DI registration code would look something like:
HttpClient httpClientA = new HttpClient();
httpClientA.BaseAddress = endPointA;
services.AddSingleton<HttpClient>(httpClientA);
HttpClient httpClientB = new HttpClient();
httpClientB.BaseAddress = endPointB;
services.AddSingleton<HttpClient>(httpClientB);
I know I could subclass HttpClient to make a unique type for each controller, but that doesn't scale very well.
What is a better way?
UPDATE
Specifically regarding HttpClient Microsoft seems to have something in the works
https://github.com/aspnet/HttpClientFactory/blob/dev/samples/HttpClientFactorySample/Program.cs#L32 - thanks to #mountain-traveller (Dylan) for pointing this out.
Note: This answer uses HttpClient and a HttpClientFactory as an example but easily applies to any other kind of thing. For HttpClient in particular, using the new IHttpClientFactory from Microsoft.Extensions.Http is preferred.
The built-in dependency injection container does not support named dependency registrations, and there are no plans to add this at the moment.
One reason for this is that with dependency injection, there is no type-safe way to specify which kind of named instance you would want. You could surely use something like parameter attributes for constructors (or attributes on properties for property injection) but that would be a different kind of complexity that likely wouldn’t be worth it; and it certainly wouldn’t be backed by the type system, which is an important part of how dependency injection works.
In general, named dependencies are a sign that you are not designing your dependencies properly. If you have two different dependencies of the same type, then this should mean that they may be interchangeably used. If that’s not the case and one of them is valid where the other is not, then that’s a sign that you may be violating the Liskov substitution principle.
Furthermore, if you look at those dependency injection containers that do support named dependencies, you will notice that the only way to retrieve those dependencies is not using dependency injection but the service locator pattern instead which is the exact opposite of inversion of control that DI facilitates.
Simple Injector, one of the larger dependency injection containers, explains their absence of named dependencies like this:
Resolving instances by a key is a feature that is deliberately left out of Simple Injector, because it invariably leads to a design where the application tends to have numerous dependencies on the DI container itself. To resolve a keyed instance you will likely need to call directly into the Container instance and this leads to the Service Locator anti-pattern.
This doesn’t mean that resolving instances by a key is never useful. Resolving instances by a key is normally a job for a specific factory rather than the Container. This approach makes the design much cleaner, saves you from having to take numerous dependencies on the DI library and enables many scenarios that the DI container authors simply didn’t consider.
With all that being said, sometimes you really want something like this and having a numerous number of subtypes and separate registrations is simply not feasible. In that case, there are proper ways to approach this though.
There is one particular situation I can think of where ASP.NET Core has something similar to this in its framework code: Named configuration options for the authentication framework. Let me attempt to explain the concept quickly (bear with me):
The authentication stack in ASP.NET Core supports registering multiple authentication providers of the same type, for example you might end up having multiple OpenID Connect providers that your application may use. But although they all share the same technical implementation of the protocol, there needs to be a way for them to work independently and to configure the instances individually.
This is solved by giving each “authentication scheme” a unique name. When you add a scheme, you basically register a new name and tell the registration which handler type it should use. In addition, you configure each scheme using IConfigureNamedOptions<T> which, when you implement it, basically gets passed an unconfigured options object that then gets configured—if the name matches. So for each authentication type T, there will eventually be multiple registrations for IConfigureNamedOptions<T> that may configure an individual options object for a scheme.
At some point, an authentication handler for a specific scheme runs and needs the actual configured options object. For this, it depends on IOptionsFactory<T> whose default implementation gives you the ability to create a concrete options object that then gets configured by all those IConfigureNamedOptions<T> handlers.
And that exact logic of the options factory is what you can utilize to achieve a kind of “named dependency”. Translated into your particular example, that could for example look like this:
// container type to hold the client and give it a name
public class NamedHttpClient
{
public string Name { get; private set; }
public HttpClient Client { get; private set; }
public NamedHttpClient (string name, HttpClient client)
{
Name = name;
Client = client;
}
}
// factory to retrieve the named clients
public class HttpClientFactory
{
private readonly IDictionary<string, HttpClient> _clients;
public HttpClientFactory(IEnumerable<NamedHttpClient> clients)
{
_clients = clients.ToDictionary(n => n.Name, n => n.Client);
}
public HttpClient GetClient(string name)
{
if (_clients.TryGet(name, out var client))
return client;
// handle error
throw new ArgumentException(nameof(name));
}
}
// register those named clients
services.AddSingleton<NamedHttpClient>(new NamedHttpClient("A", httpClientA));
services.AddSingleton<NamedHttpClient>(new NamedHttpClient("B", httpClientB));
You would then inject the HttpClientFactory somewhere and use its GetClient method to retrieve a named client.
Obviously, if you think about this implementation and about what I wrote earlier, then this will look very similar to a service locator pattern. And in a way, it really is one in this case, albeit built on top of the existing dependency injection container. Does this make it better? Probably not, but it’s a way to implement your requirement with the existing container, so that’s what counts. For full defense btw., in the authentication options case above, the options factory is a real factory, so it constructs actual objects and doesn’t use existing pre-registered instances, so it’s technically not a service location pattern there.
Obviously, the other alternative is to completely ignore what I wrote above and use a different dependency injection container with ASP.NET Core. For example, Autofac supports named dependencies and it can easily replace the default container for ASP.NET Core.
Another option is to
use an additional generic type parameter on the interface or a new interface implementing the non generic interface,
implement an adapter/interceptor class to add the marker type and then
use the generic type as “name”
I’ve written an article with more details: Dependency Injection in .NET: A way to work around missing named registrations
Use named registrations
This is exactly what named registrations are for.
Register like this:
container.RegisterInstance<HttpClient>(new HttpClient(), "ClientA");
container.RegisterInstance<HttpClient>(new HttpClient(), "ClientB");
And retrieve this way:
var clientA = container.Resolve<HttpClient>("ClientA");
var clientB = container.Resolve<HttpClient>("ClientB");
If you want ClientA or ClientB automatically injected into another registered type, see this question. Example:
container.RegisterType<ControllerA, ControllerA>(
new InjectionConstructor( // Explicitly specify a constructor
new ResolvedParameter<HttpClient>("ClientA") // Resolve parameter of type HttpClient using name "ClientA"
)
);
container.RegisterType<ControllerB, ControllerB>(
new InjectionConstructor( // Explicitly specify a constructor
new ResolvedParameter<HttpClient>("ClientB") // Resolve parameter of type HttpClient using name "ClientB"
)
);
Use a factory
If your IoC container lacks any ability to handle named registrations, you could inject a factory and let the controller decide how to get the instance. Here is a really simple example:
class HttpClientFactory : IHttpClientFactory
{
private readonly Dictionary<string, HttpClient> _clients;
public void Register(string name, HttpClient client)
{
_clients[name] = client;
}
public HttpClient Resolve(string name)
{
return _clients[name];
}
}
And in your controllers:
class ControllerA
{
private readonly HttpClient _httpClient;
public ControllerA(IHttpClientFactory factory)
{
_httpClient = factory.Resolve("ClientA");
}
}
And in your composition root:
var factory = new HttpClientFactory();
factory.Register("ClientA", new HttpClient());
factory.Register("ClientB", new HttpClient());
container.AddSingleton<IHttpClientFactory>(factory);
Really the consumer of the service should not care where about the implementation of the instance it is using. In your case I see no reason to manually register many different instances of HttpClient. You could register the type once and any consuming instance that needs an instance will get it's own instance of HttpClient. You can do that with AddTransient.
The AddTransient method is used to map abstract types to concrete services that are instantiated separately for every object that requires it
services.AddTransient<HttpClient, HttpClient>();
This question already has answers here:
What is the difference between an interface and a class, and why I should use an interface when I can implement the methods directly in the class?
(16 answers)
Closed 5 years ago.
With .net core you can register "Services" which as I understand, simply means you can register types to concrete classes.
As such, I decided it's about time I learnt DI and practised it. I understand the concept, and with testing it is massively beneficial. However what confuses me is the idea of registering services and whether it's actually needed.
For example, if I have:
public class MyClass
{
public MyClass(IDataContext)
{
... store it
}
}
Then this means I can inject any class that implements the IDataContext, allowing for fakes and moqs in testing. But why would I register a service and map IDataContext to a concrete class in the startup? Is there something wrong with just using the following in other methods:
DataContext dc = new DataContext(); // concrete
var c = new MyClass(dc);
Edit
This question was around the point of using the container (services) rather than why use an interface in the constructor.
Now those classes where you put this code
public class MyService
{
public void DoSomething()
{
DataContext dc = new DataContext(); // concrete
var c = new MyClass(dc);
c.DoSomething();
}
}
have a hard dependency on DataContext and MyClass. So you can't test MyService in isolation. Classes shouldn't care how other classes do what they do, they should only care that they do what they say they're going to do. That's why we use interfaces. This is separation of concerns. Once you've achieved this, you can unit test any piece of code in isolation without depending on the behavior of outside code.
Registering your dependencies up front in one location is also cleaner and means you can swap dependencies out by changing one location instead of hunting down all the usages and changing them individually.
In my code example at the top, MyService requires the usage of both DataContext and MyClass. Instead, it should be like this:
public class MyService
{
private readonly IMyClass _myClass;
public MyService(IMyClass myClass)
{
_myClass = myClass;
}
public void DoSomething()
{
_myClass.DoSomething();
}
}
public interface IMyClass
{
void DoSomething();
}
public class MyClass : IMyClass
{
private readonly IDataContext _context;
public MyClass(IDataContext context)
{
_context = context;
}
public void DoSomething()
{
_context.SaveSomeData();
}
}
Now MyService isn't dependent on DataContext at all, it doesn't need to worry about it because that's not its job. But it does need something that fulfills IMyClass, but it doesn't care how it's implemented. MyService.DoSomething() can now be unit tested without depending on the behavior of other code.
If you weren't using a container to handle satisfying the dependencies, then you're probably introducing hard dependencies into your classes, which defeats the entire point of coding against an interface in the first place.
Testing in isolation is important. It's not a unit test if you're testing more than one finite piece of code. It's an integration test (which have their own value for different reasons). Unit tests make it quick and easy to verify a finite block of code works as expected. When a unit test isn't passing, you know right where the problem is and don't have to search hard to find it. So if a unit test depends on other types, or even other systems (likely in this case, DataContext is specific to a particular database) then we can't test MyService without touching a database. And that means the database must be in a particular state for testing, which means the test likely isn't idempotent (you can't run it over and over and expect the same results.)
For more information, I suggest you watch Deep Dive into Dependency Injection and Writing Decoupled Quality Code and Testable Software by Miguel Castro. The best point he makes is that if you have to use new to create an instance of an object, you've tightly coupled things. Avoid using new, and Dependency Injection is a pattern that enables you to avoid it. (using new isn't always bad, I'm comfortable with using new for POCO models).
You can inject your dependencies manually. However this can get a very tedious task. If your services get bigger, you will get more dependencies, where each dependency on its own can have multiple dependencies.
If you change your dependencies, you need to adjust all usages. One of the main advantages of a DI container is, that the container will do all dependency resolving. No manual work required. Just register the service and use it wherever you want and how often you want.
For small projects this seems like too much overhead, but if your project grows a little, you will really appreciate this.
For fixed dependencies, which are strongly related and not likely to change, injecting them manually is fine.
Using a DI container has another advantage. The DI container will control the life cycle of its services. A service could be a singleton, transient (each request will get a new instance) or have scoped life time.
For example, if you have a transactional workflow. The scope could match the transaction. While in the transaction, requests to a service will return the same instance.
The next transaction will open a new scope and therefore will get new instances.
This allows you to either discard or commit all instances of one transaction, but prevents that following transaction uses resources from the previous one.
You right, you can create all instances manually. In small projects it's an usual practice. The place in your project where links the classes is called Composition Root, and what you do is Constructor Injection.
IoC-libraries can simplify this code, especially considering complex cases like life-time scopes and group registration.
Inversion of control (of constructing an object)
The idea of this pattern is when you want to construct an object you only need to know about the type of the object and nothing about its dependencies or parameters.
Dependency injection
This pattern is taking the inversion of control pattern a step further by enabling you to directly inject an object into a constructor for example.
Again you only need to know the type of the object you want to get and the dependency container will inject an object.
You also don't need to know if a new object is constucted or if you get a allready existing reference.
The most common used type of dependency injection is constructor injection but you could inject your type into other places like methods.
Seperation of concerns
Generally you register a type by an interface to get rid of the dependency on the type.
This is very helpfull for mocking types when testing and it helps to use the open closed principle.
Martin Fowler on "Inversion of Control Containers and the Dependency Injection pattern".