How to use Property Injection with AutoFac? - c#

In a Console application, I'm using Log4Net and in the Main method I'm getting the logger object. Now, I'd like to make this log object available in all my classes by letting all the classes inherit from a BaseClass which has a ILog property and is supposed to be set by Property Injection rather than Constructor Injection.
I'm using AutoFac IoC container, how to inject my log Object to the Log property of my every class?
What's the best/easiest way to achieve this?
Is there any way to automatically resolve types?
Below is my test application:
namespace ConsoleApplication1
{
class Program
{
static ILog Log;
static IContainer Container;
static void Main(string[] args)
{
InitializeLogger();
InitializeAutoFac();
// the below works but could it be done automatically (without specifying the name of each class)?
Product.Log = Container.Resolve<ILog>();
// tried below but didn't inject ILog object into the Product
Container.Resolve<Product>();
RunTest();
Console.ReadLine();
}
private static void RunTest()
{
var product = new Product();
product.Do();
}
private static void InitializeAutoFac()
{
var builder = new ContainerBuilder();
builder.Register(c => Log).As<ILog>();
builder.RegisterType<Product>().PropertiesAutowired();
Container = builder.Build();
}
private static void InitializeLogger()
{
log4net.Config.XmlConfigurator.Configure();
Log = LogManager.GetLogger("LoggerName");
}
}
public class Product
{
public static ILog Log { get; set; }
public void Do()
{
// this throws exception because Log is not set
Log.Debug("some Debug");
}
}
}

In my opinion the solution Ninject created is much nicer than the propertyinjection in Autofac. Therefore I created a a custom attribute which is a postsharp aspect which automatically injects my classes:
[AutofacResolve]
public IStorageManager StorageManager { get; set; }
My aspect:
[Serializable]
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class AutofacResolveAttribute : LocationInterceptionAspect
{
public override void OnGetValue(LocationInterceptionArgs args)
{
args.ProceedGetValue();
if (!args.Location.LocationType.IsInterface) return;
if ( args.Value != null )
{
args.Value = DependencyResolver.Current.GetService(args.Location.LocationType);
args.ProceedSetValue();
}
}
}
I know the answer on the question is already given but I thought this was a really neat way of solving automatic property injection in Autofac. Maybe it'll be useful to somebody in the future.

Use Property Injection:
builder.Register(c => LogManager.GetLogger("LoggerName"))
.As<ILog>();
builder.RegisterType<CustomClass>()
.PropertiesAutowired();

Property injection works for Properties and not for Fields. In your class, Log is a field and not a property and hence it will never get resolved by the Autofac.

I didn't want to use postsharp so I made a quick solution, but it doesn't auto inject. I am new to Autofac, and it should be possible to build on to this solution.
[Serializable]
[AttributeUsage(AttributeTargets.Property)]
public class AutofacResolveAttribute : Attribute
{
}
public class AutofactResolver
{
/// <summary>
/// Injecting objects into properties marked with "AutofacResolve"
/// </summary>
/// <param name="obj">Source object</param>
public static void InjectProperties(object obj)
{
var propertiesToInject = obj.GetType().GetProperties()
.Where(x => x.CustomAttributes.Any(y => y.AttributeType.Name == nameof(AutofacResolveAttribute))).ToList();
foreach (var property in propertiesToInject)
{
var objectToInject = Autofact.SharedContainer.Resolve(property.PropertyType);
property.SetValue(obj, objectToInject, null);
}
}
}
Use it with this call:
AutofactResolver.InjectProperties(sourceObject);

