Download as pdf or txt
Download as pdf or txt
You are on page 1of 18

(https://stackify.

com/)
Product  Pricing Solutions 

Learn  Login

.Net Core Dependency Injection


JARED NANCE | OCTOBER 16, 2017 |
DEVELOPER TIPS, TRICKS & RESOURCES (HTTPS://STACKIFY.COM/DEVELOPERS/)

(https://info.stackify.com/cs/c/?cta_guid=0467a1b6-1087-4d63-97b2-
13bcecff249d&signature=AAH58kHDWt79GnVbj1mSh2jCbApc1f Yqhg&placement_guid=fac1d799-
6f06-4da8-8350-ab6ccdfa9da6&click=2c8a9b61-0190-40fd-b0d1-
af6237911c46&hsutk=ea757bf786d28aa6f43ca4e058e7fac4&canon=https%3A%2F%2Fstackify.com
core-dependency-
injection%2F&portal_id=207384&redirect_url=APefjpFOa8uP75DbWhzZQdD_o0Ks1kZ6kdeRCK6lr1O
IIPf-
(https://stackify.com/)
Product  Pricing Solutions 
kKe5eL6iPTxmonNBMhj5GcBWCgskR2jOE_wDLdyCKrKjLea3odZEZzXlPDzuUObhwkjcCaHdC6yWzp2O
RH6X8WAy5IUl3PyAzsA_qMMeB3HdaZjqAyXMPocN4OmYtCnYfxNV5xGyAy2Xl2DWpXT8M8uHbXzcA
Learn  Login
iIjdlvncqiy5Ix&__hstc=23835621.ea757bf786d28aa6f43ca4e058e7fac4.1615492961405.1615492961

What is Dependency Injection?


Dependency Injection
(https://www.martinfowler.com/articles/injection.html) (DI) is a pattern
that can help developers decouple the different pieces of their
applications. It provides a mechanism for the construction of
dependency graphs independent of the class definitions. Throughout
this article, I will be focusing on constructor injection
(https://en.wikipedia.org/wiki/Dependency_injection#Constructor_injection) w
dependencies are provided to consumers through their constructors.
Consider the following classes:

class Bar : IBar {


// ...
}

class Foo {
private readonly IBar _bar;
public Foo(IBar bar) {
_bar = bar;
}
}

In this example, Foo depends on IBar and somewhere we’ll have to


construct an instance of Foo and specify that it depends on the
implementation Bar like so:
var bar = new Bar();
(https://stackify.com/)
Product  Pricing Solutions 
var foo = new Foo(bar);
Learn  Login
The problem with this is two-fold. Firstly, it violates the Dependency
Inversion Principle
(https://en.wikipedia.org/wiki/Dependency_inversion_principle) because
the consuming class implicitly depends (http://deviq.com/explicit-
dependencies-principle/) on the concrete types Bar and Foo. Secondly,
it results in a scattered definition of the dependency graph and can
make unit testing very difficult.

The Composition Root


(http://blog.ploeh.dk/2011/07/28/CompositionRoot/) pattern states
that the entire dependency graph should be composed in a single
location “as close as possible to the application’s entry point”. This could
get pretty messy without the assistance of a framework. DI frameworks
provide a mechanism, often referred to as an Inversion of Control (IoC)
Container, for offloading the instantiation, injection, and lifetime
management of dependencies to the framework. You invert the control
of component instantiation from the consumers to the container,
hence “Inversion of Control”.

To do this, you simply register services with a container, and then you
can load the top level service. The framework will inject all child
services for you. A simple example, based on the class definitions
above, might look like:

container.Register<Bar>().As<IBar>();
container.Register<Foo>();
// per the Composition Root pattern, this _should_ be the only lookup o
n the container
var foo = container.Get<Foo>();
Dependency Injection in ASP.Net Core
(https://stackify.com/)
Product  Pricing Solutions 

Prior to .Net Core (https://stackify.com/net-core-2-0-changes/), the only


Learn 
way to get DI in your applications was through the use of a Login
framework
such as Autofac (https://autofac.org/), Ninject
(http://www.ninject.org/), StructureMap
(https://structuremap.github.io/) and many others.
(https://github.com/danielpalme/IocPerformance) However, DI is
treated as a first-class citizen (https://docs.microsoft.com/en-
us/aspnet/core/fundamentals/dependency-injection) in ASP.Net Core.
You can configure your container in your Startup.ConfigureServices
method:

public class Startup {


public void ConfigureServices(IServiceCollection services) {
services.AddTransient<IArticleService, ArticleService>();
}
// ...
}

When a request gets routed to your controller, it will be resolved from


the container
(https://github.com/aspnet/Mvc/blob/eeac99985a61e75ca48e620f0371e16df
L26) along with all its dependencies:
public class(https://stackify.com/)
ArticlesController : Controller {
Product  Pricing Solutions 
private readonly IArticleService _articleService;
Learn 
public ArticlesController(IArticleService articleService) Login
{
_articleService = articleService;
}

[HttpGet("{id}"]
public async Task<IActionResult> GetAsync(int id) {
var article = await _articleService.GetAsync(id);
if(article == null)
return NotFound();
return Ok(article);
}
}

Dependency Lifetimes
At registration time, dependencies require a lifetime definition. The
service lifetime defines the conditions under which a new service
instance will be created. Below are the lifetimes defined by the ASP.Net
DI framework. The terminology may be different if you choose to use a
different framework.

Transient – Created every time they are requested


Scoped – Created once per scope. Most of the time, scope refers to
a web request. But this can also be used for any unit of work, such
as the execution of an Azure Function.
Singleton – Created only for the first request. If a particular
instance is specified at registration time, this instance will be
provided to all consumers of the registration type.

Using Different Providers


If you would like to use a more mature DI framework, you can do so as
(https://stackify.com/)
Product  Pricing Solutions 
long as they provide an IServiceProvider
(https://github.com/dotnet/corefx/blob/c6dbe361680efd21a20fdb8def01936
Learn  Login
L10) implementation. If they don’t provide one, it is a very simple
interface
(https://github.com/dotnet/corefx/blob/c6dbe361680efd21a20fdb8def01936
L10) that you should be able to implement yourself. You would just
return an instance of the container in your ConfigureServices method.
Here is an example using Autofac
(https://www.nuget.org/packages/Autofac/4.6.1):

public class Startup {


public IServiceProvider ConfigureServices(IServiceCollection services
) {
// setup the Autofac container
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterType<ArticleService>().As<IArticleService>();
var container = builder.Build();
// return the IServiceProvider implementation
return new AutofacServiceProvider(container);
}
// ...
}

Generics
Dependency injection can get really interesting when you start working
with generics. Most DI providers allow you to register open generic
types (https://docs.microsoft.com/en-us/dotnet/csharp/language-
reference/language-specification/types) that will have their generic
arguments set based on the requested generic type arguments. A great
example of this is Microsoft’s new logging framework
(Microsoft.Extensions.Logging).
(https://stackify.com/)
If you look under the hood
Product  Pricing Solutions 
(https://github.com/aspnet/Logging/blob/af314d54058389c8685dbaeb360c9
can see how they inject the open generic ILogger<>: Learn  Login

services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(L
ogger<>)));

This allows you to depend on the generic ILogger<> like so:

public class Foo {


public Foo(ILogger<Foo> logger) {
logger.LogInformation("Constructed!!!");
}
}

Another common use case is the Generic Repository Pattern


(https://cpratt.co/truly-generic-repository/). Some consider this an anti-
pattern (https://www.infoworld.com/article/3117713/application-
development/design-patterns-that-i-often-avoid-repository-
pattern.html) when used with an ORM like Entity Framework because it
already implements the Repository Pattern. But, if you’re unfamiliar
with DI and generics, I think it provides an easy entry point.

Open generic injection also provides a great mechanism for libraries


(such as JsonApiDotNetCore (https://github.com/json-api-
dotnet/JsonApiDotNetCore)) to offer default behaviors with easy
extensibility for applications. Suppose a framework provides an out-of-
the-box, implementation of the generic repository pattern. It may have
an interface that looks like this, implemented by a GenericRepository:

public interface IRepository<T> where T : IIdentifiable {


T Get(int id);
}
The library would provide some IServiceCollection extension method
(https://stackify.com/)
Product  Pricing Solutions 
like:
Learn  Login
public static void AddDefaultRepositories(this IServiceCollection servi
ces) {
services.TryAdd(ServiceDescriptor.Scoped(typeof(IRepository<>), typeo
f(GenericRepository<>)));
}

And the default behavior could be supplemented by the application on


a per resource basis by injecting a more specific type:

services.AddScoped<IRepository<Foo>, FooRepository>();

And of course FooRepository can inherit from GenericRepository<>.

class FooRepository : GenericRepository<Foo> {


Foo Get(int id) {
var foo = base.Get(id);
// ...authorization of resources or any other application concerns
can go here
return foo;
}
}

Beyond the Web


The ASP.Net team has separated their DI framework from the ASP.Net
packages into Microsoft.Extensions.DependencyInjection
(https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/
What this means is that you are not limited to web apps and can
leverage these new libraries in event-driven apps (such as Azure
(https://stackify.com/)
Product  Pricing Solutions 
Functions and AWS Lambda) or in thread loop apps. All you need to do
is: Learn  Login

1. Install the framework NuGet package:


Install-Package Microsoft.Extensions.DependencyInjection
or
dotnet add package Microsoft.Extensions.DependencyInjection

2. Register your dependencies on a static container:


var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<IEmailSender, AuthMessageSender>();
serviceCollection.AddScoped<AzureFunctionEventProcessor, IEventProc
essor>();
Container = serviceCollection.BuildServiceProvider();

3. Define the lifetime scope (if applicable) and resolve your top level
dependency:
var serviceScopeFactory = Container.GetRequiredService<IServiceScop
eFactory>();
using (var scope = serviceScopeFactory.CreateScope())
{
var processor = scope.ServiceProvider.GetService<IEventProcessor>
();
processor.Handle(theEvent);
}

Under the hood


(https://github.com/aspnet/DependencyInjection/blob/06e2de235ce5b27b42
the call to .BuildServiceProvider() will inject an IServiceScopeFactory
(https://github.com/aspnet/DependencyInjection/blob/d5e5aa703297b164b2
You can load this service and define a scope so you can use properly
scoped services. 
Disposable(https://stackify.com/)
Services
Product  Pricing Solutions 

If a registered service implements IDisposable it will be disposed of


Learn  Login
when the containing scope is disposed. You can see how this is done
here
(https://github.com/aspnet/DependencyInjection/blob/5a549d6a1ad59633b2
L57). For this reason, it is important to always resolve services from a
scope and not the root container, as described above. If you
resolve IDisposables from the root container, you may create a memory
leak since these services will not be disposed of until the container gets
disposed. 

Dynamic Service Resolution


Some DI providers provide resolution time hooks that allow you to
make runtime decisions about dependency injection. For example,
Autofac provides an AttachToComponentRegistration
(https://autofac.org/apidoc/html/DB09DDBB.htm) method that can be
used to make runtime decisions. At Stackify, we used this with Azure
Functions (https://stackify.com/azure-functions-performance-
monitoring-retrace/) to wrap the TraceWriter
(https://docs.microsoft.com/en-us/azure/azure-functions/functions-
reference-csharp#logging) (before they supported the ILogger
interface (https://github.com/Azure/Azure-Functions/issues/293))
behind a facade. This facade passed the logging method calls to the
scoped TraceWriter instance as well as our log4net logger. To do this,
we register the instance of the TraceWriter when we begin the lifetime
scope:
using (var scope = ServiceProvider.BeginLifetimeScope(b
(https://stackify.com/) => b.RegisterIn
Product  Pricing Solutions 
stance(traceWriter)))
{ Learn  Login
// ...
}

I’ve created a gist here


(https://gist.github.com/jaredcnance/45f5e7d367a02375c588087160e8f126) 
you can reference if you’d like to see the rest of the implementation.

When Not To Use IoC Containers


In general, IoC containers are an application concern. What this means
is library and framework authors should think carefully about whether
or not it is really necessary to create an IoC container within the
package itself. An example of one that does this is the
AspNetCore.Mvc framework packages. However, this framework is
intended to manage the life of the application itself. This is very
different than say a logging framework.

Conclusion
Dependency Injection describes the pattern of passing dependencies
to consuming services at instantiation. DI frameworks provide IoC
containers that allow developers to offload control of this process to
the framework. This lets us decouple our modules from their concrete
dependencies, improving testability
(https://stackify.com/fundamentals-web-application-performance-
testing/) and extensibility of our applications.
Hope this article was helpful. I often reference what we do here at
(https://stackify.com/)
Product  Pricing Solutions 
Stackify and wanted to share that we also use our own tools in house
to continually improve our applications. Both ourLearn
free dynamic
 Logincode
profile, Stackify Prefix (https://stackify.com/prefix), and our full lifecycle
APM, Stackify Retrace (https://stackify.com/retrace), help us make sure
we are providing our clients with the best value.

Note
All of the source code links used in this article are permalinks to the code on the default repository
branches. These links should be used as a reference and not as the current state of the underlying
implementations or APIs since these are subject to change at any time.

Improve Your Code with Retrace APM


Stackify’s APM tools are used by thousands of .NET, Java, PHP, Node.js, Python, & Ruby
developers all over the world.
Explore Retrace’s product features to learn more.

(/retrace-application-performance-management/)

App Performance Management (https://stackify.com/retrace-application-performance-


management/)

(/retrace-code-profiling/)

Code Profiling (https://stackify.com/retrace-code-profiling/)


(https://stackify.com/)
Product  Pricing Solutions 

Learn  Login
(/retrace-error-monitoring/)

Error Tracking (https://stackify.com/retrace-error-monitoring/)

(/retrace-log-management/)

Centralized Logging (https://stackify.com/retrace-log-management/)

(/retrace-app-metrics/)

App & Server Metrics (https://stackify.com/retrace-app-metrics/)

Learn More
(/retrace/)

 About the Author  Latest Posts

About Jared Nance


Software Engineer at Stackify and part-time consultant with over 10
years of experience in software development. He specializes in
developing .Net and JavaScript applications with a heavy focus on clean coding
(https://stackify.com/)
practices, testing and architecture. Product  Pricing Solutions 

 (https://twitter.com/jaredcnance) Learn  Login

Email

Sign Up Today

Search Stackify
 Search

Topics/Keywords
ASP.NET (https://stackify.com/?
Product Updates (https://stackify.com/stackify/)
tag=asp.net,net-core)

.NET Core App Monitoring (https://stackify.com/?


(https://stackify.com/content/net-core/) tag=monitoring,apm)

App Performance Tips (https://stackify.com/?


Java (https://stackify.com/content/java/)
tag=performance,profiler,apm)

Azure Error Handling (https://stackify.com/?


(https://stackify.com/content/azure/) tag=exception,exceptions,error,errors)

AWS
Logging Tips (https://stackify.com/?tag=logs,logging)
(https://stackify.com/content/AWS/)

Cloud (https://stackify.com/?
DevOps (https://stackify.com/content/DevOps/)
tag=cloud,azure,aws)

Popular Posts
ASP.NET Performance: 9 Types of Tools You Need to Know!

How to Troubleshoot IIS Worker Process (w3wp) High CPU Usage


How to Monitor IIS Performance: From the Basics to Advanced IIS Performance Monitoring
(https://stackify.com/)
Product  Pricing Solutions 

SQL Performance Tuning: 7 Practical Tips for Developers Learn  Login

Looking for New Relic Alternatives & Competitors? Learn Why Developers Pick Retrace

Recent Posts
Web Applications Monitoring Guide
(https://stackify.com/web-applications-monitoring-guide/)
(https://stackify.com/web-applications-
monitoring-guide/)

What Is
(https://stackify.com/nullreferenceexception-object-reference-not-set/)
NullReferenceException?
Object reference not set
to an instance of an object (https://stackify.com/nullreferenceexception-object-reference-not-set/)

Why you should use


(https://stackify.com/why-you-should-use-central-error-logging-services/)
Central Error Logging
Services
(https://stackify.com/why-you-should-use-central-error-logging-services/)

ASP.NET Performance: 9
(https://stackify.com/asp-net-performance-tools-you-need-to-know/)
Types of Tools You Need to
Know!
(https://stackify.com/asp-net-performance-tools-you-need-to-know/)

Performance Tuning in MySQL


(https://stackify.com/performance-tuning-in-mysql/)
(https://stackify.com/performance-tuning-in-
mysql/)
(https://stackify.com/)
Product  Pricing Solutions 

Learn  Login
(/stackify-developer-ebooks/)

(https://stackify.com/guest-blogging-guidelines/)

Get In Touch

Contact Us

Request a Demo

Start Free Trial

Products

Retrace

Prefix
.NET Monitoring (https://stackify.com/)
Product  Pricing Solutions 

Java Monitoring
Learn  Login
PHP Monitoring

Node.js Monitoring

Ruby Monitoring

Python Monitoring

Retrace vs New Relic

Retrace vs Application Insights

Solutions

Application Performance Management

Centralized Logging

Code Profiling

Error Tracking

Application & Server Monitoring

Real User Monitoring

For Developers

For DevOps

Resources

What is APM?

Pricing

Case Studies

Blog
Documentation
(https://stackify.com/)
Product  Pricing Solutions 
Free eBooks

Free Webinars Learn  Login

Videos

Ideas Portal

ROI Calculator

Support

News

Company

About Us

News

Careers

GDPR

Security Information

Terms & Conditions

Privacy Policy

PO Box 2159
Mission, KS 66201
816-888-5055 (tel:18168885055)

   
(https://www. (https://twitte (https://www. (https://www.
facebook.com r.com/Stackif youtube.com/ linkedin.com/
/Stackify/) y) channel/UCnx company/stac
YNQDtTr_ZY kify/)
UnMjeACfCg)

© 2020 Stackify

You might also like