Using Prism 7.1, I can register two named dependencies:
containerRegistry.Register<ICustomersService, CustomersFakeService>("One");
containerRegistry.Register<ICustomersService, CustomersFakeService>("Two");
Now - how can I use any of them in ViewModel constructor?
public CustomersViewModel(ICustomersService customersService, EventAggregator eventAggregator)
throws an exception:
Resolution of the dependency failed, type =
'WPFPrismDI.ViewModels.CustomersViewModel', name = '(none)'. Exception
occurred while: while resolving. Exception is:
InvalidOperationException - The current type,
WPFPrismDI.Services.ICustomersService, is an interface and cannot be
constructed. Are you missing a type mapping?
----------------------------------------------- At the time of the exception, the container was: Resolving
WPFPrismDI.ViewModels.CustomersViewModel,(none) Resolving parameter
'customersService' of constructor
WPFPrismDI.ViewModels.CustomersViewModel(WPFPrismDI.Services.ICustomersService
customersService, Prism.Events.EventAggregator eventAggregator)
Resolving WPFPrismDI.Services.ICustomersService,(none)
My implementation of the service:
public interface ICustomersService
{
ObservableCollection<CustomerModel> CustomerGetAll();
}
public class CustomersDBService : ICustomersService
{
public ObservableCollection<CustomerModel> CustomerGetAll()
{
ObservableCollection<CustomerModel> returnValue = new ObservableCollection<CustomerModel>();
returnValue.Add(new CustomerModel() { NameFirst = "DB", });
return returnValue;
}
}
Now - how can I use any of them in CustomersViewModel constructor?
By injecting all of them:
public CustomersViewModel(ICustomersService[] customersServices, IEventAggregator eventAggregator)
Related
This question already has answers here:
Prism 6 with Unity - resolving view models for views without naming convention
(2 answers)
Closed 6 years ago.
I use prism 6.1. I set up the Unity configuration in the method ConfigureContainer of Bootstrapper class. But, when the Prism framework try to call the View Model, it can't create this, and throw the exception 'No parameterless constructor defined for this object.'.
Bootstrapper.cs
public class Bootstrapper: UnityBootstrapper
{
...
protected override void ConfigureContainer()
{
base.ConfigureContainer();
this.Container.RegisterType<IMyService, MyService>(new ContainerControlledLifetimeManager());
this.Container.RegisterType<MyFormViewModel>(new ContainerControlledLifetimeManager());
}
...
}
MyFormModule.cs
public class MyFormModule : IModule
{
private readonly IRegionViewRegistry regionViewRegistry;
public SkypeActionModule(IRegionViewRegistry registry)
{
this.regionViewRegistry = registry;
}
public void Initialize()
{
regionViewRegistry.RegisterViewWithRegion("MainRegion", typeof(Views.MyFormView));
}
}
MyFormViewModel.cs
public class MyFormViewModel : BindableBase
{
private readonly IMyService myService;
public SkypeActionViewModel(IMyService myService)
{
this.myService = myService;
}
...
}
In this line throw the exception:
regionViewRegistry.RegisterViewWithRegion("MainRegion", typeof(Views.MyFormView));
In the prism documentation explains how to configurate unity, but this is in the Module class (in my case is MyFormModule). I don't understand that because in this way, I need to configurate that in each module, and I haven't the object this.container.RegisterType in my module class.
In others links, I found some configuration similar to "MEF" configuration, where the "DI" configuration are in the ConfigureContainer method. But it doesn't work for my, or something missing in my configuration.
Edit
I include the container in my module class. But I have the same problem. I suppose that is normal, because the problem is when Prism create the view model class MyFormViewModel.
public class MyFormModule : IModule
{
private readonly IRegionViewRegistry regionViewRegistry;
private readonly IUnityContainer container;
public MyFormModule(IRegionViewRegistry registry, IUnityContainer container)
{
this.regionViewRegistry = registry;
this.container = container;
}
public void Initialize()
{
this.container.RegisterType<IMyService, MyService>(new ContainerControlledLifetimeManager());
this.container.RegisterType<MyFormViewModel>();
this.container.RegisterType<MyFormView>();
regionViewRegistry.RegisterViewWithRegion("MainRegion", typeof(MyFormView));
}
}
Edit
Solution: I found the solution in this question on stackoverflow
Create the method BindViewModelToView on Bootstrap class:
public void BindViewModelToView<TViewModel, TView>()
{
ViewModelLocationProvider.Register(typeof(TView).ToString(), () => Container.Resolve<TViewModel>());
}
and then, in the method ConfigureViewModelLocator in Bootstrap class call all view models it to bind with views:
protected override void ConfigureViewModelLocator()
{
BindViewModelToView<ViewAVM, ViewA>();
BindViewModelToView<ViewAVM, ViewB>();
}
How do you tell prism to create the view model? Are you using ViewModelLocator.AutoWireViewModel="True"?
If so, you want to do something like
ViewModelLocationProvider.SetDefaultViewModelFactory( type =>
{
return Container.Resolve(type);
});
in the bootstrapper to make sure that your container is used for resolving the view model...
I have lots of repositories like this:
public class PersonRepository : IPersonRepository
{
private readonly IUnitOfWork _unitOfWork;
public PersonRepository(IUnitOfWork instance)
{
_unitOfWork = instance;
}
//Remove, Get methods...
public void Add(Person p)
{
_unitOfWork.Context.People.Add(p);
}
}
and Unit of work class like this:
public class UnitOfWork : IUnitOfWork, IDisposable
{
public UnitOfWork(){ }
private readonly HezarehContext _context = new HezarehContext();
public HezarehContext Context
{
get
{
return _context;
}
}
public int Save()
{
return _context.SaveChanges();
}
public void Initialize()
{
Context.Database.Initialize(false);
}
#region IDisposable Members
public void Dispose()
{
_context.Dispose();
}
#endregion
}
Now i want each time my ViewModels gets resolved, a new IUnitOfWork instantiated. Most of my ViewModels are like this:
public class PeopleMainViewModel : NotificationObject
{
// both of repositories must have same instance of IUnitOfWork
private readonly IPersonRepository _personRepository = ServiceLocator.Current.GetService<IPersonRepository>();
private readonly ICategoryRepository _categoryRepository = ServiceLocator.Current.GetService<ICategoryRepository>();
public PeopleMainViewModel()
{
InitializeView();
}
// add, edit, remove commands ...
}
ViewModels always gets resolved using Unity Container like this:
Container.RegisterType<IPersonRepository, PersonRepository>();
// resolve in InjectionProperty...
Container.RegisterType<Object, PeopleMainView>("PeopleMainView", new InjectionProperty(PeopleMainView.DataContextProperty.Name, Container.Resolve<PeopleMainViewModel>();
And my question is, How and Where i Register my ViewModels and IUnitOfWork to have IUnitOfWork instance for each of them?
If I understand your question, just register your IUnitOfWork the same way (and same place) you register the repository in your above example. You don't need to register your ViewModels based on your current design since you aren't using an Interface.
Container.RegisterType<IUnitOfWork, UnitOfWork>();
And continue to have your repositories accept the IUnitOfWork in the constructor. This will allow Unity to use constructor injection to provide a new instance of IUnitOfWork each time it resolves a repository. By default, you'll get a new instance of the IUnitOfWork each time. If you'd like to have a singleton IUnitOfWork, you would have to say so when you register the IUnitOfWork like this:
Container.RegisterType<IUnitOfWork, UnitOfWork>(new ContainerControlledLifetimeManager());
If you want to read up on Lifetime Managers, you can do so here.
I would also recommend changing your ViewModels to take the repositories in as Constructor Parameters, like this if you are going to Resolve them (so Unity will do the work without you referencing the ServiceLocator directly)
public PeopleMainViewModel(IPersonRepository personRepo, ICategoryRepository categoryRepo)
{
...
}
Update:
There is another solution here in unity.codeplex discussions.
I finally found a solution.
There is a feature in Unity container that let you pass parameters while resolving a Type. by changing constructor of ViewModels to this:
public class PeopleMainViewModel : NotificationObject
{
private readonly IPersonRepository _personRepository = null;
private readonly ICategoryRepository _categoryRepository = null;
public PeopleMainViewModel(IUnityContainer container, IUnitOfWork unitOfWork)
{
// now both of repositories have same instance of IUnitOfWork
_personRepository = container.Resolve<IPersonRepository>(new ParameterOverride("unitOfWork", unitOfWork));
_categoryRepository = container.Resolve<ICategoryRepository>(new ParameterOverride("unitOfWork", unitOfWork));
InitializeView();
}
// add, edit, remove commands ...
}
problem solved. now _personReposiotry and _categoryRepository have reference to same instance of unitOfWork.
This question might look naive, but I couldn't understand this code in the ViewModelLocator.cs file:
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
}
else
{
SimpleIoc.Default.Register<IDataService, DataService>();
}
SimpleIoc.Default.Register<MainViewModel>();
}
I see that we use a DataService to get data (from WCF service for example) and assigning it to the MainViewModel. But what if I'm registering more than one ViewModel? like this:
static ViewModelLocator()
{
....
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<Page2ViewModel>();
}
and let's say I have another DataService (DataService2 for example), but this one I'll use with the Page2ViewModel. how can I do that?
Also, if someone can help me (or even give me a link to read) about the above code. I have no clue what it means.
You are not assigning any IDataService to the MainViewModel here. You are registering a type mapping, so your container will be aware that it should return a DataService whenever an IDataService required.
This is related to dependency injection http://en.wikipedia.org/wiki/Dependency_injection
The DI container auto-wires the dependencies, so when you need a specific type, you can call
ServiceLocator.Current.GetInstance<IDataService>()
or
ServiceLocator.Current.GetInstance<MainViewModel>()
etc. If it can build it (so you registered your types), it will resolve the full dependency graph for you.
For example, if your MainViewModel has a constructor dependency on IDataService, and you are not in design mode, a DataService will be injected to the MainViewModel constructor. Don't be afraid from the buzzword injected, it is just a call to the MainViewModel constructor with the appropriate parameters :).
So, MainViewModel will not interference with Page2ViewModel here.
I made a simple sample for you to demonstrate what happens (I used Unity, http://unity.codeplex.com/ , but the syntax is almost the same):
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IService, Service1>();
container.RegisterType<IService, Service2>("MySpecificService");
container.RegisterType<IRepository, Repository>();
ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));
var viewModel = ServiceLocator.Current.GetInstance<MainViewModel>();
viewModel.Foo();
}
}
interface IService
{
}
interface IRepository
{
}
class Service1 : IService
{
public Service1(IRepository repository)
{
Console.WriteLine("Service1 created");
}
}
class Service2 : IService
{
public Service2()
{
Console.WriteLine("Service2 created");
}
}
class Repository : IRepository
{
public Repository()
{
Console.WriteLine("Repository created");
}
}
class MainViewModel
{
public MainViewModel(IService service)
{
Console.WriteLine("MainViewModel created");
}
public void Foo()
{
var specificService = ServiceLocator.Current.GetInstance<IService>("MySpecificService");
}
}
the output is:
Repository created
Service1 created
MainViewModel created
Service2 created
Because you need a MainViewModel (maybe in SimpleIoC you need to register MainViewModel too, in Unity, it can resolve concrete classes without mapping), the container trying to create one, but it realizes that MainViewModel needs an IService, and it finds the default one from the mapping, which is Service1, but it realizes that Service1 needs an IRepository, and it finds the default one, so it can pass a Repository to the Service1 constructor, then the Service1 instance to the MainViewModel constructor. All the dependencies resolved.
The Foo call is an example how you can register more than one type to the same interface. Dependency injection is a much more bigger topic, but auto-wiring is an important part of it.
I am using PRISM 4 and got my head around almost all features, however as soon as I would like to inject my DomainContext class (RIA) into my view model, the hell breaks loose. :) It would be great if an experienced Unity/Prism developer could give me an advice how to proceed.
Within my bootstrapper, I am registering the required class in Unity Container like this:
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType<SCMDomainContext>();
}
Within the NavigationModule, I have the following in the ctor to register the NavigationView with a particular region.
public NavigationModule(IUnityContainer container, IRegionManager regionManager)
{
_container = container;
_regionManager = regionManager;
_regionManager.RegisterViewWithRegion(Constants.NavRegion, () => _container.Resolve<NavigationView>());
}
The View takes the View Model as dependency:
public NavigationView(NavigationViewModel viewModel)
{
InitializeComponent();
Loaded += (s, e) =>
{
DataContext = viewModel;
};
}
The ViewModel has the following:
public NavigationViewModel(SCMDomainContext context)
{
_context = context;
ConstructCommon();
}
As soon as I comment this ctor out and put a en empty ctor, it is all fine, for some reason I can't resolve the SCMDomainContext class. Which is the one you add to have the Domain Context created for you provided by Ria Services.
Since I am using Silverlight, I can't see the stack trace to follow the exception, all I get is this message on a page. What am I missing please?
Microsoft JScript runtime error: Unhandled Error in Silverlight Application An exception occurred while initializing module 'NavigationModule'.
- The exception message was: Activation error occured while trying to get instance of type NavigationModule, key ''
Check the InnerException property of the exception for more information. If the exception occurred
while creating an object in a DI container, you can exception.GetRootException() to help locate the
root cause of the problem. at Microsoft.Practices.Prism.Modularity.ModuleInitializer.HandleModuleInitializationError(ModuleInfo moduleInfo, String assemblyName, Exception exception)
at Microsoft.Practices.Prism.Modularity.ModuleInitializer.Initialize(ModuleInfo moduleInfo)
at Microsoft.Practices.Prism.Modularity.ModuleManager.LoadModulesThatAreReadyForLoad()
at Microsoft.Practices.Prism.Modularity.ModuleManager.IModuleTypeLoader_LoadModuleCompleted(Object sender, LoadModuleCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.XapModuleTypeLoader.RaiseLoadModuleCompleted(LoadModuleCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.XapModuleTypeLoader.HandleModuleDownloaded(DownloadCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.XapModuleTypeLoader.IFileDownloader_DownloadCompleted(Object sender, DownloadCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.FileDownloader.WebClient_OpenReadCompleted(Object sender, OpenReadCompletedEventArgs e)
at System.Net.WebClient.OnOpenReadCompleted(OpenReadCompletedEventArgs e)
at System.Net.WebClient.OpenReadOperationCompleted(Object arg)
Your help on this is highly appreciated,
Kave
I can't see much wrong here. But having said that, I'm using the Initialize method from the interface in the following way to register types and views for regions:
#region properties
[Dependency]
public IUnityContainer Container { get; set; }
[Dependency]
public IRegionManager RegionManager { get; set; }
#endregion
public virtual void Initialize()
{
this.Container.RegisterType<NavigationViewModel>(new ContainerControlledLifetimeManager());
this.Container.RegisterType<NavigationView>(new ContainerControlledLifetimeManager());
this.RegionManager.RegisterViewWithRegion(Constants.NavRegion, () => this.Container.Resolve<NavigationView>());
}
Not sure whether it makes a difference if you don't explicitly register the ViewModel and the View type. Personally I prefer to have control over the way how a type gets resolved by the container.
In fact its best to create a layer for the DomainContext like this. Then its easily resolvable by an IoC:
public class ContactModuleService : IContactModuleService
{
readonly SCMDomainContext _context = new SCMDomainContext();
#region Implementation of IContactModuleService
public EntitySet<Contact> Contacts
{
get { return _context.Contacts; }
}
public EntityQuery<Contact> GetContactsQuery()
{
return _context.GetContactsQuery();
}
public SubmitOperation SubmitChanges(Action<SubmitOperation> callback, object userState)
{
return _context.SubmitChanges(callback, userState);
}
public SubmitOperation SubmitChanges()
{
return _context.SubmitChanges();
}
public LoadOperation<TEntity> Load<TEntity>(EntityQuery<TEntity> query, Action<LoadOperation<TEntity>> callback, object userState) where TEntity : Entity
{
return _context.Load(query, callback, userState);
}
public LoadOperation<TEntity> Load<TEntity>(EntityQuery<TEntity> query) where TEntity : Entity
{
return _context.Load(query);
}
#endregion
}
I have a WPF windows application that uses the ms ribbon control for the menu. In my infrastructure project I want to have a shared service that will be referenced in all modules. Each module will then use that service to define what menu items should be displayed for the module.
I read this Prism+MEF: delayed a service export from prism-module but can't get my other modules to recognize the service.
The service
namespace Infrastructure
{
[ModuleExport("InfModule", typeof(InfModule), InitializationMode = InitializationMode.WhenAvailable)]
[PartCreationPolicy(CreationPolicy.Shared)]
public class InfModule : IModule
{
[Export(typeof(IMenuService))]
public IMenuService MenuService { get; private set; }
public void Initialize()
{
MenuService = new MenuService();
MenuService.AddItem("test");
}
}
}
The module
namespace Classic
{
[ModuleExport("Classic", typeof(Classic), InitializationMode = InitializationMode.WhenAvailable)]
[ModuleDependency("InfModule")]
public class Classic : IModule
{
private IRegionManager _regionManager;
[Import(typeof(IMenuService))]
private IMenuService menuService { get; set; }
[ImportingConstructor]
public Classic(IRegionManager regionManager)
{
this._regionManager = regionManager;
// This shows as true
Debug.WriteLine(menuService == null);
}
public void Initialize()
{
_regionManager.RegisterViewWithRegion("RibbonRegion", typeof(Views.RibbonTabMenu));
// This shows as true
Debug.WriteLine(menuService == null);
}
}
}
I would have expected one of the debug lines to output as false since its imported. Any idea's what I'm missing?
Property imports will never be set while running the constructor, since you can't set properties on an object until it's constructed.
The other problem is that in InfModule, you are setting the exported value too late. MEF only looks at the value for an export once, after that it caches the value and doesn't call the getter again. In this case it is getting the export before Initialize() is called. The logic to set the export needs to either run from the constructor or from code in the property getter.