Using MEF with MVC - c#

I'm starting to use MEF with my MVC application, so that it follows SOLID priciples.
I asked this question last week: Should a dependency be injected many "levels" up than it is needed? and part of what I asked (in the comments) was, if you have two constructors;
One constructor for Dependancy Injection
Another construtor with no parameters
And the contstructor with no parameters instantiates instances of the dependancies needed, then this should make a Service Locator moot. The response was that a class should not instantiate it's own dependancies. OK, I get this, but looking at this MS tutorial on MEF:
http://msdn.microsoft.com/en-us/library/hh708870(v=vs.110).aspx
They say you should have two constructors:
public HomeController() : this(new TraceLogger())
{
}
public HomeController(ILogger logger)
{
_logger = logger;
}
But from what I've been told, the first constructor is a no-no as the class is instantiating it's own dependacy?
Also, in the tutorial, MS just say; replace the second construtor with this:
public HomeController([Import("myTraceLogger")]ILogger logger)
{
_logger = logger;
}
What's the point in that? I still have to supply an instance of of the ILogger... unless I'm missing something? I removed the default constructor:
public HomeController() : this(new TraceLogger())
{
}
And the application just says: "No parameterless constructor defined for this object."
So I must have to supply an instance, because if MEF was creating a new instance, surly it would work without a default constructor... and if not, what's the point in using MEF? I might as well just do the dependancy injection myself.

Sounds like you need to use [ImportingConstructor] attribute on your HomeController(ILogger) constructor. Like so:
[ImportingConstructor]
public HomeController([Import("myTraceLogger")]ILogger logger)
{
_logger = logger;
}
MEF creates a singleton instance of ILogger (by default). It will make sure to create ILogger before it creates your HomeController class.
A service locator is convenient when you are creating a list of objects with exported types as part of some run-time workflow.

OK. So you could use MEF to do Dependancy Injection and inject the parts, but personally I wouldn't. The performance i've seen on it is pretty dire. If you use it wrongly it can also leak and consume memory easily.
You can apply your solid principals with other techniques. Use a well know Inversion of Control (IoC) container, such as StructureMap or AutoFac. You can add the nuget package to your MVC app, write a few lines of setup code in the global asax and your constructors will automagically work. These are also much more forgiving and easier to setup and configure.
When you application starts up and creates the IoC container (or when the object is first requested depending on your settings), the dependency is 'Newed' up and injected into your class constructor. Effectively you don't need to do much other than tell the IoC container where to find an instance of a Logger class (i.e. in which assembly) if you class requests an ILogger.
public HomeController(ILogger logger)
{
_logger = logger;
}
Check out these posts.
Structure Map website
How do I get StructureMap working with an
AngularJs / MVC5 and WebApi2 web project
How to configure
StructureMap for asp.net MVC 5

Related

What is the best way to merge into one same services injected in several constructors?

I'm working on a ASP.net core app and of course using dependency injection. Mainly injecting required services in constructors of pages or other services.
Some of these injected services are the same in almost every other constructor. For example there is the ILogger<T>, an IAppInfo holding some application wide information and there is an IFileServices used in many other services also.
So I end up with lots of injections in constructors, in some more than 7.
Question is, which is the best way to get rid of all there parameters used in almost every constructor?
For now I have implemented another service with methods to get the required services:
public interface IBasicsService<out T>
{
ILogger<T> GetLogger();
ApplicationInfo GetApplicationInfo();
}
implemented in:
public class BasicsService<T> : IBasicsService<T>
{
private readonly ILogger<T> _logger;
private readonly ApplicationInfo _info;
// ReSharper disable once ContextualLoggerProblem
public BasicsService(ApplicationInfo info, ILogger<T> logger) {
_info = info;
_logger = logger;
}
public ILogger<T> GetLogger() {
return _logger;
}
public ApplicationInfo GetApplicationInfo() {
return _info;
}
}
Is that correct? Is it better to inject IServiceProvider and resolve services with this?
Thank you.
It is better not to use IServiceProvider it hides the dependency of your service
Assume that in some case you want to test this service
oops your are forced to Mock IserviceProvider.
The task that you wants to do has no differ from using ServiceLocator
This link can help you to see why it is not good to use ServiceLocator
ServiceLocator is an antipattern
But if you are really wants to do that in any circumstances, Constructor injection is not the only way that you can use to inject dependency.
There is another way that called Property injection
This is a good discussion about property injection
Property Injection in ASP.NET Core
Do not forget you can configure asp.net core to use some other IOC containers like castle Windsor or Unity that support property injection

