I just started using Autofac. How do I register multiple components? I see this in the QuickStart guide:
private static IContainer Container { get; set; }
.
.
.
var builder = new ContainerBuilder();
builder.RegisterType<ConsoleOutput>().As<IOutput>();
builder.RegisterType<TodayWriter>().As<IDateWriter>();
Container = builder.Build();`
What happens if you have multiple components? Does each have their own container to run in? Do I create separate instances for each?
I tried this:
using System;
using Autofac;
namespace DemoApp
{
public class Program
{
private static IContainer ContainerA { get; set; }
private static IContainer ContainerB { get; set; }
static void Main(string[] args)
{
var builderA = new ContainerBuilderA();
builderA.RegisterType<ConsoleOutputA>().As<IOutputA>();
builderA.RegisterType<TodayWriterA>().As<IDateWriterA>();
ContainerA = builderA.Build();
var builderB = new ContainerBuilderB();
builderB.RegisterType<ConsoleOutputB>().As<IOutputB>();
builderB.RegisterType<TodayWriterB>().As<IDateWriterB>();
ContainerB = builderB.Build();
WriteDateA();
WriteDateB();
}
}
}
Is there a way to make this cleaner? Also, I am still new to Autofac..Do I still need to provide a design pattern or will autoface handle this for me?
Related
I have a class (Service) that receives 2 arguments (an IClient and an ICounter).
I want Unity to inject the same instance for both (a Decorator that implements both interfaces).
But how?
And one more thing: I want Unity to inject the same instance to Service using a per-thread basis. This is, in each a thread, each time container.Resolve<Service>() is invoked, the same instance of Decorator should be injected to both arguments of Service
This is the code I have so far. I only registers the types and it runs, but 3 instances of the Decorator class are created. In this case, with only one thread, only one instance of Decorator should be created.
You can run it with DotNetFiddle: https://dotnetfiddle.net/Widget/m3PRQz
using System;
using Microsoft.Practices.Unity;
namespace ConsoleApplication1
{
public class Program
{
public static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IClient>(new InjectionFactory(c => new Decorator(c.Resolve<Client>())));
container.RegisterType<ICounter, Decorator>();
container.Resolve<Service>();
Console.WriteLine(Decorator.NumberOfInstances + " instances of Decorator have been created");
}
}
public class Client : IClient
{
}
public class Decorator : IClient, ICounter
{
public static int NumberOfInstances { get; private set; }
public Decorator(IClient client)
{
NumberOfInstances++;
}
}
public interface ICounter
{
}
public interface IClient
{
}
public class Service
{
public Service(IClient client, ICounter counter)
{
}
}
}
EDIT: If I wasn't using DI, I would write this code. Keep in mind I don't invoke any method, for simplicity.
public class Program
{
public static void Main(string[] args)
{
var t1 = Task.Run(() => CreateService());
var t2 = Task.Run(() => CreateService());
}
private static Service CreateService()
{
var decorator = new Decorator(new Client());
return new Service(decorator, decorator);
}
}
You can try something like this:
register Decorator per thread:
container.RegisterType<Decorator>(
new PerThreadLifetimeManager(),
new InjectionFactory(c => new Decorator(c.Resolve<Client>())));
map interfaces to decorator:
container.RegisterType<ICounter, Decorator>();
container.RegisterType<IClient, Decorator>();
In Unity, I can register a named type like this
using Microsoft.Practices.Unity;
var container = new UnityContainer();
container.RegisterType<IOutputService, ConsoleOutputService>("Console");
container.RegisterType<IOutputService, MessageBoxOutputService>("MessageBox");
container.RegisterType<ICalculatorReplLoop, CalculatorReplLoop>();
ICalculatorReplLoop loop = container.Resolve<ICalculatorReplLoop>();
and auto resolve it using attribute like this
public class CalculatorReplLoop : ICalculatorReplLoop
{
public CalculatorReplLoop() {}
[Dependency("MessageBox")]
public IOutputService OutputService { get; set; }
}
I know how to register Named Service in Autofac
using Autofac;
using Autofac.Core;
var builder = new ContainerBuilder();
builder.RegisterType<ConsoleOutputService>().Named<IOutputService>("Console");
builder.RegisterType<MessageBoxOutputService>().Named<IOutputService>("MessageBox");
builder.RegisterType<CalculatorReplLoop>().As<ICalculatorReplLoop>().SingleInstance();
IContainer container = builder.Build();
ICalculatorReplLoop loop = container.Resolve<ICalculatorReplLoop>();
but how to resolve it inside CalculatorReplLoop class ?
Look at this Sample code and this is one of the ways of auto resolve the using autofac when you share a contract with two implementations.
using System;
using Autofac;
using Autofac.Features.Indexed;
namespace AutoFac
{
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<OnlineState>().Keyed<IDeviceState>("online");
builder.RegisterType<OfflineState>().Keyed<IDeviceState>("offline");
builder.RegisterType<Modem>().AsImplementedInterfaces();
var container = builder.Build();
var r = container.Resolve<IModem>();
r.print();
}
}
public interface IDeviceState
{
string Get();
}
public class OnlineState : IDeviceState
{
public string Get()
{
return "OnlineState";
}
}
public class OfflineState : IDeviceState
{
public string Get()
{
return "OfflineState";
}
}
public class Modem : IModem
{
readonly IIndex<string, IDeviceState> _states;
private readonly IDeviceState _deviceState;
public Modem(IIndex<string, IDeviceState> states)
{
_states = states;
_deviceState = _states["online"];
//_deviceState = _states["offline"];
}
public void print()
{
Console.WriteLine(_deviceState.Get());
}
}
public interface IModem
{
void print();
}
}
My code is as follows
IUnityContainer container = new UnityContainer();
container
.ConfigureAutoRegistration()
.LoadAssemblyFrom(typeof(Test).Assembly.Location)
.LoadAssemblyFrom(typeof(ITest).Assembly.Location)
.ApplyAutoRegistration();
This is my first question.
I'm not sure whether I have used the LoadAssemblyFrom method correctly here:
ITest test = container.Resolve<ITest>();
When I try to compile I get the exception "ResolutionFailedException".
What am I doing wrong?
Thanks for your time in advance.
It appears that what you are looking for is this:
container.ConfigureAutoRegistration()
.LoadAssemblyFrom(typeof(ITest).Assembly.Location)
.LoadAssemblyFrom(typeof(Test).Assembly.Location)
.Include(If.ImplementsITypeName, Then.Register())
.ApplyAutoRegistration();
This will tell Unity.AutoRegistration to register all types where there is an interface with the same name, prefixed with I.
Here is a complete working console example showing how to set Unity up for registration by convention, then transfer control into the dependency injection world. You will have to add the Unity NuGet package for this to work.
Tested with Unity v3.5 and VS 2012.
#region
using System;
using Microsoft.Practices.Unity;
#endregion
namespace Demo___Unity
{
internal class Program
{
private static void Main(string[] args)
{
using (var container = new UnityContainer())
{
// Manual method.
//container.RegisterType<IEntryPoint, EntryPoint>();
//container.RegisterType<IInjected, Injected>();
// Set up registration by convention.
// http://blogs.msdn.com/b/agile/archive/2013/03/12/unity-configuration-registration-by-convention.aspx
container.RegisterTypes(
AllClasses.FromAssembliesInBasePath(),
WithMappings.FromMatchingInterface,
WithName.Default,
WithLifetime.ContainerControlled);
var controller = container.Resolve<IEntryPoint>();
controller.Main();
}
}
}
public interface IEntryPoint
{
string Name { get; set; }
void Main();
}
public class EntryPoint : IEntryPoint
{
private readonly IInjected Injected;
public EntryPoint(IInjected injected)
{
Injected = injected;
}
public void Main()
{
Console.Write("Hello, world!\n");
Injected.SubMain();
Injected2.SubMain();
Console.Write("[any key to continue]");
Console.ReadKey();
}
// Demonstrates property injection.
[Dependency]
public IInjected Injected2 { get; set; }
public string Name { get; set; }
}
public interface IInjected
{
void SubMain();
}
public class Injected : IInjected
{
public void SubMain()
{
Console.Write("Hello, sub world!\n");
}
public string Name { get; set; }
}
}
I'm currently using MEF in my project, however, a legacy component uses Castle to export all its components.
I would like to be able to Import from this kernel when creating new objects, in addition to getting the exports from the Xap.
Is this possible? Can you show me some example code?
MEF was designed to be as flexible as possible, and one of its secretly hidden but real nice features, is the ability to define new ExportProvider instances, that allow you to plug in additional components. I've talked about this previously by utilising the Common Service Locator project in an ASP.NET MVC with MEF Project (see part 3 here).
The CSL is a nice flexible approach, as there are many specific CSL implementations for many of the existing IoC containers, such as Castle, Autofac, Ninject, Unity etc.
Another good example can be found here, which demonstrates a slightly different, but fundamentally similar approach.
As Matthew correctly said, the way to do this is using an ExportProvider
Another example is here (it demonstrates exports from Xaml).
Below is what I did in the end to solve the problem.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace MEFCastleBridge
{
public class CastleExportProvider : ExportProvider
{
WindsorContainer _container;
private readonly Dictionary<ExportDefinition, List<Export>> _exports =
new Dictionary<ExportDefinition, List<Export>>();
private readonly object _sync = new object();
public CastleExportProvider(WindsorContainer container)
{
_container = container;
var handlers = _container.Kernel.GetAssignableHandlers(typeof(object));
foreach (var handler in handlers)
{
RegisterCastleComponent(handler);
}
_container.Kernel.ComponentRegistered += ComponentRegistered;
}
protected override IEnumerable<Export> GetExportsCore(
ImportDefinition definition, AtomicComposition atomicComposition)
{
var contractDefinition = definition as ContractBasedImportDefinition;
var retVal = Enumerable.Empty<Export>();
if (contractDefinition != null)
{
string contractName = contractDefinition.ContractName;
if (!string.IsNullOrEmpty(contractName))
{
var exports =
from e in _exports
where string.Compare(e.Key.ContractName, contractName, StringComparison.OrdinalIgnoreCase) == 0
select e.Value;
if (exports.Count() > 0)
{
retVal = exports.First();
}
}
}
return retVal;
}
void RegisterCastleComponent(IHandler handler)
{
var type = handler.Service;
var contractName = type.ToString();
lock (_sync)
{
var found = from e in _exports
where string.Compare(e.Key.ContractName,
contractName, StringComparison.OrdinalIgnoreCase) == 0
select e;
if (found.Count() == 0)
{
var metadata = new Dictionary<string, object>();
var definition = new ExportDefinition(contractName, metadata);
_exports.Add(definition, new List<Export>());
}
var wrapper = new Export(contractName, () => _container.Resolve(type));
found.First().Value.Add(wrapper);
}
}
void ComponentRegistered(string key, IHandler handler)
{
RegisterCastleComponent(handler);
}
}
public interface IMyComponent
{
string TheString { get; }
}
public class RegisteredComponent : IMyComponent
{
public string TheString { get { return "RegisteredComponent"; } }
}
[Export(typeof(IMyComponent))]
public class ExportedComponent : IMyComponent
{
public string TheString { get { return "ExportedComponent"; } }
}
public class ExportExample
{
// Will contain an instance of RegisteredComponent and ExportedComponent
[ImportMany]
public List<IMyComponent> Components { get; set; }
public ExportExample()
{
// Create a Windsor container and add a type.
var container = new WindsorContainer();
container.Register(Component.For<IMyComponent>().ImplementedBy<MyComponent>().LifeStyle.Singleton);
// Add the Export Provider, in addition to the DeploymentCatalog
var compContainer = new CompositionContainer(new DeploymentCatalog(), new CastleExportProvider(container));
// Should only be called once, before any attempt to SatisfyImports.
CompositionHost.Initialize(compContainer);
CompositionInitializer.SatisfyImports(this);
Test = string.Join(", ", Components.Select(c => c.DoSomething));
}
public string Test { get; set; }
}
}
I have IMessageSender interface.
using System.ComponentModel.Composition;
public interface IMessageSender
{
void Send(string message);
}
And I have two plugins that implements this interface. This is plugin.cs.
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System;
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
}
and this is plugin2.cs
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message + "!!!!");
}
}
And I have this code to run those plugins with MEF.
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System.Collections.Generic;
using System;
public class Program
{
[ImportMany]
public IEnumerable<IMessageSender> MessageSender { get; set; }
public static void Main(string[] args)
{
Program p = new Program();
p.Run();
foreach (var message in p.MessageSender) {
message.Send("hello, world");
}
}
public void Run()
{
Compose();
}
private void Compose()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(#"./"));
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
After compilation, I get what I want.
> mono program.exe
hello, world
hello, world!!!!
My question is how can I selectively run out of many plugins. This example just gets all the available plugins to run all of them, but what should I do when I just want to run first plugin or second plugin?
For example, can I run only plugin2.dll as follows?
public static void Main(string[] args)
{
Program p = new Program();
p.Run();
var message = messageSender.GetPlugin("plugin"); // ???
message.Send("hello, world");
}
SOLVED
Based on this site, and Matthew Abbott's answer. I could come up with this working code.
interface code (interface.cs)
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System;
public interface IMessageSender
{
void Send(string message);
}
public interface IMessageSenderMetadata
{
string Name {get; }
string Version {get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class MessageMetadataAttribute : ExportAttribute, IMessageSenderMetadata
{
public MessageMetadataAttribute( string name, string version)
: base(typeof(IMessageSender))
{
Name = name;
Version = version;
}
public string Name { get; set; }
public string Version { get; set; }
}
Plugin code (Plugin.cs ...)
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System;
[MessageMetadataAttribute("EmailSender1", "1.0.0.0")]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message + "????");
}
}
Program.cs
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System.Collections.Generic;
using System;
using System.Linq;
public class Program
{
[ImportMany(typeof(IMessageSender), AllowRecomposition = true)]
public IEnumerable<Lazy<IMessageSender, IMessageSenderMetadata>> Senders { get; set; }
public static void Main(string[] args)
{
Program p = new Program();
p.Run();
var sender1 = p.GetMessageSender("EmailSender1","1.0.0.0");
sender1.Send("hello, world");
sender1 = p.GetMessageSender("EmailSender2","1.0.0.0");
sender1.Send("hello, world");
}
public void Run()
{
Compose();
}
public IMessageSender GetMessageSender(string name, string version)
{
return Senders
.Where(l => l.Metadata.Name.Equals(name) && l.Metadata.Version.Equals(version))
.Select(l => l.Value)
.FirstOrDefault();
}
private void Compose()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(#"./"));
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
MEF supports the exporting of custom metadata to accompany your exported types. What you need to do, is first define an interface that MEF will use to create a proxy object containing your metadata. In your example, you'll likely need a unique name for each export, so we could define:
public interface INameMetadata
{
string Name { get; }
}
What you would then need to do, is make sure you assign that metadata for each of your exports that require it:
[Export(typeof(IMessageSender)), ExportMetadata("Name", "EmailSender1")]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
}
What MEF will do, is generate a project an implementation of your interface, INameMetadata using the value stored in the ExportMetadata("Name", "EmailSender1") atrribute.
After you've done that, you can do a little filtering, so redefine your [Import] to something like:
[ImportMany]
public IEnumerable<Lazy<IMessageSender, INameMetadata>> Senders { get; set; }
What MEF will create is an enumerable of Lazy<T, TMetadata> instances which support deferred instantiation of your instance type. We can query as:
public IMessageSender GetMessageSender(string name)
{
return Senders
.Where(l => l.Metadata.Name.Equals(name))
.Select(l => l.Value)
.FirstOrDefault();
}
Running this with an argument of "EmailSender1" for the name parameter will result in our instance of EmailSender being returned. The important thing to note is how we've selected a specific instance to use, based on querying the metadata associated with the type.
You can go one further, and you could amalgamate the Export and ExportMetadata attributes into a single attribute, such like:
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false), MetadataAttribute]
public class ExportMessageSenderAttribute : ExportAttribute, INameMetadata
{
public ExportMessageSenderAttribute(string name)
: base(typeof(IMessageSender))
{
Name = name;
}
public string Name { get; private set; }
}
This allows us to use a single attribute to export a type, whilst still providing additional metadata:
[ExportMessageSender("EmailSender2")]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
}
Obviously querying this way presents you with a design decision. Using Lazy<T, TMetadata> instances means that you'll be able to defer instantiation of the instance, but that does mean that only one instance can be created per lazy. The Silverlight variant of the MEF framework also supports the ExportFactory<T, TMetadata> type, which allows you to spin up new instances of T each time, whilist still providing you with the rich metadata mechanism.