0
votes

I'm using Prism 7.1 for WPF application. I tried to use built-in IOC(Unity) but I don't know how I can resolve new instance at run time maybe from method or from containerProvider. But it seems IContainerProvider is not available to be injected in my view model. Do I have any option?

I want to do this to reload my database context. I was told that creating new context is the easiest among others.

    public class ProjectViewModel : BindableBase
    {
        private UnitOfWork unitOfWork;
        private IContainerProvider containerProvider;
        private IEventAggregator eventAggregator;
        #region Constructor
        public ProjectViewModel(UnitOfWork unitOfWork, IContainerProvider cp, IEventAggregator ea)
        {
            this.unitOfWork = unitOfWork;
            containerProvider = cp;
            eventAggregator = ea;
            eventAggregator.GetEvent<SendReloadDataEvents>().Subscribe(Reload);
            Reload();
        }
        #endregion

        private void Reload()
        {
            this.unitOfWork = containerProvider.Resolve<UnitOfWork>();
            Projects = new ObservableCollection<Projects>(unitOfWork.ProjectRepo.GetAll());
            Customers = new ObservableCollection<Customers>(unitOfWork.CustomerRepo.Find(x => x.Projects.Count > 0));
            SelectedProjectType = null;
        }
//Other logic continues
}
1

1 Answers

1
votes

Injecting the container is an anti-pattern, so we'll try to avoid that and inject a factory instead. In fact, IContainerProvider and IContainerRegistry aren't registered themselves for this reason, to make it impossible to inject them.

A factory is easy though:

public class ProjectViewModel : BindableBase
{
    private UnitOfWork unitOfWork;
    private Func<UnitOfWork> unitOfWorkFactory;
    private IEventAggregator eventAggregator;
    #region Constructor
    public ProjectViewModel(Func<UnitOfWork> unitOfWorkFactory, IEventAggregator ea) // no need to inject a unit of work
    {
        _unitOfWorkFactory = unitOfWorkFactory;
        eventAggregator = ea;
        ea.GetEvent<SendReloadDataEvents>().Subscribe(Reload); // prefer the parameter
        Reload();
    }
    #endregion

    private void Reload()
    {
        this.unitOfWork = _unitOfWorkFactory(); // create a new one here (the container does the work but is hidden)
        Projects = new ObservableCollection<Projects>(unitOfWork.ProjectRepo.GetAll()); // I'd rather update the existing collection
        Customers = new ObservableCollection<Customers>(unitOfWork.CustomerRepo.Find(x => x.Projects.Count > 0)); // same here, or probably, it could just be IEnumerable
        SelectedProjectType = null;
    }
//Other logic continues
}

Note that this Func<> factory is ok only for the most simple cases. If you need parameters passed into the product constructor, you have to code it yourself as described in this answer. Also note how the container never shows up anywhere (except where it's configured), making your code dependent on the container is just unnecessary and will make tests more ugly.