Use Property Injection (In addition to #cuongle answer).
Option 1:
builder.Register(c => LogManager.GetLogger("LoggerName")).As<ILog>();
builder.RegisterType<Product>()
.WithProperty("Log", LogManager.GetLogger("LoggerName"));
Option 2:
Or you can add a SetLog method to the Product class:
public class Product
{
public static ILog Log { get; set; }
public SetLog(Log log)
{
this.Log = log;
}
}
This way you won't have to call LogManager.GetLogger("LoggerName") twice but to use the context of the builder in order to resolve the Log.
builder.Register(c => LogManager.GetLogger("LoggerName")).As<ILog>();
builder.Register(c =>
var product = new Product();
product.SetLog(c.Resolve<Log>());
return product;
);
Option 3:
Use the OnActvated:
The OnActivated event is raised once a component is fully constructed.
Here you can perform application-level tasks that depend on the
component being fully constructed - these should be rare.
builder.RegisterType<Product>()
.OnActivated((IActivatedEventArgs<Log> e) =>
{
var product = e.Context.Resolve<Parent>();
e.Instance.SetParent(product);
});
These options gives more control, and you will not have to worry about #steven comment:
The scary thing with PropertiesAutowired however is that it does
implicit property injection, which means that any unresolvable
dependencies will be skipped. This makes it easy to miss configuration
errors and can result in application that fails at runtime

There is an interface IPropertySelector that you can implement and pass the implementaiton via .PropertiesAutowired(new MyPropertySelector()). This will allow you to implement any logic you want.

Related

Having some parameters Injected with DI and some assigned manually

In a .NET Core 3.1 console application I want a Class that would have some parameters in constructor injected but some that I could assign manually. For example something like that but with IConfiguration Injected:
static void Main() {
var myObj1 = new MyClass(1);
var myObj2 = new MyClass(2);
}
public class MyClass {
public MyClass(IConfiguraiton config, int myVal)
{
}
}
I tried this with Ninject:
static void Main()
{
kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
kernel.Get<MyClass>();
}
public class MyClass
{
public MyClass(IConfiguraiton config)
{
}
}
public class Bindings : NinjectModule
{
public override void Load()
{
var configuration = new ConfigurationBuilder().AddJsonFile($"appsettings.json").Build();
Bind<IConfiguration>().ToMethod(ctx => SetupConfiguration()).InSingletonScope();
Bind<MyClass>().ToSelf().InTransientScope();
}
}
I managed to make simple dependency injection, but haven't had any success making injection with parameters.
I've read a lot of people suggesting that it's better to pass parameters into methods of the class rather than constructor, however in my situation this isn't an option in addition I'm a software engineering student, and would like to learn how to do this, since it might be useful in some situations.
This is a situation where the Ninject.Extensions.Factory is useful, as it is made exactly for this situation. It does pull in the Factory dependency in addition to Castle.Core, as it uses DynamicProxy under the hood (as a SE student, playing with this library is a good idea for using the interceptor pattern).
To use it, you define a Factory interface like so:
public interface IMyClassFactory
{
MyClass Create(int myVal);
}
Note that the Create method returns MyClass, and the argument(s) to the Create method match exactly in type and name to the arguments you wish to provide. The argument type(s) you want injected must be registered with the kernel. Unfortunately, it is easy to make a mistake here - if you specify a parameter that does not exist in the factory interface it is ignored, but if you forget one it will throw an exception when called.
Next, register IMyClassFactory like this: Bind<IMyClassFactory>().ToFactory(); and remove your binding for MyClass. Then wherever you need to create an instance, inject IMyClassFactory and call Create: kernel.Get<IMyClassFactory>().Create(2)
You can achieve the same result without using Ninject.Extensions.Factory by writing and registering your own implementation of IMyClassFactory, essentially doing the same thing that the code the Factory extension ends up emitting. A full sample is below using both methods based on commenting in/out the registration (note the output if you add .InSingletonScope() to the registration of IConfiguraiton - both approaches respect the binding scopes of Ninject).
internal class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Bind<IConfiguraiton>().To<Configuraiton>();
kernel.Bind<IMyClassFactory>().ToFactory();
//kernel.Bind<IMyClassFactory>().To<NinjectMyClassFactory>().InSingletonScope();
var factory = kernel.Get<IMyClassFactory>();
var one = factory.Create(1);
var two = factory.Create(2);
}
}
public interface IMyClassFactory
{
MyClass Create(int myVal);
}
public class NinjectMyClassFactory : IMyClassFactory
{
public NinjectMyClassFactory(IResolutionRoot resolutionRoot)
{
ResolutionRoot = resolutionRoot;
}
private IResolutionRoot ResolutionRoot { get; }
public MyClass Create(int myVal)
{
return ResolutionRoot.Get<MyClass>(new ConstructorArgument("myVal", myVal));
}
}
public class MyClass
{
public MyClass(IConfiguraiton config, int myVal)
{
Console.Out.WriteLine("Created MyClass({0},{1})", config.MyNum, myVal);
}
}
public interface IConfiguraiton { int MyNum { get; } }
public class Configuraiton : IConfiguraiton
{
static int CreateCount;
public Configuraiton()
{
MyNum = Interlocked.Increment(ref CreateCount);
}
public int MyNum { get; }
}

