Initialize Shell with ViewModel after all modules loaded in Prism 6 - c#

The ViewModel (set via AutoWireViewModel="True") of my Shell / MainWindow requests a dependency which gets loaded in a module at startup using the ConfigurationModuleCatalog.
Because the Shell is initialzed before the modules, the DI container obviously can't resolve it, so the application crashes.
public class MainWindowViewModel : BindableBase
{
// Cannot resolve IService
public MainWindowViewModel(IService service)
{
}
}
I already tried the two approaches of this post, but both didn't worked.
I tried it this way:
public interface IShellService
{
int NumberOfLoadedModules { get; }
void FlagModuleAsLoaded();
}
public class ShellService : IShellService
{
private readonly IModuleCatalog _moduleCatalog;
public ShellService(IModuleCatalog moduleCatalog)
{
_moduleCatalog = moduleCatalog;
}
public int NumberOfLoadedModules { get; private set; }
public void FlagModuleAsLoaded()
{
NumberOfLoadedModules++;
if (NumberOfLoadedModules != _moduleCatalog.Modules.Count())
return;
InitializeShell();
}
private static void InitializeShell()
{
Application.Current.MainWindow.Show();
}
}
internal class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return null;
}
protected override void InitializeShell()
{
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterInstance<IShellService>(new ShellService(ModuleCatalog), new ContainerControlledLifetimeManager());
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
}
Usage
public abstract class ModuleBase : IModule
{
private readonly IShellService _shellService;
protected ModuleBase(IShellService shellService)
{
_shellService = shellService;
}
public void Initialize()
{
InitializeInternal();
FlagAsLoaded();
}
public abstract void InitializeInternal();
public void FlagAsLoaded()
{
_shellService.FlagModuleAsLoaded();
}
}
public class FooModule : ModuleBase
{
IUnityContainer _container;
public MusicUIModule(IUnityContainer container, IShellService shellService) : base(shellService)
{
_container = container;
}
public override void InitializeInternal()
{
_container.RegisterType<IService, Service>();
}
}
It starts counting the modules and then the application crashes because of the same reason.
If the approach above isn't fitting for my purpose, how could that problem be solved?
Thanks!

I tried to implement Haukinger's suggestion and did it this way which works just fine:
// Factory --------------------------------------------------------
public interface IDependencyFactory
{
IService GetService();
}
public class DependencyFactory : IDependencyFactory
{
private readonly IUnityContainer _container;
public DependencyFactory(IUnityContainer container)
{
_container = container;
}
public IService GetService()
{
return _container.Resolve<IService>();
}
}
// PubSubEvent ------------------------------------------------------
public class AllModulesLoaded : PubSubEvent
{
}
// Bootstrapper -----------------------------------------------------
internal class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
}
protected override void InitializeModules()
{
base.InitializeModules();
// Publishing event to tell subscribers that the modules are loaded
var eventAggregator = Container.Resolve<IEventAggregator>();
eventAggregator?.GetEvent<AllModulesLoaded>().Publish();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
// ...
Container.RegisterType<IDependencyFactory, DependencyFactory>();
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
}
// ViewModel ---------------------------------------------------------
public class MainWindowViewModel : BindableBase
{
private IService _service;
private readonly IEventAggregator _eventAggregator;
private readonly IDependencyFactory _dependencyFactory;
public MainWindowViewModel(IEventAggregator eventAggregator, IDependencyFactory dependencyFactory)
{
_eventAggregator = eventAggregator;
_dependencyFactory = dependencyFactory;
_eventAggregator.GetEvent<AllModulesLoaded>().Subscribe(OnAllModulesLoaded);
}
private void OnAllModulesLoaded()
{
var service = _dependencyFactory.GetService();
if (service != null)
_service = service ;
_eventAggregator.GetEvent<AllModulesLoaded>().Unsubscribe(OnAllModulesLoaded);
}
}

