Here the Unity registration
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<ITestService,TestService>(new InjectionConstructor("XXXXX"));
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
Here the webApi controller
[MyFilter]
public class TestController : ApiController
{
private ITestService _testService;
public EmployeeController(ITestService testService)
{
_testService = testService;
}
}
My test class
public interface ITestService
{
string GetText();
}
public class TestService : ITestService
{
private string _mystring;
public TestService(string mystring)
{
_mystring = mystring;
}
public string GetText()
{
return _mystring;
}
}
The problem : The value to inject in the constructor (hard coded here "XXXXX")is know only in [MyFilter] not before, not at registration time. Is it possible to inject a value coming from the attribute ?
Thanks,
Update1:
The workaround I used is save the value "XXXXX" in session working but not very clean.
public class MyFilter: AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
try
{
HttpContext.Current.Session["MyData"] = "XXXXX";
return;
HandleUnauthorized(actionContext);
}
catch (Exception ex)
{
}
}
private void HandleUnauthorized(HttpActionContext actionContext)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
Inject value in resolve method:
container.RegisterType<ITestService,TestService>();
...
var service = container.Resolve<ITestService>(new ParameterOverride(#"mystring", new InjectionParameter(typeof(string), "XXXXX")));
Expanding on my comment above, this example shows a way of storing the filter value in an attribute and recovering it to pass it into the TestService:
This assumes that each TestController will use the same filter (here abc), and that each OtherTestController will use the same other filter (like, def ?). That is, the filter attached to the type not the instance.
class Program
{
static void Main( string[] args )
{
var unityContainer = new UnityContainer();
unityContainer.RegisterType<ITestServiceFactory, TestServiceFactory>();
var theController = unityContainer.Resolve<TestController>();
// theController._testService.FilterString is "abc"
}
}
[MyFilter("abc")]
public class TestController
{
private ITestService _testService;
public TestController( ITestServiceFactory testServiceFactory )
{
_testService = testServiceFactory.CreateTestService(this);
}
}
public class MyFilterAttribute : Attribute
{
public string FilterString
{
get;
}
public MyFilterAttribute( string filterString )
{
FilterString = filterString;
}
}
public interface ITestServiceFactory
{
ITestService CreateTestService( object owner );
}
public interface ITestService
{
string GetText();
}
internal class TestServiceFactory : ITestServiceFactory
{
public ITestService CreateTestService( object owner )
{
return new TestService( ((MyFilterAttribute)owner.GetType().GetCustomAttribute( typeof( MyFilterAttribute ) )).FilterString );
}
}
internal class TestService : ITestService
{
public TestService( string mystring )
{
_mystring = mystring;
}
public string GetText()
{
return _mystring;
}
private readonly string _mystring;
}
If you don't insist on the attribute, you can simplify this and set the filter in TestController's constructor directly:
public TestController( ITestServiceFactory testServiceFactory )
{
_testService = testServiceFactory.CreateTestService("abc");
}
Related
Following i have a worker class and there is a foreach.
Inside the forach there is service call which can be GetX(), GetY() ...
as implementation, I have to re-initialize the Api client based on the parameter, is there pattern to avoid _aService.SetApiClient(p) Line?
public class Worker
{
private readonly IAService _aService;
public Worker(IAService entryPointService)
{
_aService = entryPointService;
}
protected void ExecuteAsync()
{
while (true)
{
new List<string>() { "x", "y", "z" }.ForEach(p =>
{
_aService.SetApiClient(p);
_aService.GetX();
// OR _aService.GetY(),_aService.GetYZ();//
});
}
}
}
public class AService : IAService
{
private GoogleApiClient _googleApiClient;
public AService(GoogleApiClient apiClient)
{
_googleApiClient = apiClient;
}
public void SetApiClient(string param)
{
_googleApiClient = new GoogleApiClient(new AuthProvider (param));
}
public string GetX()
{
return _googleApiClient.CallX();
}
}
public interface IAService
{
void SetApiClient(string param);
string GetX();
}
public interface IGoogleApiClient
{
string CallX();
string CallY();
string CallZ();
}
public class GoogleApiClient : IGoogleApiClient
{
private AuthProvider _param;
public GoogleApiClient(AuthProvider param)
{
_param = param;
}
public string CallX()
{
return DoSomeCal("X", _param);
}
public string CallY()
{
return DoSomeCal("Y", _param);
}
public string CallZ()
{
return DoSomeCal("Z", _param)
}
}
please note that string list values can be any thing
Your api client really doesn't need to hold state.(private field}) It is a service / gateway class. Rather just pass param into the methods e.g.GetX(string param}.
I am struggling with how to return Yield for type that is interface type of IBasic. Currently i can have three diffrent types of IBasic: InputData1, InputData2, InputData3.
The problem is on this part of code:
internal class CsvRepo<T> : ICsvRepo<T> where T : IBasic
{
private readonly ICsvSettings _settings;
public CsvRepo(ICsvSettings settings)
{
_settings = settings;
}
public IEnumerable<T> GetRecords()
{
//return from line in File.ReadLines(_settings.Path)
// select line.Split(',') into parts
// where parts.Length == 3
// select new InputData { X = Convert.ToInt32(parts[1]), Y = Convert.ToInt32(parts[2]) };
}
}
in the line: select new InputData
i am going to say something like return new IBasic but diffrent InputDataX has diffrent parameters and i am not sure how to do so? Is it possible?
This is full code:
namespace ClassLibrary3
{
public interface IRepo { }
public interface IRepository<T> : IRepo where T : IBasic { }
public interface ICsvRepo<T> : IRepository<T> where T : IBasic
{
IEnumerable<T> GetRecords();
}
public interface ISqlRepo
{
}
public interface IOracleRepo<T> : IRepository<T> where T : IBasic { }
public interface IRepoX : IRepo { }
public interface ICsvSettings
{
string Path { get; }
string FileName { get; }
}
public interface ISqlSettings
{
string ConnectionString { get; }
string Username { get; }
string Password { get; }
}
internal class CsvSettings : ICsvSettings
{
public string Path { get; set; }
public string FileName { get; set; }
}
internal class SqlSettings : ISqlSettings
{
public string ConnectionString { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
internal class CsvRepo<T> : ICsvRepo<T> where T : IBasic
{
private readonly ICsvSettings _settings;
public CsvRepo(ICsvSettings settings)
{
_settings = settings;
}
public IEnumerable<T> GetRecords()
{
return null;
//return from line in File.ReadLines(_settings.Path)
// select line.Split(',') into parts
// where parts.Length == 3
// select new InputData { X = Convert.ToInt32(parts[1]), Y = Convert.ToInt32(parts[2]) };
}
}
internal class SqlRepo : ISqlRepo
{
private readonly ISqlSettings _settings;
private readonly IRepoX _repoX;
public SqlRepo(ISqlSettings settings, IRepoX repoX)
{
_settings = settings;
_repoX = repoX;
}
}
internal class OracleRepo<T> : IOracleRepo<T> where T : IBasic
{
private readonly ISqlSettings _settings;
private readonly IRepoX _repoX;
public OracleRepo(ISqlSettings settings, IRepoX repoX)
{
_settings = settings;
_repoX = repoX;
}
}
internal class OracleRepo333<T> : IOracleRepo<T> where T : IBasic
{
private readonly ISqlSettings _settings;
private readonly IRepoX _repoX;
public int id;
public OracleRepo333(ISqlSettings settings, IRepoX repoX)
{
_settings = settings;
_repoX = repoX;
}
}
internal class RepoX : IRepoX { }
public class RepoModule : NinjectModule
{
private readonly string _username;
private readonly string _password;
public RepoModule(string username, string password)
{
_username = username;
_password = password;
}
public override void Load()
{
Bind<ICsvSettings>().ToConstant(new CsvSettings
{
FileName = "foo",
Path = Config.Instance.ServerName,
}).InSingletonScope();
Bind<ISqlSettings>().ToConstant(new SqlSettings
{
ConnectionString = "foo",
Password = _password,
Username = _username
}).InSingletonScope();
Bind<IRepoX>().To<RepoX>();
Bind(typeof(ICsvRepo<>)).To(typeof(CsvRepo<>));
Bind(typeof(ISqlRepo)).To(typeof(SqlRepo));
Bind(typeof(IOracleRepo<>)).To(typeof(OracleRepo<>));
Bind(typeof(IOracleRepo<>)).To(typeof(OracleRepo333<>));
}
}
public interface IBasic
{
}
public class InputData1 : IBasic
{
public int X;
public int Y;
}
public class InputData2 : IBasic
{
public string Name;
}
public class InputData3 : IBasic
{
public IEnumerable<string> WhateverList;
}
}
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel(new RepoModule("foo", "bar")); /*some other modules here maybe?*/
//thousand of code lines later...
var csvRepo = kernel.Get<ICsvRepo<InputData1>>();
//var data = FetchData(csvRepo);
var sqlRepo = kernel.Get<ISqlRepo>();
//data = FetchData(sqlRepo);
// var oracleRepo = kernel.Get<IOracleRepo<InputData>>();
//data = FetchData(oracleRepo);
var oracleRepos = kernel.GetAll<List<IOracleRepo<InputData1>>>();}
}
}
//static T[] FetchData<T>(IRepository<InputData> repo)
//{
// throw new NotImplementedException();
//}
}
The problem is that you are trying to return a concrete type where a generic type is expected. Consider the following instantiation of CsvRepo<T>
var repo = new CsvRepo<InputData1Derived>(null);
repo.GetRecords().First().PropFromInputData1Derived
You are instantiating InputData while the caller expects InputDataDerived. This is why the compiler does not let you do this.
You could have several solutions, let CsvRepo could be abstract and implement it for specific classes:
internal abstract class CsvRepo<T> : ICsvRepo<T> where T : IBasic
{
public CsvRepo()
{
}
public abstract IEnumerable<T> GetRecords();
}
internal class InputDataCsvRepo : CsvRepo<InputData1>
{
public override IEnumerable<InputData1> GetRecords()
{
return from line in File.ReadLines(_settings.Path)
select line.Split(',') into parts
where parts.Length == 3
select new InputData { X = Convert.ToInt32(parts[1]), Y = Convert.ToInt32(parts[2]) };
}
}
Or you can make the T parameter have a default constructor and use that (but only properties in IBasic will be initializable which is not what you want probably.
This seems to be one of those situations where if you have a hammer everything looks like a nail. In short there is no need to make the argument for the method generic as already know the concrete return type for any implementation and you want that return type to implement a specific interface.
Remove the generic type constraint T on method GetRecords and replace it with IBasic interface constraint.
public interface ICsvRepo<T> : IRepository<T> where T : IBasic
{
IEnumerable<IBasic> GetRecords();
}
internal class CsvRepo<T> : ICsvRepo<T> where T : IBasic
{
private readonly ICsvSettings _settings;
public CsvRepo(ICsvSettings settings)
{
_settings = settings;
}
public IEnumerable<IBasic> GetRecords()
{
return from line in File.ReadLines(_settings.Path)
select line.Split(',') into parts
where parts.Length == 3
select new InputData { X = Convert.ToInt32(parts[1]), Y = Convert.ToInt32(parts[2]) };
}
}
I altered your code below to only include what is needed to show the solution.
On an unrelated note making fields public is almost always a bad idea because you expose the internals of the class. Make them into properties instead with public getter/setters.
Example:
public class InputData : IBasic
{
public int X {get;set;}
public int Y {get;set;}
}
Basically, I'm trying to add a logging interceptor for each class that doesn't have a ILogger property or field.
The project I'm working with is build using Monorail 2.1, and the latest Castle Windsor stable release (August 2012, 3.1.0).
Let's say that I have:
[ViewComponentDetails("Followers")]
public class FollowersComponent : ViewComponent
{
private readonly ISession NHibernateSession;
public FollowersComponent(ISession session)
{
NHibernateSession = session;
}
public override void Render()
{
IPrincipal loggedUser = EngineContext.CurrentUser;
if ((loggedUser.Identity.AuthenticationType == "Monorail Type") && (loggedUser.Identity.IsAuthenticated))
{
var user = (PrincipalAdapter<Int64>)Session["User"];
PropertyBag["loggedUser"] = NHibernateSession.Get<User>(user.UserId);
RenderView("Followers");
}
}
}
And I want to add to this class, and any other class which doesn't have logging, the following interceptor:
public class AspectLogger : IInterceptor
{
public AspectLogger(ILoggerFactory loggerFactory)
{
LoggerFactory = loggerFactory;
Loggers = new ThreadSafeDictionary<Type, ILogger>();
}
public ILoggerFactory LoggerFactory { get; private set; }
public ThreadSafeDictionary<Type, ILogger> Loggers { get; private set; }
public void Intercept(IInvocation invocation)
{
if (!Loggers.ContainsKey(invocation.TargetType))
{
Loggers.Add(invocation.TargetType, LoggerFactory.Create(invocation.TargetType));
}
ILogger logger = Loggers[invocation.TargetType];
if (logger.IsDebugEnabled) logger.Debug(invocation.PrettyPrint());
try
{
invocation.Proceed();
}
catch (Exception ex)
{
if (logger.IsErrorEnabled) logger.Error(invocation.PrettyPrint(), ex);
throw;
}
}
}
So, using the docs from Windsor's site, and some other blogposts, I have come up with the following installers and facilities: a Nhibernate Installer/Facility which setups the session factory and session, a Monorail installer which adds the Monorail Windsor Facility and registers all the controllers, view components and filters and finally, a logging Installer which add this facility:
public class ExtendedLoggingFacility : LoggingFacility
{
public ExtendedLoggingFacility()
: base()
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi) :
base(loggingApi)
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi, string configFile) :
base(loggingApi, configFile)
{
}
public ExtendedLoggingFacility(string customLoggerFactory, string configFile) :
base(customLoggerFactory, configFile)
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi, string customLoggerFactory, string configFile) :
base(loggingApi, customLoggerFactory, configFile)
{
}
protected override void Init()
{
base.Init();
Kernel.Register(Component.For<IInterceptor>()
.ImplementedBy<AspectLogger>());
Kernel.ComponentRegistered += Kernel_ComponentRegistered;
}
private void Kernel_ComponentRegistered(string key, IHandler handler)
{
if (!(handler.ComponentModel.Implementation.GetProperties().Any(prop => prop.PropertyType.GetInterfaces().Contains(typeof(ILogger))) || handler.ComponentModel.Implementation.GetFields().Any(l=>l.FieldType.GetInterfaces().Contains(typeof(ILogger)))))
{
handler.ComponentModel.Interceptors.AddIfNotInCollection(new InterceptorReference(typeof(AspectLogger)));
}
}
}
The only problem? No interceptor gets registered! Atleast, according to this unit test:
[TestFixture]
public class ControllersInstallerTests
{
private IWindsorContainer containerWithControllers;
[SetUp]
public void OnSetup()
{
containerWithControllers = new WindsorContainer()
.Install(FromAssembly.Containing(typeof(UserController)));
}
[Test]
public void All_components_which_dont_have_ILogger_as_a_property_or_field_have_an_AspectLog()
{
var allComponents = GetPublicClassesFromApplicationAssembly(p => !(p.GetProperties().Any(prop => prop.PropertyType.IsAssignableFrom(typeof(ILogger)) || p.GetFields().Any(g => g.FieldType.IsAssignableFrom(typeof(ILogger))))));
var allHandlers = GetAllHandlers(containerWithControllers);
foreach (var comp in allComponents)
{
var handlersForComponent = GetHandlersFor(comp, containerWithControllers);
if (handlersForComponent.Length != 0)
Assert.True(handlersForComponent.All(p => p.ComponentModel.HasInterceptors));
}
}
Try changing your facility to this:
public class ExtendedLoggingFacility : LoggingFacility
{
public ExtendedLoggingFacility()
: base()
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi) :
base(loggingApi)
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi, string configFile) :
base(loggingApi, configFile)
{
}
public ExtendedLoggingFacility(string customLoggerFactory, string configFile) :
base(customLoggerFactory, configFile)
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi, string customLoggerFactory, string configFile) :
base(loggingApi, customLoggerFactory, configFile)
{
}
protected override void Init()
{
base.Init();
Kernel.Register(Component.For<AspectLogger>());
Kernel.ComponentModelCreated += Kernel_ComponentModelCreated;
}
private void Kernel_ComponentModelCreated(ComponentModel model)
{
if (
!(model.Implementation.GetProperties()
.Any(prop => prop.PropertyType.GetInterfaces().Contains(typeof(ILogger))) ||
model.Implementation.GetFields()
.Any(l => l.FieldType.GetInterfaces().Contains(typeof(ILogger)))))
{
model.Interceptors.AddIfNotInCollection(InterceptorReference.ForType<AspectLogger>());
}
}
}
Also, you should use a IContributeComponentModelConstruction instead: http://docs.castleproject.org/Default.aspx?Page=ComponentModel-construction-contributors&NS=Windsor&AspxAutoDetectCookieSupport=1
It would look like this:
public class ExtendedLoggingFacility : LoggingFacility
{
public ExtendedLoggingFacility()
: base()
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi) :
base(loggingApi)
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi, string configFile) :
base(loggingApi, configFile)
{
}
public ExtendedLoggingFacility(string customLoggerFactory, string configFile) :
base(customLoggerFactory, configFile)
{
}
public ExtendedLoggingFacility(LoggerImplementation loggingApi, string customLoggerFactory, string configFile) :
base(loggingApi, customLoggerFactory, configFile)
{
}
protected override void Init()
{
base.Init();
Kernel.Register(Component.For<AspectLogger>());
Kernel.ComponentModelBuilder.AddContributor(new AddLoggingAspect());
}
}
public class AddLoggingAspect : IContributeComponentModelConstruction
{
public void ProcessModel(IKernel kernel, ComponentModel model)
{
if (
!(model.Implementation.GetProperties()
.Any(prop => prop.PropertyType.GetInterfaces().Contains(typeof(ILogger))) ||
model.Implementation.GetFields()
.Any(l => l.FieldType.GetInterfaces().Contains(typeof(ILogger)))))
{
model.Interceptors.AddIfNotInCollection(InterceptorReference.ForType<AspectLogger>());
}
}
}
Let's assume that I have this scenario: I have got 2 repositories of information, and I want to access both, but it would be nice to leave the task of deciding which repo to use to common class.
The goal is to accomplish this with something similar to the code I've wrote below, but this sounds pretty bad:
where TOnline : class
where TOffline : class
where TContract : class
Sure I can ommit that, but bassically what I'm asking is what to do in order to stop using reflection and go typed. Maybe any design-pattern recomendation?
Code (if you copy/paste this on a console app replacing the Program class you should be able to run the example)
using CustomerDispatcher = DispatcherProxy<CustomerOnline, CustomerOffline, ICustomer>;
public interface ICustomer
{
string Get(int id);
}
public class CustomerOnline : ICustomer
{
public string Get(int id)
{
// Get From intranet DB
return "From DB";
}
}
public class CustomerOffline : ICustomer
{
public string Get(int id)
{
// Get From local storage
return "From local storage";
}
}
public class DispatcherProxy<TOnline, TOffline, TContract>
where TOnline : class
where TOffline : class
where TContract : class
{
public TContract Instance { get; set; }
public bool IsConnected { get; set; }
public DispatcherProxy()
{
// Asume that I check if it's connected or not
if (this.IsConnected)
this.Instance = (TContract)Activator.CreateInstance(typeof(TOnline));
else
this.Instance = (TContract)Activator.CreateInstance(typeof(TOffline));
}
}
class Program
{
static void Main(string[] args)
{
var customerDispatcher = new CustomerDispatcher();
Console.WriteLine("Result: " + customerDispatcher.Instance.Get(1));
Console.Read();
}
}
Thanks in advance!
You can add the new() constraint:
public class DispatcherProxy<TOnline, TOffline, TContract>
where TOnline : class, new()
where TOffline : class, new()
where TContract : class //isn't TContract an interface?
{
public TContract Instance { get; set; }
public bool IsConnected { get; set; }
public DispatcherProxy()
{
// Asume that I check if it's connected or not
if (this.IsConnected)
this.Instance = new TOnline() as TContract;
else
this.Instance = new TOffline() as TContract;
}
}
In case any of you are interested, I had to change the way I did this because it was checking connection at Constructor Level, and I needed that check at Operation Level.
using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace ConsoleApplication1
{
public enum ConnectionStatus
{
Online,
Offline,
System // System checks connectivity
}
public static class Connectivity
{
private static ConnectionStatus ConnectionStatus = ConnectionStatus.Offline;
public static void ForceConnectionStatus(ConnectionStatus connectionStatus)
{
ConnectionStatus = connectionStatus;
}
public static bool IsConnected()
{
switch (ConnectionStatus)
{
case ConnectionStatus.Online:
return true;
case ConnectionStatus.Offline:
return false;
case ConnectionStatus.System:
return CheckConnection();
}
return false;
}
private static bool CheckConnection()
{
return true;
}
}
public class Unity
{
public static IUnityContainer Container;
public static void Initialize()
{
Container = new UnityContainer();
Container.AddNewExtension<Interception>();
Container.RegisterType<ILogger, OnlineLogger>();
Container.Configure<Interception>().SetInterceptorFor<ILogger>(new InterfaceInterceptor());
}
}
class Program
{
static void Main(string[] args)
{
Unity.Initialize();
var r = new Router<ILogger, OnlineLogger, OnlineLogger>();
Connectivity.ForceConnectionStatus(ConnectionStatus.Offline);
Console.WriteLine("Calling Online, will attend offline: ");
r.Logger.Write("Used offline.");
Connectivity.ForceConnectionStatus(ConnectionStatus.Online);
Console.WriteLine("Calling Online, will attend online: ");
r.Logger.Write("Used Online. Clap Clap Clap.");
Console.ReadKey();
}
}
public class Router<TContract, TOnline, TOffline>
where TOnline : TContract
where TOffline : TContract
{
public TContract Logger;
public Router()
{
Logger = Unity.Container.Resolve<TContract>();
}
}
public interface IOnline
{
IOffline Offline { get; set; }
}
public interface IOffline
{
}
public interface ILogger
{
[Test()]
void Write(string message);
}
public class OnlineLogger : ILogger, IOnline
{
public IOffline Offline { get; set; }
public OnlineLogger()
{
this.Offline = new OfflineLogger();
}
public void Write(string message)
{
Console.WriteLine("Online Logger: " + message);
}
}
public class OfflineLogger : ILogger, IOffline
{
public IOnline Online { get; set; }
public void Write(string message)
{
Console.WriteLine("Offline Logger: " + message);
}
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public class TestAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new TestHandler();
}
}
public class TestHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("It's been intercepted.");
if (!Connectivity.IsConnected() && input.Target is IOnline)
{
Console.WriteLine("It's been canceled.");
var offline = ((input.Target as IOnline).Offline);
if (offline == null)
throw new Exception("Online class did not initialized Offline Dispatcher.");
var offlineResult = input.MethodBase.Invoke(offline, this.GetObjects(input.Inputs));
return input.CreateMethodReturn(offlineResult, this.GetObjects(input.Inputs));
}
return getNext()(input, getNext);
}
private object[] GetObjects(IParameterCollection parameterCollection)
{
var parameters = new object[parameterCollection.Count];
int i = 0;
foreach (var parameter in parameterCollection)
{
parameters[i] = parameter;
i++;
}
return parameters;
}
}
}
On AppEngine "Franch" and "English" as a dependency injection what do I do?
class Program
{
static void Main(string[] args)
{
IContainer container = ConfigureDependencies();
IAppEngine appEngine = container.GetInstance<IAppEngine>();
IGeeter g1 = container.GetInstance<IGeeter>("Franch");
IGeeter g2 = container.GetInstance<IGeeter>("English");
appEngine.Run();
}
private static IContainer ConfigureDependencies()
{
return new Container(x =>
{
x.For<IGeeter>().Add<FrenchGreeter>().Named("Franch");
x.For<IGeeter>().Add<EnglishGreeter>().Named("English");
x.For<IAppEngine>().Use<AppEngine>();
x.For<IGeeter>().Use<EnglishGreeter>();
x.For<IOutputDisplay>().Use<ConsoleOutputDisplay>();
});
}
}
public interface IAppEngine
{
void Run();
}
public interface IGeeter
{
string GetGreeting();
}
public interface IOutputDisplay
{
void Show(string message);
}
public class AppEngine : IAppEngine
{
private readonly IGeeter english;
private readonly IGeeter franch;
private readonly IOutputDisplay outputDisplay;
public AppEngine(IGeeter english,IGeeter franch, IOutputDisplay outputDisplay)
{
this.english = english;
this.franch = franch;
this.outputDisplay = outputDisplay;
}
public void Run()
{
outputDisplay.Show(greeter.GetGreeting());
}
}
public class EnglishGreeter : IGeeter
{
public string GetGreeting()
{
return "Hello";
}
}
public class FrenchGreeter : IGeeter
{
public string GetGreeting()
{
return "Bonjour";
}
}
As the contract for FrenchGreeter and EnglishGreeter is the same, StructureMap will not know which to use. For each wireing it uses only one instance per contract. Try something like this:
For<IGreeter>().Use<FrenchGreeter>().Named("French");
For<IGreeter>().Use<EnglishGreeter>().Named("English");
For<IAppEngine>().Use<AppEngine>()
.Ctor<IGreeter>("French").Is(x => x.TheInstanceNamed("French"))
.Ctor<IGreeter>("English").Is(x => x.TheInstanceNamed("English"));