How do I get Type that Dependency is being injected into?

Im working with .net core 2.2 and using dependency injection. I have some custom infrastructure dependencies that manage logging, tracing, etc. that I inject into classes. I'd like the dependencies to know what class they are in. I can do that if I instantiate the class like new Logger<Type>(); but is that possible to manage with dependency injection?
Ex:
public class Logger<Type> : ILogger
{
}
public class Foo
{
private Ilogger _logger;
public Foo(ILogger logger)
{
_logger = logger;
}
public void DoStuff()
{
_logger.Log(); //<= knows it's in the Foo class.
}
}
How do I inject ILogger into Foo, and have the Logger know what Type it was injected into?
You can specify the type like this
public class Foo
{
private Ilogger<Foo> _logger;
}
Then in the Logger, you can know the type of T by
public class Logger<T> : ILogger<T>
{
public Type WhatType() => typeof(T);
}
You will need to register the service like this
serviceCollection.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
While more mature and feature rich DI Containers, such as Autofac and Simple Injector, do support context-based injection (which is the feature you are looking for), MS.DI does not support this feature.
It is for this very reason that all the Microsoft documentation describe the injection of a generic ILogger<T> where T equals the consuming type, as in:
public class C
{
public C(ILogger<C> logger) { ... }
}
Letting a consumer depend on the generic ILogger<T>, instead of simply depending on a non-generic ILogger, however, is more verbose and error prone. It makes you code harder to test and harder to maintain. This is likely the reason you are trying to inject a context-aware ILogger instead, and I applaud you for that.
You can kinda 'hack' this feature into MS.DI by iterating through the ServiceCollection, but there are practically too many limitations to it to be workable in your production application. For fun and entertainment, however, this is what you can try:
// Run just before finalizing the IServiceCollection
for (int i = 0; i < services.Count; i++)
{
ServiceDescriptor descriptor = services[i];
if (descriptor.ImplementationType != null)
{
var loggerParameters =
from ctor in descriptor.ImplementationType.GetConstructors()
from param in ctor.GetParameters()
where param.ParameterType == typeof(ILogger)
select param;
if (loggerParameters.Any())
{
// Replace registration
services[i] =
new ServiceDescriptor(
descriptor.ServiceType,
provider =>
ActivatorUtilities.CreateInstance(
provider,
descriptor.ImplementationType,
provider.GetRequiredService(
typeof(ILogger<>).MakeGenericType(
descriptor.ImplementationType))),
descriptor.Lifetime);
}
}
}
What this code does is:
search for registrations of
(closed or non-generic) implementation type
that uses Auto-Wiring (so no lambda registration, or instance registration)
and whose constructor depends on ILogger
and replaces that registration with a lambda registration that Auto-Wires the type (using ActivatorUtilities) while replacing the ILogger dependency with an ILogger<T> dependency.
Limitations:
Doesn't work on open-generic registrations
Doesn't work on delegate registrations
Might not work when replacing MS.DI with another DI Containers (e.g. might "blind" the container).
Behavior is undefined when working with multiple constructors
In practice, I would therefore not suggest using this approach but instead use a mature DI Container.
TIP: To get some inspiration, when using Simple Injector, such context-based registration can be made as follows:
container.RegisterConditional(
typeof(ILogger),
c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
When integrating with ASP.NET Core, Simple Injector even contains an extension method that simplifies this. Here's the Simple Injector documentation on how to configure the container to inject ASP.NET Core's ILogger, and the basic description on how to apply context-based injection in Simple Injector can be found here.

Get Instance from Simple Injector without "GetInstance" method

Following this answer I did this :
public class Log4netAdapter<T> : ILogger
{
private static readonly log4net.ILog logger = LogManager.GetLogger(typeof(T));
public void Log(LogEntry entry)
{
if(entry.LoggingEventType == LoggingEventType.Information)
logger.Info(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Warning)
logger.Warn(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Error)
logger.Error(entry.Message, entry.Exception);
else
logger.Fatal(entry.Message, entry.Exception);
}
}
And then on the Simple Injector :
container.RegisterConditional(
typeof(ILogger),
c => typeof(Log4netAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
This works great if I inject the ILogger on every class constructor I need. My problem is that I have some classes that I cannot use the constructor injection. For this cases I would tipically do :
var logger = SimpleInjectorInitializer.Container.GetInstance<ILogger>();
However the above method does not work, it throws an error on the simple injector class since the c.Consumer is null.
Here is one of the examples I need to resolve ILogger, this class is registered on the webapi startup class.
public class ExceptionWebApiHandlingAttribute : IExceptionFilter
{
public ExceptionWebApiHandlingAttribute()
{
}
}
Is there any alternative ?
Thanks
When working on the application boundary, it is sometimes hard or impossible to use constructor injection. Typical examples are MVC filter attributes or ASP.NET Web Form Page classes that require a default constructor.
A typical solution to these problems is to make such boundary class into a Humble Object, where all interesting logic is extracted from the boundary class into a component. The boundary class should only contain the call to the Service Locator and call one method on the resolved service. This minimizes the amount of untestable code in the application.
In all other cases, constructor injection should be preferred.
The fact however that you resolve an ILogger implies that your boundary class does too much. Instead this ILogger should be a constructor dependency of the component that you extracted from the boundary class to become a Humble Object.
Once you've done this, you won't be resolving ILogger directly anymore and this solves your problem; ILogger has become a dependency of a consumer and this ensures that Simple Injector is able to build the correct Logger<T> on your behalf.
When it comes to applying dependencies to exception filters in Web API (your particular case), a good solution is to create a proxy for your exception filters that will delegate the call to the real filter that gets resolved. This can be a bit of infrastructure and the concept is explained here.
If it is impossible to apply the above advise, for whatever reason, you can always request a Logger<T> directly from the container:
ILogger log = SimpleInjectorInitializer.Container.GetInstance<Logger<MyHumbleObject>>();

Structuremap IContainer Implementation

I am currently trying to get my head around structuremap now that the ObjectFactory static function has been marked as obsolete.
In the long run I have to use this in a MVC and WebApi application. When previously used, a line to a static method was placed in the the global.asax to initialise everything using the ObjectFactory.
ObjectFactory.Initialize{
container.For .....
}
Trying to convert this to the new IContainer approach I have come up with the following however am wondering if I have actually inadvertently implemented this often mentioned Anti-Pattern in my approach.
Static method to return container:
public class StructureMapConfig
{
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
}
Userservice's contstructor looks like this:
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly IStringService _stringService;
public UserService(IUserRepository userRepository, IStringService stringService)
{
_userRepository = userRepository;
_stringService = stringService;
}
Finally the initialise (this instance in a console app) looks somthing like this:
private static IUserService _userService;
private static IContainer _container;
static void Main(string[] args)
{
_container = StructureMapConfig.GetContainer();
_userService = _container.GetInstance<IUserService>();
}
So to my questions.
Am I doing anything seriously wrong here
In the UserService, should I be passing the IContainer in and using the object factory to get the instance or should I leave as is.
Is returning the IContainer from the static method the best approach
If this was a MVC app, is it best practice to build this once in the Global.asax or should the controller constructor call the static method every time.
Thanks for any advice.
To go through your questions in order:
Am I doing anything seriously wrong here
No, I don't see anything seriously wrong here. There are a few improvements you could make that I'll talk about shortly.
In the UserService, should I be passing the IContainer in and using
the object factory to get the instance or should I leave as is.
You're correct in injecting UserService over an instance of IContainer. If your controller only requires the UserService then why inject the entire container. Really you only want to inject the bare minimum of what you need to reduce unnecessary coupling and dependencies.
Is returning the IContainer from the static method the best approach
Within the removal of the ObjectFactory then yes, returning an instance of the container via a static method is a common approach for those classes whose creation is not managed via MVC's Dependency Resolution.
If this was a MVC app, is it best practice to build this once in the
Global.asax or should the controller constructor call the static
method every time.
Creating the container in Global.asax.cs is your best approach as it's done once on Application_Start, however see below for my recommendation of using a nested container per http request.
Improvements:-
Take advantage of StructureMap's registries:
Instead of referencing the dependencies directly like this:
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
Opt to use StructureMap's registries instead. This way you can group your dependencies (such as MVC specific dependencies or WebAPI specific dependencies, like so:
public class WebsiteRegistry : Registry
{
public WebsiteRegistry()
{
this.For<IUserService>().Use<UserService>();
this.For<IStringService>().Use<StringService>();
this.For<IUserRepository>().Use<UserRepository>();
}
}
Then load your registries like this:
container.Configure(c => {
c.IncludeRegistry<WebsiteRegistry>();
c.IncludeRegistry<TaskRegistry>();
});
HTTP Context bound containers:
Another recommended pattern when using StructureMap with ASP.NET MVC or WebApi (or any HTTP based application) is to use nested containers that are bound to each HTTP request. This basically involves creating a new nested container on each HTTP request and then disposing it at the end of the request. This ensures that dependencies such as session objects, database connections, or UoW contexts are disposed of as soon as the HTTP request is over.
I would recommend taking a look over this article which goes into more detail on the matter and talks about how this can be set up.
This is exactly the same technique that's used in the StructureMap.MVC5 package that's often recommended by StructureMap's creator, Jeremy Miller.
Auto registering dependencies
Instead of registering every dependency with StructureMap manually you can take advantage of StructureMap's auto-registration. You can also specify your own scanning conventions.

Get the container instance for Simple Injector

I am using Simple Injector with a ASP.NET MVC project. I added the SimpleInjector.Integration.Web.Mvc nuget package. This adds SimpleInjectorInitializer class in App_Start folder and initializes the DI. The code looks something like
public static void Initialize()
{
// Did you know the container can diagnose your configuration?
// Go to: https://simpleinjector.org/diagnostics
var container = new Container();
//Container configuration code
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
}
This configures the DI for the MVC controller correctly.
My question is, if I want to get the instance of the container in any of the controller\class to resolve some dependency manually how can I do it.
I have earlier worked on AutoFac and it has a dependency interface IComponentContext which can be injected into any class that needs to do any resolution manually.
Update:
Here is a scenario. My controller uses a service who initialization depends upon the input parameter passed in the controller method and hence the dependency cannot be instantiated during construction time.
I understand that this is somewhat an anti pattern for DI, but it is requirement at few places and hence injecting the DI container is next best thing. Simple Injector samples should use of static variable to share the container which i want to avoid and also it is not possible by the way SimpleInjectorInitializer works.
Except for any code that is part of the startup path of the application, no code should depend directly on the container (or a container abstraction, container facade, etc). This pattern is called Service Locator and Mark Seemann has a good explanation why this is a bad idea.
So components (such as Controllers) should not depend on the container directly, since this hides the used dependencies and makes classes harder to test. Furthermore your code starts to depend on an external framework (making it harder to change) or depending on an abstraction it doesn't need to know about.
My controller uses a service who initialization depends upon the input
parameter passed in the controller method and hence the dependency
cannot be instantiated during construction time
There's a general pattern for this problem: the abstract factory design pattern. The factory pattern allows you to delay the creation of types and allows you to pass in extra runtime parameters for the construction of a certain type. When you do this, your controller doesn't have to depend on Container and it prevents you from having to pass in a constructed container in your unit tests (DI frameworks should in general not be used in your unit test projects).
Do note however that letting your components require runtime data during creation is a code smell. Prevent doing that.
You might think that by doing this we are just moving the problem to the factory implementation. Although we are moving the dependency on the container into the factory implementation, we are in fact solving the problem because the factory implementation will be part of the application's Composition Root, which allows the application code itself oblivious to any DI framework.
So this is how I advice you to structure your code:
// Definition of the factory in the UI or BL layer
public interface ISomeServiceFactory
{
ISomeService Create(int inputParameter);
}
// Controller depending on that factory:
public class MyController : Controller
{
private readonly ISomeServiceFactory factory;
public MyController(ISomeServiceFactory factory)
{
this.factory = factory;
}
public ActionResult Index(int value)
{
// here we use that factory
var service = this.factory.Create(value);
}
}
In your composition root (the start up path) we define the factory implementation and the registration for it:
private class SomeServiceFactory : ISomeServiceFactory
{
private readonly Container container;
// Here we depend on Container, which is fine, since
// we're inside the composition root. The rest of the
// application knows nothing about a DI framework.
public SomeServiceFactory(Container container)
{
this.container = container;
}
public ISomeService Create(int inputParameter)
{
// Do what ever we need to do here. For instance:
if (inputParameter == 0)
return this.container.GetInstance<Service1>();
else
return this.container.GetInstance<Service2>();
}
}
public static void Initialize()
{
var container = new Container();
container.RegisterSingle<ISomeServiceFactory, SomeServiceFactory>();
}
Upon creation, the Container registers itself (using the call RegisterSingle<Container>(this)) so you can always inject the container into any component. That's similar to injecting the IComponentContext when working with Autofac. But the same holds for Autofac, Simple Injector, and any other container: you don't want to inject your container into components that are located outside the composition root (and there hardly ever is a reason for it).

Categories

Resources