I'd hide the dependency of the shell behind a factory/provider and then create/fetch it when the last module is loaded. Your shell's view model subscribes to a AllModulesLoaded event that's fired from your bootstrapper's InitializeModules when base.InitializeModules returns to get notified that the dependency is available. Or the factory/provider subscribes to the event and the shell polls it, depending on how you want to use the dependency.

Related

Autofac WCF injection on reflection

I have N validators on my aplication but a client doesn't use all validators, I got by procedure all classes that my current client will need to instantiate.
My Business layer:
public class MyClass
{
public void MyMethod(int idClient)
{
//This array is returned by a procedure passing idClient
string[] validatorsName = { "ValidatorName", "ValidatorName2" };
foreach (string name in validatorsName)
{
IValidator validator = (IValidator)Activator.CreateInstance(Type.GetType(name));
//Error. I need pass the INameDB;
validator.Process();
}
}
}
My Interface:
public interface IValidator
{
void Process();
}
The Validators:
public class ValidatorName : IValidator
{
INameDB nameDB;
public ValidatorName(INameDB nameDB)
{
this.nameDB = nameDB;
}
public void Process()
{
nameDB.AnyThing(pedidoId);
}
}
public class ValidatorName2 : IValidator
{
INameDB2 nameDB;
public ValidatorName(INameDB2 nameDB)
{
this.nameDB = nameDB;
}
public void Process()
{
nameDB.AnyThing2(pedidoId);
}
}
public class ValidatorName3 : IValidator
{
INameDB2 nameDB;
public ValidatorName(INameDB2 nameDB)
{
this.nameDB = nameDB;
}
public void Process()
{
nameDB.AnyThing2(pedidoId);
}
}
On Global, I could register all validators and with the IList<IValidator>, so I would remove from the list the validators that I will not need.
string[] validatorsName = { "ValidatorName", "ValidatorName2" };
validators = validators .Where(p => validatorsName .Contains(p.GetType().Name)).ToList();
but I have a lot of classes, it would register this no need.
My Global:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<NameDB>().As<INameDB>();
builder.RegisterType<NameDB2>().As<INameDB2>();
//builder.RegisterType<ValidatorName1>().As<IValidator>();
//builder.RegisterType<ValidatorName2>().As<IValidator>();
//builder.RegisterType<ValidatorName3>().As<IValidator>();
AutofacHostFactory.Container = builder.Build();
//AutofacHostFactory.Container.Resolve<IList<IValidator>>();
}
}
My question is how can I detect the interface INameDB or INameDB2, get the instance on Autofac and use on Activator.CreateInstance?
Thanks.
After some days, I could code the solution:
My main class, I create a method to injection the validators list:
public class MyClass
{
private IList<IValidator> listValidators;
public void MyMethod(int idClient)
{
ExecuteValidations(idClient);
}
private void ValidatorInjection(int idClient)
{
listValidators = new List<IValidator>();
//This array is returned by a procedure passing idClient
string[] validatorsName = { "ValidatorName", "ValidatorName2" };
foreach (string name in validatorsName)
{
IValidator validador = (IValidator)Activator.CreateInstance(Type.GetType(name));
listValidators.Add(validador);
}
}
private void ExecuteValidations(int idClient)
{
ValidatorInjection(idClient);
RunValidatorsList();
}
private void RunValidatorsList()
{
foreach (var validator in listValidators)
{
validator.Process();
}
}
}
My validators, I needed get the interface database instance on container with INameDB2 db = AutofacHostFactory.Container.Resolve<INameDB2>();:
public class ValidatorName : IValidator
{
public void Process()
{
INameDB db = AutofacHostFactory.Container.Resolve<INameDB>();
db.AnyThing(pedidoId);
}
}
public class ValidatorName2 : IValidator
{
public void Process()
{
INameDB2 db = AutofacHostFactory.Container.Resolve<INameDB2>();
db.AnyThing2(pedidoId);
}
}
public class ValidatorName3 : IValidator
{
public void Process()
{
INameDB2 db = AutofacHostFactory.Container.Resolve<INameDB2>();
db.AnyThing2(pedidoId);
}
}
On Global, I did a way that I don't need add line to register a new class that IValidator implement:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<NameDB>().As<INameDB>();
builder.RegisterType<NameDB2>().As<INameDB2>();
string assembly = "MY_ASSEMBLY";
builder.RegisterAssemblyTypes(Assembly.Load(assembly)).Where(t => t.IsAssignableTo<IValidator>()).AsImplementedInterfaces();
AutofacHostFactory.Container = builder.Build();
}
}

