I wrote a blog entry about MEF a while back (I just checked and it was four years ago!). My boss came across a container called AutoFac which I did not know about so I've been looking at it. I am particularly interested in how the different types of registration affect the timing of the constructors.
Create a new C# .Net WPF project (I used Framework 4.5.1 but it should work with Core too). Call it DemoAutoFac. Use NuGet to add the AutoFac package.
Change App.xaml.cs to look like this.
using System.Windows;
namespace DemoAutoFac
{
public partial class App : Application
{
public static Autofac.IContainer Container { get; set; }
}
}
namespace DemoAutoFac
public partial class App : Application
{
public static Autofac.IContainer Container { get; set; }
}
and change MainWindow.xaml.cs to look like this.
using Autofac;
using System;
using System.Windows;
namespace DemoAutoFac
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
namespace DemoAutoFac
public partial class MainWindow : Window
{
public MainWindow()
InitializeComponent();
Console.WriteLine("-------------------------");
Console.WriteLine("MainWindow");
CreateAutoFacContainerByType();
WriteDate();
WriteDate();
Console.WriteLine("");
CreateAutoFacContainerByInstance();
WriteDate();
WriteDate();
}
public void CreateAutoFacContainerByType()
{
Console.WriteLine("CreateAutoFacContainerByType");
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ConsoleOutput>().As<IOutput>();
builder.RegisterType<TodayWriter>().As<IDateWriter>();
DemoAutoFac.App.Container = builder.Build();
Console.WriteLine("Exit
CreateAutoFacContainerByType");
}
public void CreateAutoFacContainerByInstance()
{
Console.WriteLine("CreateAutoFacContainerByInstance");
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterInstance<ConsoleOutput>(new ConsoleOutput()).As<IOutput>();
builder.RegisterInstance<TodayWriter>(new TodayWriter()).As<IDateWriter>();
DemoAutoFac.App.Container = builder.Build();
Console.WriteLine("Exit
CreateAutoFacContainerByInstance");
}
public void WriteDate()
{
DemoAutoFac.App.Container.Resolve<IDateWriter>().WriteDate();
}
}
public interface IOutput
{
void Write(string content);
}
public class ConsoleOutput : IOutput
{
public ConsoleOutput()
{
Console.WriteLine("ctor ConsoleOutput");
}
public void Write(string content)
{
Console.WriteLine("ConsoleOutput.Write");
Console.WriteLine(content);
}
}
public interface IDateWriter
{
void WriteDate();
}
public class TodayWriter : IDateWriter
{
public TodayWriter()
{
Console.WriteLine("ctor TodayWriter");
}
public void WriteDate()
{
IOutput output = DemoAutoFac.App.Container.Resolve<IOutput>();
output.Write(DateTime.Today.ToShortDateString());
}
}
}
WriteDate();
WriteDate();
Console.WriteLine("");
WriteDate();
WriteDate();
}
public void CreateAutoFacContainerByType()
Console.WriteLine("CreateAutoFacContainerByType");
public void CreateAutoFacContainerByInstance()
Console.WriteLine("CreateAutoFacContainerByInstance");
public void WriteDate()
DemoAutoFac.App.Container.Resolve<IDateWriter>().WriteDate();
}
public interface IOutput
{
void Write(string content);
public class ConsoleOutput : IOutput
{
public ConsoleOutput()
Console.WriteLine("ctor ConsoleOutput");
public void Write(string content)
Console.WriteLine("ConsoleOutput.Write");
}
public interface IDateWriter
{
void WriteDate();
public class TodayWriter : IDateWriter
{
public TodayWriter()
Console.WriteLine("ctor TodayWriter");
public void WriteDate()
IOutput output = DemoAutoFac.App.Container.Resolve<IOutput>();
}
}
You can see when we use RegisterType, the constructors are not called until the class is used. However, the constructor is called EACH TIME we call WriteDate. We could use a Singleton pattern, but we would have to use that for each registered class and it will not work with a strict singleton pattern. You'd have to have a non-singleton wrapper around a singleton object because AutoFac wants to call a constructor.
The output after the blank line shows the results of RegisterInstance. The constructors are called as I register the instances, but they are only ever called once. The TodayWriter.WriteDate method can access the container to fetch a reference to the correct IOutput class.
I prefer the second method. You can avoid delays while registering instances by implementing just-in-time initialization.
No comments:
Post a Comment