Dependency Injection Into {get; set;} Property

I was wondering how I'd go about setting up my Dependency Injection to inject a dependency into properties that have public getters and setters ({get; set}).
So, an example would be:
namespace Dexter.Services {
public class CommandHandlerService : InitializableModule {
public CommandService CommandService { get; set; }
}
}
With the following dependency injector:
namespace Dexter {
public static class InitializeDependencies {
public static async Task Main() {
ServiceCollection ServiceCollection = new();
CommandService CommandService = new();
ServiceCollection.AddSingleton(CommandService);
Assembly.GetExecutingAssembly().GetTypes()
.Where(Type => Type.IsSubclassOf(typeof(InitializableModule)) && !Type.IsAbstract)
.ToList().ForEach(
Type => ServiceCollection.TryAddSingleton(Type)
);
ServiceProvider = ServiceCollection.BuildServiceProvider();
// Initialization stuff.
}
}
}
In this example, I would like the CommandService to automatically inject into the property.
I know this is possible because Discord.NET is able to do this, and I'd love to stick with that same codestyle.
( Discord.NET: https://docs.stillu.cc/guides/commands/dependency-injection.html )
Thanks! <3
This can be done without having to swap out the default DI container (IServiceProvider) using the Quickwire NuGet package.
Simply decorate your service with the [RegisterService] attribute and add [InjectService] to the property. No need for the interface.
[RegisterService(ServiceLifetime.Singleton)]
public class CommandHandlerService {
[InjectService]
public CommandService CommandService { get; set; }
}
Now from your main function, just call ScanCurrentAssembly:
public static async Task Main() {
ServiceCollection ServiceCollection = new();
ServiceCollection.ScanCurrentAssembly();
ServiceProvider = ServiceCollection.BuildServiceProvider();
// Initialization stuff.
}
Behind the scenes, ScanCurrentAssembly does all the necessary wiring to resolve dependencies, instantiate the class and inject it into properties.
For anyone curious, as per what Panagiotis recommended, a solution to this would be to create your own dependency injection. As such, I wrote a small method that loops through all the services in the provider, and attaches public properties to it. It may have bugs! Particularly regarding scoped services, of which I haven't written for it to support, but this should work as a good starting point for someone wishing to achieve a similar result!
public static object SetClassParameters(this object newClass, IServiceScope scope, IServiceProvider sp)
{
newClass.GetType().GetProperties().ToList().ForEach(property =>
{
if (property.PropertyType == typeof(IServiceProvider))
property.SetValue(newClass, sp);
else
{
object service = scope.ServiceProvider.GetService(property.PropertyType);
if (service != null)
{
property.SetValue(newClass, service);
}
}
});
return newClass;
}
Where you can use a method like the following to inject dependencies into classes. For instance, I wished to inject them into classes that extended an abstract "event" class that I made. This can be seen below:
using (var scope = serviceProvider.CreateScope()) {
GetEvents().ForEach(
type => serviceProvider.GetRequiredService(type).SetClassParameters(scope, serviceProvider)
);
}
Where GetEvents() is a reflexive function that returns all classes extending the abstract class given.

Requiring an attribute for CastleWindsor property injection

Although I prefer constructor injection, I want developers on my team to be able to use property injection as long as they explicitly mark the property as injectable with an attribute. According to CastleWindsor documentation here, this should be possible by creating a contributor and then calling AddContributor with it through the Kernel. I cannot seem to get this to work. All public properties (even those without the attribute) are injected.
When I set a breakpoint in my contributor ProcessModel method, it sets all properties with the attribute to mandatory (IsOptional = false) and skips over any properties that do not have the attribute. But despite this, the properties without the attribute still get injected. What am I doing wrong?
Below is my code:
Contributor
public class PropertyInjectionContributor : IContributeComponentModelConstruction
{
public void ProcessModel(IKernel kernel, ComponentModel model)
{
model.Properties
.Where(p => p.Property.IsDefined(typeof(InjectedAttribute)))
.All(p => p.Dependency.IsOptional = false);
}
}
Attribute
[AttributeUsage(AttributeTargets.Property)]
public class InjectedAttribute : Attribute { }
Add contributor to Kernel.ComponentModelBuilder and register components
public class Program
{
public static void Main(string[] args)
{
var container = new WindsorContainer();
container.Kernel.ComponentModelBuilder.AddContributor(new PropertyInjectionContributor());
container.Register(Component.For<IClass1>()
.ImplementedBy<Class1>()
.LifestyleTransient());
container.Register(Component.For<IClass2>()
.ImplementedBy<Class2>()
.LifestyleTransient());
var class1 = container.Resolve<IClass1>();
class1.DoSomething();
}
}
Class1
public class Class1 : IClass1
{
//[Injected]
public IClass2 Class2 { get; set; }
public void DoSomething()
{
Class2.DoSomething();
}
}
The Class2 property within Class1 is injected even though it is not decorated with the Injected attribute.
My current workaround for this is to remove CastleWindsor's PropertiesDependenciesModelInspector and replace it with an implementation that forces IsOptional to be false. It works but it repeats a lot of CW's code. I'd prefer to use the simple approach above if I can only get it to work!

In which library should an abstract factory interface and an actual factory be defined?

Short question
Where should I put the abstract factory interface and the actual factory?
Overview
I'm writing a simple video transcoding application and I'm trying to wrap my head around dependency injection.
I have separated my application into several projects in visual studio.
One class library for the transcoder, used by the application engine
One class library for the application engine that will be used by a gui or console interface
One console application that will be the main user interface for now
Without DI
This is what everything looks like before dependency injection
The transcoder lib:
namespace SimpleFFmpeg {
public interface ITranscoder {
void Transcode(String fileName);
}
public class Transcoder:ITranscoder {
// ...
public void Transcode(String fileName) {
// do transcoding stuff
}
// ...
}
}
The PusherEngine lib:
using SimpleFFmpeg;
namespace PusherLib {
public class PusherEngine {
private readonly List<VideoItem> _items;
public PusherEngine() {
_items = new List<VideoItem>();
}
// ...
public void processItems() {
foreach (VideoItem item in _items) {
ITranscoder t = new Transcoder();
t.Transcode(item.FileName);
}
}
// ...
}
}
The actual application:
namespace Pusher {
class Program {
static void Main(string[] args) {
PusherEngine pe = new PusherEngine();
pe.addVideoItem(new VideoItem(...));
pe.processItems();
}
}
}
Refactor to use DI
I create a generic abstract factory interface, like suggested in this question: Creating new instances while still using Dependency Injection
public interface IFactory<T> {
T Get();
}
Next I create a factory that creates ITranscoders
public class TranscoderFactory: IFactory<ITranscoder> {
public ITranscoder Get() {
return new SimpleFFmpeg.Transcoder();
}
}
Then I modify the PusherEngine to require a factory dependence in the constructor:
using SimpleFFmpeg;
namespace PusherLib {
public class PusherEngine {
private readonly IFactory<ITranscoder> _transcoderFactory;
private readonly List<VideoItem> _items;
public PusherEngine(IFactory<ITranscoder> transcoderFactory) {
_items = new List<VideoItem>();
_transcoderFactory = transcoderFactory;
}
// ...
public void processItems() {
foreach (VideoItem item in _items) {
ITranscoder t = _transcoderFactory.Get();
t.Transcode(item.FileName);
}
}
// ...
}
}
Finally, in the Program it looks like this:
namespace Pusher {
class Program {
static void Main(string[] args) {
IFactory<ITranscoder> f = new TranscoderFactory();
PusherEngine pe = new PusherEngine(f);
pe.addVideoItem(new VideoItem(...));
pe.processItems();
}
}
}
Question
In which lib/project should the IFactory interface be defined?
In which lib/project should the TranscoderFactory be defined?
Do they live in the Transcoder lib? In the PusherLib? Or in the actual frontend application?
I'm looking for best practices.
Thanks!
In my opinion, it doesn't matter. For me, the main point of dependency injection is being able to inject something other than the real implementation while testing. I keep my unit tests in a separate project along with the various mock definitions used for testing. The real implementations as well as the 'abstract' logic are all kept in the same assembly/project/namespace.
If you really need a factory (see comment), then this blog post by Mark Seemann addresses this issue.
Briefly, if you use the IoC Container in your factory, you want to use it in the composition root. If not, there is no harm for it to remain in the same assembly as the class it is instantiating.
EDIT
For your particular case, you do not need a factory, since you already have everything you need to solve this dependency.
using SimpleFFmpeg;
namespace PusherLib {
public class PusherEngine {
private readonly ITranscoder _transcoder;
private readonly List<VideoItem> _items;
public PusherEngine(ITranscoder transcoder) {
_items = new List<VideoItem>();
_transcoder = transcoder;
}
// ...
public void processItems() {
foreach (VideoItem item in _items) {
_transcoder.Transcode(item.FileName);
}
}
// ...
}
}
The initialization would then look like this:
namespace Pusher {
class Program {
static void Main(string[] args) {
ITranscoder t = new Transcoder();
PusherEngine pe = new PusherEngine(t);
pe.addVideoItem(new VideoItem(...));
pe.processItems();
}
}
}
The reason why a factory was needed in the answer you linked is that the dependency needed values only known at run-time to be able to be instantiated, while your dependency does not require run-time dependent arguments to be created.
To answer your actual question, and not if this is a good use case for a factory or not:
For this purpose I sometimes split up Interface and Implementation into different projects, and something like your IFactory<> would live in the Common.I project.
This doesn't work in every scenario, but one of the advantages of this approach for me is that I can swap out Implementation dll's with either mocks or a new implementation when there are underlying technology changes.
For example, we recently switched from parsing xml files from a directory to getting data from a service. The only thing I had to update on client machines was this one Implementation dll because the interface did not change at all.
But I guess in the end it doesn't really matter, as mentioned before.

How to Inject daoFactory into NHibernate EventListener

I need to Inject some global service (daoFactory) into EventListenet subscribed on PostUpdate event. I`ve read that it is possible to do this way:
public class YourPostInsertListener : IPostInsertEventListener
{
private readonly IPersistentAuditor auditor;
public YourPostInsertListener(IPersistentAuditor auditor)
{
this.auditor = auditor;
}
public void OnPostInsert(PostInsertEvent #event)
But this code just throws exception: no parameterless constructor was specified for EventListener. And this is understandable behavior, because I haven`t added my service to any container. So how can I specify the IoC contauner in NHibernate?
The IoC that I've been using is Ninject. The best way I found so far is to take advantage of the ServiceLocator provdided by the Microsoft Patterns and Practices guys:
internal class YourPostInsertListener : IPostInsertEventListener
{
IKernel Kernel
{
get
{
return ServiceLocator.Current.GetInstance<IKernel>();
}
}
IPersistentAuditor
{
get
{
return Kernel.Get<IPersistentAuditor>();
}
}
// ... Rest of class
}
In the class that sets up your IoC container you would do this:
ServiceLocator.SetLocatorProvider( () => new NinjectServiceLocator( kernel ) );

Categories

Resources