Property Injection (setter injection) Prism for Xamarin.Forms

Is the setter injection supported in the Xamarin.forms?
I have a service injected in the bootstrapper like this
Container.RegisterType<ICommonService, CommonService>();
And inside a viewmodel, I want to have an instance injected to a property like this
[Dependency]
public ICommonService CommonService { get; set; }
But in the runtime, the property CommonService is always null.
The attribute I used is the Microsoft.Practices.Unity.DependencyAttribute, not Xamarin.Forms.DependencyAttribute
If I inject inside the constructor, it works
public LandingPageViewModel(INavigationService navigationService, ICommonService commonService)
Edited: added code snippet
public class Bootstrapper : UnityBootstrapper
{
protected override Page CreateMainPage()
{
try
{
return Container.Resolve<Views.LandingPage>();
}
catch (Exception exception)
{
//TODO: intent to get exception info
throw;
}
}
protected override void RegisterTypes()
{
DependencyResolver.Instance.Initialize(Container);
this.RegisterViews();
this.RegisterServices();
this.RegisterSingleton();
}
private void RegisterViews()
{
Container.RegisterTypeForNavigation<LandingPage>();
Container.RegisterTypeForNavigation<Page1>();
}
private void RegisterServices()
{
Container.RegisterType<ICommonService, CommonService>();
}
private void RegisterSingleton()
{
}
}
public partial class App : Application
{
public App()
{
InitializeComponent();
var bootstrapper = new Bootstrapper();
bootstrapper.Run(this);
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
Hmm they removed the DependencyAttribute injection feature since Prism 7.0, I think we should register it manually. (your code snippet should work)
Look: https://brianlagunas.com/whats-new-in-prism-for-xamarin-forms-7-0/

Avoiding property injection with Ninject

I keep reading that property injection is bad, but I have one usecase where I can justify it to myself, private property injection no less. But I am wondering if it could be done differently.
So, my issue is that I'm creating (Prism) modules for an app, they need to implement the IModule interface like this
public class Configuration : NinjectModule
{
public override void Load()
{
...
//Binding here
...
}
}
public class MyModule : IModule
{
private readonly IKernel _kernel;
private readonly IRegionManager _regionManager;
public MyModule (IKernel kernel, IRegionManager regionManager)
{
_kernel = kernel;
_regionManager = regionManager;
}
public void Initialize()
{
_kernel.Load<Configuration>();
//register views and the like here.
}
}
It is however not optimal in my world. For instance I always have to inject the kernel and regionmanager. I can handler most of it in an abstract class like this
public abstract class AModule : IModule
{
protected IKernel Kernel { get; set; }
protected IRegionManager RegionManager { get; set; }
protected AModule(IKernel kernel, IRegionManager regionManager)
{
Kernel = kernel;
RegionManager = regionManager;
}
public virtual void Initialize()
{
Kernel.Load(CreateConfiguration());
}
protected abstract NinjectModule CreateConfiguration();
}
public class MyModule : IModule
{
public MyModule (IKernel kernel, IRegionManager regionManager)
: base(kernel, regionManager)
{
}
public void Initialize()
{
base.Initialize();
//register views and the like here.
}
protected override NinjectModule CreateConfiguration()
{
return new Configuration();
}
}
But I still have to worry about the kernel and regionmanager in the constructor definition. Ideally I want to avoid writing a constructor entirely like this
public abstract class AModule : IModule
{
[Inject]
protected IKernel Kernel { get; set; }
[Inject]
protected IRegionManager RegionManager { get; set; }
public virtual void Initialize()
{
Kernel.Load(CreateConfiguration());
}
protected abstract NinjectModule CreateConfiguration();
}
This allows me to write the module like this
public class MyModule : AModule
{
public override void Initialize()
{
base.Initialize();
//register views and the like here.
}
protected override NinjectModule CreateConfiguration()
{
return new Configuration();
}
}
Why is this a bad way to do it, and is it even possible to do this without property injection?

Why Won't Ninject New Up Objects In A Class

My Setup:
Visual Studio 2013
Web Forms/MVC project
C#
Ninject 3.2.0.0
Entity Framework
I have a Web Forms/MVC hybrid project that uses Ninject for its IoC containter. I've no problems with Ninject until today. The problem I ran into is that I can't get Ninject to new up some objects whenever I use a class. Here is some code that works:
// Master1.master
namespace TestCode
{
public partial class Master1 : MasterPage
{
[Inject]
public FooController Foo { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
// Do some setup logic.
Foo.Bar();
}
}
}
Now here is some code that doesn't work using a class:
// Master1.master
namespace TestCode
{
public partial class Master1 : MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
new Wrapper().SomeMethod();
}
}
}
// Wrapper.cs
namespace TestCode
{
public class Wrapper
{
[Inject]
public FooController Foo { get; set; }
public void SomeMethod()
{
// Do some setup logic.
Foo.Bar();
}
}
}
My problem is that when I execute SomeMethod(), Foo is null. Why is this and what can I do to get Ninject to new up Foo?
Okay - I got it working now. Thanks everyone! I needed to add a binding my NinjectWebCommon class like so:
public static class NinjectWebCommon
{
private static readonly Bootstrapper Bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
Bootstrapper.Initialize(CreateKernel);
}
public static void Stop()
{
Bootstrapper.ShutDown();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
// Needed to add this binding.
kernel.Bind<IWraper>().To<Wraper>().InRequestScope();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
}

