We are using SimpleInjector as a Dependency Injector, and we are registering all interface types using assembly iteration.
public static void RegisterInterfaceTypes(this Container container, Assembly assembly)
{
assembly.GetExportedTypes()
.Select(t => new {
Type = t,
Interface = t.GetInterfaces().FirstOrDefault()
})
.ToList()
.ForEach(t =>
{
container.Register(t.Interface, t.Type, Lifestyle.Transient);
});
}
We also have lazy classes to register. We can register these classes like below one by one. But we want to register all lazy types with similar iteration using reflection.
container.Register(() => new Lazy<ICommonBusiness>(container.GetInstance<CommonBusiness>));
You can make use of the ResolveUnregisteredType extension method to make last-minute registrations for resolve Lazy<T> dependencies:
Source:
public static void AllowResolvingLazyFactories(this Container container)
{
container.ResolveUnregisteredType += (sender, e) =>
{
if (e.UnregisteredServiceType.IsGenericType &&
e.UnregisteredServiceType.GetGenericTypeDefinition() == typeof(Lazy<>))
{
Type serviceType = e.UnregisteredServiceType.GetGenericArguments()[0];
InstanceProducer registration = container.GetRegistration(serviceType, true);
Type funcType = typeof(Func<>).MakeGenericType(serviceType);
Type lazyType = typeof(Lazy<>).MakeGenericType(serviceType);
var factoryDelegate = Expression.Lambda(funcType, registration.BuildExpression()).Compile();
var lazyConstructor = (
from ctor in lazyType.GetConstructors()
where ctor.GetParameters().Length == 1
where ctor.GetParameters()[0].ParameterType == funcType
select ctor)
.Single();
var expression = Expression.New(lazyConstructor, Expression.Constant(factoryDelegate));
var lazyRegistration = registration.Lifestyle.CreateRegistration(
serviceType: lazyType,
instanceCreator: Expression.Lambda<Func<object>>(expression).Compile(),
container: container);
e.Register(lazyRegistration);
}
};
}
Usage:
container.AllowResolvingLazyFactories();
But please note the warnings from the documentation:
Warning: Registering [Lazy<T>] by default is a design smell. The use of [Lazy<T>] makes your design harder to follow and your system harder to maintain and test. Your system should only have a few of those [...] at most. If you have many constructors in your system that depend on a [Lazy<T>], please take a good look at your dependency strategy. The following article goes into details about why [this is] a design smell.
Warning: [...] the constructors of your components should be simple, reliable and quick (as explained in this blog post by Mark Seemann). That would remove the need for lazy initialization. For more information about creating an application and container configuration that can be successfully verified, please read the How To Verify the container’s configuration.
Related
In a previous question about how I visualize the graph of my dependencies I got the foundation for the code I now use to visualize my dependency graph as it is resolved by Autofac.
Running the code I get a tree that results in code like the following.
Usd.EA.Bogfoering.WebApi.Controllers.BogfoerController (3851,7 ms. / 0,0 ms.) Depth: 0
Usd.EA.Bogfoering.WebApi.Controllers.BogfoerController (3851,7 ms. / 0,4 ms.) Depth: 1
Usd.Utilities.WebApi.Controllers.UnikOwinContext (0,1 ms. / 0,0 ms.) Depth: 2
Usd.Utilities.WebApi.Controllers.UnikOwinContext (0,1 ms. / 0,0 ms.) Depth: 3
In the start I thought there was a problem with the code, and that it for some reason resulted in the components getting resolved multiple times. As Steven points out, this could happen when a component is registered as InstancePerDependency. But as several of my components are registered as InstancePerLifetime or SingleInstance dependencies, those dependencies shouldn't be resolved twice in the graph.
Steven does mention that "the first resolve of the InstancePerDependency dependency seems to have more dependencies than the next resolve, because this graph only shows resolves. Perhaps this is what's going on." But as I'm seeing InstancePerLifetime components being registered multiple times, on several occasions throughout the graph, I have the feeling that there's something else going on here.
What could be going on here?
How the dependencies are registered
The following code is the one we use to register our assemblies:
public static void RegisterAssemblies(this ContainerBuilder containerBuilder, IList<Assembly> assemblies, params Type[] typesToExclude)
{
if (containerBuilder != null && assemblies.Any())
{
var allTypes = assemblies.SelectMany(assembly => assembly.GetTypes()).Where(t => !typesToExclude.Any(t2 => t2.IsAssignableFrom(t))).ToList();
RegisterAllClassesWithoutAttribute(containerBuilder, allTypes);
RegisterClassesThatAreSingleton(containerBuilder, allTypes);
RegisterClassesThatAreInstancePerLifetimeScope(containerBuilder, allTypes);
RegisterGenericInterfaces(containerBuilder, allTypes);
RegisterRealOrTestImplementations(containerBuilder, allTypes);
RegisterAutofacModules(containerBuilder, allTypes);
containerBuilder.Register(c => UnikCallContextProvider.CurrentContext).As<IUnikCallContext>();
}
}
private static void RegisterAutofacModules(ContainerBuilder containerBuilder, List<Type> allTypes)
{
var modules = allTypes.Where(type => typeof(IModule).IsAssignableFrom(type) && type.GetCustomAttribute<DoNotRegisterInIocAttribute>() == null);
foreach (var module in modules)
{
containerBuilder.RegisterModule((IModule) Activator.CreateInstance(module));
}
}
private static void RegisterRealOrTestImplementations(ContainerBuilder containerBuilder, List<Type> allTypes)
{
if (StaticConfigurationHelper.UseRealImplementationsInsteadOfTestImplementations)
{
var realTypes = allTypes.Where(type => type.GetCustomAttribute<RealImplementationAsInstancePerLifetimeScopeAttribute>() != null).ToArray();
containerBuilder.RegisterTypes(realTypes).AsImplementedInterfaces()
.InstancePerLifetimeScope();
}
else
{
var testTypes = allTypes.Where(type => type.GetCustomAttribute<TestImplementationAsInstancePerLifetimeScopeAttribute>() != null).ToArray();
containerBuilder.RegisterTypes(testTypes).AsImplementedInterfaces()
.InstancePerLifetimeScope();
}
}
private static void RegisterGenericInterfaces(ContainerBuilder containerBuilder, List<Type> allTypes)
{
var typesAsGenericInterface = allTypes.Where(type => type.GetCustomAttribute<RegisterAsGenericInterfaceAttribute>() != null).ToArray();
foreach (var type in typesAsGenericInterface)
{
var attribute = type.GetCustomAttribute<RegisterAsGenericInterfaceAttribute>();
containerBuilder.RegisterGeneric(type).As(attribute.Type);
}
}
private static void RegisterClassesThatAreInstancePerLifetimeScope(ContainerBuilder containerBuilder, List<Type> allTypes)
{
var typesAsInstancePerDependency = allTypes.Where(type => type.GetCustomAttribute<InstancePerLifetimeScopeAttribute>() != null).ToArray();
containerBuilder.RegisterTypes(typesAsInstancePerDependency).InstancePerLifetimeScope().AsImplementedInterfaces();
}
private static void RegisterClassesThatAreSingleton(ContainerBuilder containerBuilder, List<Type> allTypes)
{
var typesAsSingleton = allTypes.Where(type => type.GetCustomAttribute<SingletonAttribute>() != null).ToArray();
containerBuilder.RegisterTypes(typesAsSingleton).SingleInstance().AsImplementedInterfaces();
}
private static void RegisterAllClassesWithoutAttribute(ContainerBuilder containerBuilder, List<Type> allTypes)
{
var types = allTypes.Where(type => !typeof(IModule).IsAssignableFrom(type) &&
type.GetCustomAttribute<DoNotRegisterInIocAttribute>() == null &&
type.GetCustomAttribute<SingletonAttribute>() == null &&
type.GetCustomAttribute<RealImplementationAsInstancePerLifetimeScopeAttribute>() == null &&
type.GetCustomAttribute<TestImplementationAsInstancePerLifetimeScopeAttribute>() == null &&
type.GetCustomAttribute<InstancePerLifetimeScopeAttribute>() == null &&
type.GetCustomAttribute<RegisterAsGenericInterfaceAttribute>() == null).ToArray();
containerBuilder.RegisterTypes(types).AsSelf().AsImplementedInterfaces();
}
Where the assemblies that are delivered to the RegisterAssemblies method could be fetched like this:
private List<Assembly> GetAssemblies()
{
var assemblies = AssemblyResolveHelper.LoadAssemblies(AppDomain.CurrentDomain.BaseDirectory,
new Regex(#"Usd.EA.*\.dll"),
SearchOption.TopDirectoryOnly);
assemblies.AddRange(AssemblyResolveHelper.LoadAssemblies(AppDomain.CurrentDomain.BaseDirectory,
new Regex(#"Usd.Utilities.*\.dll"),
SearchOption.TopDirectoryOnly));
assemblies.Add(GetType().Assembly);
return assemblies.Distinct().ToList();
}
The attributes
The attributes used in RegisterAllClassesWithoutAttribute are custom attributes that we manually assign to individual classes
using System;
[AttributeUsage(AttributeTargets.Class)]
public class DoNotRegisterInIocAttribute : Attribute
{
}
Used like this
[ExcludeFromCodeCoverage]
[DoNotRegisterInIoc]
public sealed class TestClass : ITestClass
When I'm not overwriting Autofacs MaxResolveDepth I get the following error
Failed An error occurred when trying to create a controller of type
'BogfoerController'. Make sure that the controller has a parameterless
public constructor. An exception was thrown while activating λ:Usd.EA
.Bogfoering.WebApi.Controllers.BogfoerController ->
Usd.EA.Bogfoering.WebApi.Controllers.BogfoerController -> ......
Probable circular dependency between factory-scoped components. Chain
includes 'Activator = DomainWrapper (DelegateActivator), Services =
SomeService, Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime,
Sharing = None, Ownership = ExternallyOwned'
Short answer:
This is casused by the Autofac behaviour when resolving services from a child ILifetimeScope created by calling BeginLifetimeScope(Action<ContainerBuilder> configurationAction).
Long answer:
I have set up a simple test to prove above statement. I have generated a 51 test classes referencing themselves.
public class Test0
{
public Test0() { }
}
public class Test1
{
public Test1(Test0 test) { }
}
(...)
public class Test50
{
public Test50(Test49 test) { }
}
Registered them in a newly created container and tried to resolve the "Test50" class directly from the container. As you already found out. There is hard coded limit of 50 dependencies depth in the Autofac library, which you can see it on the GitHub page. After reaching this limit the DependencyResolutionException is thrown stating "Probable circular dependency between factory-scoped components." And this is exactly what happened in my first test.
Now you have asked, why are you seeing multiple registrations of the same dependencies. So here comes the fun part. When you are trying to resolve your instance, you are probably gonna use the BeginLifetimeScope function to create new ILifetimeScope. This would be still ok, unless you are going to add some new registrations to the child scope using one of the overloads. See example below:
using (var scope = container.BeginLifetimeScope(b => { }))
{
var test = scope.Resolve<Test49>();
}
I'm resolving only 50 dependencies (which have previously worked), but now, it yields an exception:
As you can see, this is exactly the same behaviour as you previously described. Each dependency is now showed 2 times. On that image, you can also see that the dependency graph has only reached the Test25 class. This has effectively reduced the previous max depth by a half (whole 25 dependencies!). We can test this by successuflly resolving Test24 class, but exception is thrown when trying to resolve the Test25. This goes even funnier, how do you think, what happens if we add another scope?
using (var scope1 = container.BeginLifetimeScope(b => { }))
{
using (var scope2 = scope1.BeginLifetimeScope(b => { }))
{
var test2 = scope2.Resolve<Test49>();
}
}
You probably guessed it, now you can only resolve the dependencies of depth 50 / 3 = ~16.
Conclusion: Creating nested scopes is limiting the actual available maximum depth of the dependencies graph N times, where the N is the depth of the scope. To be honest, scopes created without extending the container builder do not affect this number. In my opinion, this is a huge absurd, to have hard-coded magic number, which is nowhere in the documentation, cannot be easily configured, doesn't even represent the actual maximum depth and when overflowed, it throws misleading exception stating that you have circular dependencies in the graph somewhere.
Solutions: As a resolution to this issue you could not use this overload of this function. This could be not possible due to architecture limitations, or even the 3rd party framework which could be using the Autofac as DI container.
Another solution that you have already mentioned is overwriting the MaxResolveDepth using dirty reflection.
string circularDependencyDetectorTypeName = typeof(IContainer).AssemblyQualifiedName.Replace(typeof(IContainer).FullName, "Autofac.Core.Resolving.CircularDependencyDetector");
Type circularDependencyDetectorType = Type.GetType(circularDependencyDetectorTypeName);
FieldInfo maxResolveDepthField = circularDependencyDetectorType.GetField("MaxResolveDepth", BindingFlags.Static | BindingFlags.NonPublic);
maxResolveDepthField.SetValue(null, 500);
On the Autofac's GitHub you can also read that they are already planning to change the behaviour of the CircularDependencyDetector, so it could handle the infinite depth of dependencies, but those plans were mentioned in 2018 and they even couldn't change that exception message by this date.
How Can I inject IEnumerable<Func<T>> using Simple Injector?
Just to add some context, I'm trying to create all EventHandlers that knows how to handle one specific Event. So here is my Container registration:
container.RegisterCollection(typeof(IHandleDomainEvent<>),
AppDomain.CurrentDomain.GetAssemblies());
And here Are two classes that implement the IHandleEvent<T> interface for the same Event:
public class Reservation : IHandleDomainEvent<OrderConfirmed>{}
public class Order: IHandleDomainEvent<OrderConfirmed>{}
So when I call the Simple Injector:
var handlers = _container.GetAllInstances<Func<IHandleDomainEvent<OrderConfirmed>>>();
I would like to Receive IEnumerable<Func<IHandleDomainEvent<OrderConfirmed>>>
Just to clarify, I know that if I call:
var handlers = _container.GetAllInstances<IHandleDomainEvent<OrderConfirmed>>();
I would get an IEnumerable<IHandleDomainEvent<OrderConfirmed>>.
For interfaces that have only one implementation, registering using:
container.Register(typeof(IHandleDomainEvent<>),
AppDomain.CurrentDomain.GetAssemblies(), Lifestyle.Scoped);
And adding the following ResolveUnregisteredType to the end of the registration:
container.ResolveUnregisteredType += (o, args) => ResolveFuncOfT(o, args, container);
// Function
private static void ResolveFuncOfT(object s, UnregisteredTypeEventArgs e, Container container)
{
var type = e.UnregisteredServiceType;
if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Func<>)) return;
Type serviceType = type.GetGenericArguments().First();
InstanceProducer producer = container.GetRegistration(serviceType, true);
Type funcType = typeof(Func<>).MakeGenericType(serviceType);
var factoryDelegate = Expression.Lambda(funcType, producer.BuildExpression()).Compile();
e.Register(Expression.Constant(factoryDelegate));
}
Will allow calling:
var handler = _container.GetInstance<Func<IHandleDomainEvent<TEvent>>>();
This is the beauty of Simple Injector: You'll never have to resolve an IEnumerable<Func<T>> because any IEnumerable<T> resolved by Simple Injector already functions as a stream.
This means that when you resolve an IEnumerable<T>, none of the elements of the stream will be resolved. They get only resolved when iterating the enumerable, and are resolved one-by-one.
When iterating the stream, elements will be resolved according to their lifestyle. This means that when the elements in the collection are Transient iterating the stream twice will cause the creation of new transient instances.
Example:
// Only resolves the enumerable, not the contained handlers.
// This enumerable itself is a singleton, you can reference it forever.
var collection = container.GetInstances<IEventHandler<OrderConfirmed>>();
// Calls back into the container to get the first element, but nothing more
var first = collection.First();
// Since the stream that Simple Injector returns is a IList<T>, getting the last
// element is an O(1) operation, meaning that only the last element is resolved;
// not the complete collection.
var last = collection.Last();
// Calling .ToArray(), however, will obviously resolve all registrations that are
// part of the collection.
var all = collection.ToArray();
// Iterating a stream will always call back into the container, which ensures
// that the stream adheres to the elements lifestyles. Transients will be
// created on each iteration, while singletons will only be created once.
container.Register<Apple>(Lifestyle.Transient);
container.Register<Banana>(Lifestyle.Singleton);
container.RegisterCollection<IFruit>(typeof(Apple), typeof(Banana));
var fruits = container.GetAllInstances<IFruit>();
Assert.AreNotSame(fruits.First(), fruits.First());
Assert.AreSame(fruits.Last(), fruits.Last());
// Even other collection types such as IReadOnlyCollection<T> behave as streams
var col = container.GetInstance<IReadOnlyCollection<IEventHandler<OrderConfirmed>>();
// This gives you the possibility to get a particular item by its index.
var indexedItem = col[3];
You can find more information on working with collections in Simple Injector here:
Simple Injector Documentation - Using - Collection types
Simple Injector Documentation - Advanced - Auto-Registration
Simple Injector Documentation - Design Decisions -
The API clearly differentiates the registration of collections
Simple Injector Documentation - Collections and lifetime management
is there a way I can keep track of how much time is taken to resolve an instance via Simple Injector and Constructor's IoC?
I mean something at trace level
Thanks
Resolving instances in Simple Injector is blazingly fast, and should never be a problem, unless your constructors do too much.
Nonetheless, adding tracing can be done using the following extension method (works for Simple Injector v2.x and beyond):
public static void ApplyInterceptor(
this ContainerOptions options, Func<Func<object>, object> interceptor)
{
options.Container.ExpressionBuilding += (s, e) =>
{
var factory = Expression.Lambda(typeof(Func<object>), e.Expression).Compile();
e.Expression = Expression.Convert(
Expression.Invoke(
Expression.Constant(interceptor),
Expression.Constant(factory)),
e.Expression.Type);
};
}
This ApplyInterceptor extension method can be called to intercept the creation of all types produced by the container, for instance to add this monitoring behavior:
container.Options.ApplyInterceptor(producer =>
{
var watch = Stopwatch.StartNew();
object instance = null;
try
{
instance = producer();
return instance;
}
finally
{
watch.Stop();
if (watch.ElapsedMilliseconds > 50)
{
string name = instance.GetType().ToFriendlyName();
Console.WriteLine(
$"WARNING: {name} took {watch.ElapsedMilliseconds} ms. to resolve.");
}
}
})
WARNING: This interceptor gets applied to all registrations in Simple Injector and could severely impact runtime performance, so make sure you only add this during debug builds or when the debugger is attached, to make sure you don't impact runtime performance.
Question
I have a full name of a type, for example "StrategyA",and I want to get new Strategy(value) that assigned to its interface "IStrategy", how to get it?
What I have tries
I have tried this:
IStrategy strategy;
if (strategyName == "StrategyA")
{
strategy = new StrategyA(value);
}
else if(strategyName == "StrategyB")
{
strategy = new StrategyB(date);
}
...
but when I create a new strategy , I have to add another branch to the code, and I think it is a bad code style.
Is there any better way to solve this problem?
Here are a few options, in no particular order:
(A) If your strategy name is a full CLR type name (or a full type name may be determined by convention), and each strategy has common constructor parameters, you can find the type using reflection and create an instance.
Type strategyType = Type.GetType(strategyName)
IStrategy instance = (IStrategy)Activator.CreateInstance(strategyType, paramArray);
Be aware that you should not use this approach if you cannot trust the strategyName input, otherwise you may be creating instances of unexpected types.
(B) You could create a mapping from strategy name to factory delegate using a dictionary. This approach may be useful if various constructors are used, or if factories come and go.
Dictionary<string, Func<IStrategy>> factories = new Dictionary<string, Func<IStrategy>>();
//register various factories
factories.Add("StrategyA", () => new StrategyA(value));
factories.Add("StrategyB", () => new StrategyB(date));
Func<IStrategy> factory;
if(factories.TryGetValue(strategyName, out factory))
{
IStrategy instance = factory();
}
(C) You could rely on any number of IoC containers such as Autofac, and ask for the corresponding IStrategy implementation.
(D) Another related pattern that is sometimes used relies on implementations of IStrategy to check applicability and returning the first one which is applicable. This can be useful when the caller doesn't know which strategy to pick.
List<IStrategy> strategies = new List<IStrategy>();
//register strategies (highest priority first)
strategies.Add(new StrategyA(value));
strategies.Add(new StrategyB(value));
//alternatively, you might resolve IEnumerable<IStrategy> from your IoC container
foreach(IStrategy strategy in strategies)
{
if(strategy.IsApplicable(someInput)) return strategy;
}
You would do
strategy = (IStrategy)Activator.CreateInstance(Type.GetType(strategyName));
Why don't you use Reflection.
Some thing like :
Type type = Type.GetType(strategyName, true);
// create an instance of that type
object instance = Activator.CreateInstance(type);
There are various ways of doing it.
1) Simple switch case, if your conditions are less
2) IOC containers. http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx or Unity container provided by microsoft http://msdn.microsoft.com/en-us/library/ff649614.aspx
3) Activator.CreateInstance(type);
4) You can customize your own using factory design pattern
Try Constructor Injection (part of Dependency Injection)
E.g.
public class MyStrategy
{
IStrategy strategy;
public MyStrategy(IStrategy concreteImplementation)
{
this.strategy = concreteImplementation;
}
}
In this way you can pass any object that implements IStrategy interface. So you could eliminate the If...else conditions in your constructor. The usage of this is as follows.
StrategyA strategyA = new StrategyA(value);
MyStrategy myStrategyA = new MyStrategy(strategyA);
StrategyB strategyB = new StrategyB(date);
MyStrategy myStrategyB = new MyStrategy(strategyB);
StrategyC strategyC = new StrategyC(someValue);
MyStrategy myStrategyC = new MyStrategy(strategyC);
Hope this helped!
Messenger.Default.Register<OpenWindowMessage>(this, message =>
{
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>();
adventurerWindowVM.Adv = message.Argument;
var adventurerWindow = new AdventurerView()
{
DataContext = adventurerWindowVM
};
adventurerWindow.Show();
});
This code is fairly simple; it just opens a new window and sets the DataContext of the new window. The problem I'm having is that if I execute this twice, the content of the first instance will be overwritten and be set to that of the second since adventurerWindowVM is the DataContext of both windows and it is overwritten each time this code is called. I'm looking for a way to prevent this; I'd like to be able to open multiple windows using this message and have each of them be unique, but thus far I haven't figured out a way to do so. Any advice would be greatly appreciated. I apologize for the vague title; I was unsure of what to name this question. (Also, I know that this isn't a method. What would this block of code be called?)
Update: I'm using MVVM Light and my code is based off of an example somebody provided for me in this answer: https://stackoverflow.com/a/16994523/1667020
Here is some code from my ViewModelLocator.cs
public ViewModelLocator()
{
_main = new MainViewModel();
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<GameViewModel>();
SimpleIoc.Default.Register<AdventurerViewModel>();
}
Having given the other answer, I guess I can say the IoC container used here is just SimpleIoC from MvvmLight and to get a new instance of the VM on every GetInstance(...) all you need to do is pass in a unique key every time when trying to resolve an instance of the VM.
So you can switch
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>();
to
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>(System.Guid.NewGuid().ToString());
However as mentioned by the author of MVVMLight Here these VM's will get cached and we need to get rid of them when no longer needed. In your case probably when the Window is closed.
Thus I'd have that entire lambda something like:
Messenger.Default.Register<OpenWindowMessage>(this, message =>
{
var uniqueKey = System.Guid.NewGuid().ToString();
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>(uniqueKey);
adventurerWindowVM.Adv = message.Argument;
var adventurerWindow = new AdventurerView()
{
DataContext = adventurerWindowVM
};
adventurerWindow.Closed += (sender, args) => SimpleIoc.Default.Unregister(uniqueKey);
adventurerWindow.Show();
});
Note:
While this is somewhat longer 3 lines compared to just creating a new VM yourself with (new AdventurerViewModel()) I still favor this because if you use an IoC container to manage LifeTime of your VM's, then have it manage them completely. Don't really like mix-n-match when not needed. Rather keep the IoC Container doing what it's meant to do.
If you need more control over VM injection and Life-time management look at more sophisticated Ioc controllers such as Unity. SimpleIoC was just meant to be a simple get your feet "wet" in IoC kind of container and it does a very good job in that regard.
I think you are trying to use the same instance of your ViewModel with multiple views. So the views will obviously overwrite each others viewmodel contents.
What if you do this;
Messenger.Default.Register<OpenWindowMessage>(this, message =>
{
var adventurerWindowVM = new AdventurerViewModel();
adventurerWindowVM.Adv = message.Argument;
var adventurerWindow = new AdventurerView()
{
DataContext = adventurerWindowVM
};
adventurerWindow.Show();
});
It's a method call, passing in an anonymous method using a lambda expression.
It looks like you are getting your AdventurerViewModel from some sort of IoC container. How is the IoC container configured? In particular, what is the scope of the objects it gives you back? If you have the IoC configured to create objects in singleton scope, for example, then you will always get back a reference to the same object each time. You may need to configure the scope of the object in your IoC container so that it gives you back a fresh copy every time.
How you do that will depend on your IoC container. Without knowing which IoC framework you are using or seeing its configuration, it's impossible to make any further comment.
My advice would be to create an extension method for SimpleIOC. Something like this:
public static T CreateInstance<T>(this SimpleIoc simpleIoc)
{
// TODO implement
}
You already know the method to get the same instance; extended SimpleIoc with a method to create a new instance:
T instance = SimpleIoc.Default.GetInstance<T>();
T createdInstance = SimpleIoc.Defalt.CreateInstance<T>();
If you are not familiar with extension methods, see Extension Methods Demystified
The implementation:
Of type T, get the constructor.
If there is more than one constructor: either throw exception, or decide which constructor to use. Simple method: use the same method that is used in SimpleIoc.GetInstance, with an attribute. More elaborate method: try to find out if you can find registered elements that match one of the constructors. This is not explained here.
Once you've found the constructor that you need, get its parameters.
Ask SimpleIoc for instances of this parameter, or if they should be new also, ask SimpleIoc to create new instances.
CreateInstance
.
public static T CreateInstance<T>(this SimpleIoc ioc)
{
return (T)ioc.CreateInstance(typeof(T));
}
public static object CreateInstance(this SimpleIoc ioc, Type type)
{
ConstructorInfo constructor = ioc.GetConstructor(type);
IEnumerable<object> constructorParameterValues = ioc.GetParameters(constructor);
constructor.Invoke(constructorParameterValues.ToArray());
}
To decide which constructor to use:
private static ConstructorInfo GetConstructor(this SimpleIoc ioc, Type type)
{
ConstructorInfo[] constructors = type.GetConstructors();
ConstructorInfo constructorToUse;
if (constructorInfo.Length > 1)
{
// Decide which constructor to use; not explained here
// use Attribute like SimpleIoc.GetInstance?
// other method: use SimpleIoc.IsRegistered to check which Parameters
// are registered: use ConstructorInfo.GetParameters()
constructorToUse =
}
else
constructorToUse = constructoInfo[0];
return constructorToUse;
}
To get the values of the parameters in the constructor, we need to decide whether we want existing values from Ioc, or create new values:
public static IEnumerable<object> GetParameterValues(this simpleIoc ioc,
ConstructorInfo constructor)
{
IEnumerable<Type> parameterTypes = contructor.GetParameters()
.Select(parameter => parameter.ParameterType);
return ioc.GetInstances(parameterTypes);
}
public static IEnumerable<object> GetInstances(this SimpleIoc ioc,
IEnumerable<Type> types)
{
// TODO: decide if we want an existing instance from ioc,
// or a new one
// use existing instance:
return types.Select(type => ioc.GetInstance(type));
// or create a new instance:
return types.Select(type => ioc.CreateInstance(type));
}
This seems like a lot of code, but most of it is comment and most methods are one liners.