Can I register my types in modules in Unity like I can in Autofac?

I am fairly familiar with Autofac and one feature that I really love about Autofac is the registering of modules. Does anyone know how I can do this with Unity? I'm having a hard time finding which terms to use in Google to come up with the unity equivalent if there is one.
public class Global : HttpApplication, IContainerProviderAccessor
{
private static IContainerProvider _containerProvider;
protected void Application_Start(object sender, EventArgs e)
{
var builder = new ContainerBuilder();
builder.RegisterModule(new MyWebModule());
_containerProvider = new ContainerProvider(builder.Build());
}
[...]
public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
}
public class MyWebModule: Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterModule(new ApplicationModule());
builder.RegisterModule(new DomainModule());
}
}
public class ApplicationModule: Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(c => new ProductPresenter(c.Resolve<IProductView>()))
.As<ProductPresenter>()
.ContainerScoped();
}
}
Actually, you can do trivially with Unity container extensions.
public class Global : HttpApplication, IContainerProviderAccessor
{
private static IContainerProvider _containerProvider;
protected void Application_Start(object sender, EventArgs e)
{
var container = new UnityContainer();
container.AddNewExtension<MyWebModule>();
_containerProvider = new ContainerProvider(container);
}
[...]
public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
}
public class MyWebModule : UnityContainerExtension
{
protected override void Initialize()
{
Container.AddNewExtension<ApplicationModule>();
Container.AddNewExtension<DomainModule>();
}
}
public class ApplicationModule: UnityContainerExtension
{
protected override void Initialize()
{
Container.RegisterType<ProductPrensenter>(
new ContainerControlledLifetimeManager(),
new InjectionFactory(c => new ProductPresenter(c.Resolve<IProductView>())));
}
}
You can't. Just use Autofac or Windsor. You will find there's a lot missing in Unity and what's there works in unexpected ways. It's just not worth your time.

Categories

Resources