Using ninject as a WPF view mode locator - viewmodels as singletons - c#

I'm using ninject's kernel as a viewmodel locator in a WPF application.
The kernel helper class:
public static class IoCKernel
{
private static IKernel kernel;
public static void Init(params NinjectModule[] modules)
{
if (kernel == null)
{
kernel = new StandardKernel(modules);
}
}
public static T Get<T>()
{
return kernel.Get<T>();
}
}
And the ViewModelLocator exposes the Get method like:
public class ViewModelLocator : IViewModelLocator
{
public MainWindowViewModel MainWindowViewModel
{
get
{
return IoCKernel.Get<MainWindowViewModel>();
}
}
}
And when the instance is needed, it's called like:
IoCKernel.Get<IViewModelLocator>().MainWindowViewModel;
However, the IoCKernel.Get<MainWindowViewModel>() will always return a new instance. Is there a way to make it only work with one instance?

If you set up a binding in Ninject, you can call the InSingletonScope method:
Bind<IYourInterface>().To<YourClass>().InSingletonScope();
In your case (you do not have an interface for the view model) it might be:
Bind<MainWindowViewModel>().ToSelf().InSingletonScope();
See here for more info : Object Scopes in Ninject

Related

Fail to initialize dependencies. Singleton class using Dependency Injection (Ninject)

I want a singleton class that uses dependency injection (ninject) start as soon as the application starts. The singleton class resides in Domain layer(Class Library) -
Domain.Concrete.Operations. And I'm using this class in WebUI layer(MVC).
I'm stuck at initializing dependencies in static constructor of the service that I plan to start in Application_Start method. What is the right way to do it?
Singleton class:
namespace Domain.Concrete.Operations
{
public sealed class SingletonClass
{
private IInterface1 _iInterface1;
private IInterface2 _iInterface2;
public SingletonClass(IInterface1 iInterface1, IInterface2 iInterface2)
{
this._iInterface1 = iInterface1;
this._iInterface2 = iInterface2;
StartAllOperations();
}
public void StartAllOperations()
{
}
}
}
NinjectDependencyResolver:
namespace WebUI.Infrastructure
{
public class NinjectDependencyResolver : IDependencyResolver
{
IKernel kernel;
public NinjectDependencyResolver(IKernel kernelParam)
{
kernel = kernelParam;
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
kernel.Bind<IInterface1>().To<Class1>();
kernel.Bind<IInterface2>().To<Class2>();
kernel.Bind<SingletonClass>().To<SingletonClass>().InSingletonScope();
}
}
}
As far as I understand this code will help to return the same instance of SigletonClass:
kernel.Bind<SingletonClass>().To<SingletonClass>().InSingletonScope();
Service in App_Start:
namespace WebUI.App_Start
{
public class OperationManagerService
{
private IInterface1 _iInterface1;
private IInterface2 _iInterface2;
static OperationManagerService() //static constructor cannot have parameters
{
_iInterface1 = //how to initialize
_iInterface2 = //interfaces here?
}
public static void RegisterService()
{
new SingletonClass(_iInterface1, _iInterface2);
}
}
}
Register service in Application_Start (Global.asax.cs):
namespace WebUI
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
OperationManagerService.RegisterService();
}
}
}
UPDATE:
I must admit that I'm able to initialize dependencies like this, but then I can only use the OperationManagerService class in controller. Not in Application_Start!
static OperationManagerService(IInterface1 iInterface1, IInterface2 iInterface2)
{
_iInterface1 = iInterface1;
_iInterface2 = iInterface2;
}
This leads me to thought that I can't use injection with Ninject in Application_Start. If it's true, then where is the right place to create a class that should load at startup?
You are trying to intermix the Singleton pattern with Ninject's Singleton Scope, which confuses who is trying to construct what when. Don't use the old the Singleton pattern when trying to use DI. Half of the point of DI is to manage the lifetime (scope) of the objects it contains. You do this by specifying .InSingletonScope() as you have done.
Now, onto your question of injecting dependencies into a startup feature: you will need to allow Ninject to construct the OperationManagerService in order to have the dependencies provided by Ninject. To do this, register it in Singleton scope, as you did with SingletonClass. The first time it is requested from the Ninject container, it will be constructed and injected with the necessary parameters. Singleton scope only tells Ninject to only ever construct one instance.
However, it seems that you would like it to be constructed during startup? If this is a requirement, something will need to ask for it. The simplest solution would be to get it after binding it:
private void AddBindings()
{
kernel.Bind<IInterface1>().To<Class1>();
kernel.Bind<IInterface2>().To<Class2>();
kernel.Bind<SingletonClass>().ToSelf().InSingletonScope();
kernel.Bind<OperationManagerService>().ToSelf().InSingletonScope();
kernel.Get<OperationManagerService>(); // activate
}
If you find yourself doing this alot, I have used a simple "auto-start" pattern:
public interface IAutoStart()
{
void Start();
}
public class SomeClassThatStarts : IAutoStart
{
public void Start()
{
Console.Log("Starting!");
}
}
public class AutoStartModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
foreach(var starter in Kernel.GetAll<IAutoStart>())
{
starter.Start();
}
}
}
Register the AutoStartModule last in your Kernel, and any IAutoStart will be loaded with any dependencies and started.

Way to dynamically get repositories without a dependency on a DI container

I have a class that returns a repository (read only) using a generic method this is to reduce the number of repository classes I need to inject into classes in my business layer. It also allows me to add and use a new repo anywhere I have this wrapper class simply by adding a repo which implements IGenericReadRepo<T> as this will be registered in unity using the line Container.RegisterType(typeof(IGenericReadRepository<>), typeof(GenericReadRepository<>), new TransientLifetimeManager());. However this has is dependent on unity being the DI container. This smells to me.
public class ReadRepositoryWrapper : IReadRepositoryWrapper
{
private IUnityContainer _unityContainer;
public ReadRepositoryWrapper(IUnityContainer container)
{
_unityContainer = container;
}
public IGenericReadRepository<T> GetReadRepository<T>() where T : class
{
return _unityContainer.Resolve<IGenericReadRepository<T>>();
}
}
Can anyone think of a way to implement the GetReadRepository<T> without a the dependency on unity while not introducing any new dependencies. Or can someone think of another way to get repositories without having bloated constructors or a dependency on my context.
You can create generic factory interfaces/classes for dynamic object creation. Many DI containers support object creation using lambda expressions.
public interface IFactory<T>
{
T Create();
}
public class Factory<T> : IFactory<T>
{
private readonly Func<T> _creator;
public Factory(Func<T> creator)
{
if(creator == null)
throw new ArgumentNullException("creator");
_creator = creator;
}
public T Create()
{
return _creator();
}
}
The generic factory interface than can be injected into the consuming classes.
public class ReadRepositoryWrapper<T> : IReadRepositoryWrapper<T> where T : class
{
private readonly IFactory<IGenericReadRepository<T>> _factory;
public ReadRepositoryWrapper(IFactory<IGenericReadRepository<T>> factory)
{
if(factory == null)
throw new ArgumentNullException("factory");
_factory = factory;
}
public IGenericReadRepository<T> GetReadRepository()
{
return _factory.Create();
}
}
Or something like that.

Winforms IoC Container - How to handle concrete types with a presenter factory

Background
I'm using Winforms with a MVP pattern to create an application. I'm using SimpleInjector as my IoC container. My presenters inherit from:
public interface IPresenter<TView>
{
TView View { get; set; }
}
internal class HomePresenter : IPresenter<IHomeView>
{
public IHomeView View { get; set; }
...
}
In order to create my presenters, I have decided to use a presenter factory with the following method:
public static IPresenter<TView> CreateForView<TView>(TView view)
{
var presenter = _container.GetInstance<IPresenter<TView>>();
presenter.View = view;
return presenter;
}
And then in each view, the view creates its own presenter by calling the presenter factory:
_homeMainPresenter = (HomePresenter) presenterFactory.CreateForView<IHomeView>(this);
_homeMainPresenter.View = this;
In my Program.cs file, I have:
static void Main()
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
System.Windows.Forms.Application.Run((HomeView)container.GetInstance<IHomeView>());
}
private static void Bootstrap()
{
// Create the container
container = new Container();
// Register types
container.Register<IHomeView, HomeView>(Lifestyle.Singleton);
container.Register<IPresenter<IHomeView>, HomePresenter>();
...
// Verify the container
container.Verify();
}
Problem
When the presenter factory is called from the HomeView view, the type fed into the factory is a HomeView type, not IHomeView. So, the application throws an exception because the container does not have a HomeView registration (only IHomeView). My presenters all have interfaces for the views references they store as I feel this will be better for testing. How do I avoid this situation?
Having a interface-to-implementation binding for your forms is not useful, since they are root types for your presentation technology. Most presentation technologies can't deal with custom abstractions anyway and this is the reason that you are casting your IHomeView back to HomeView to allow it to be passed on to the Application.Run method.
Instead of resolving the presenter from within the view, you can do the following instead:
public interface IHomeView { }
public interface IPresenter<TView> {
TView View { get; set; }
}
public class HomeView : Form, IHomeView
{
private readonly IPresenter<IHomeView> presenter;
public HomeView(IPresenter<IHomeView> presenter) {
this.presenter = presenter;
InitializeComponent();
}
}
Here the Form gets injected with an IPresenter<IHomeView> and stores that incoming dependency. The factory is not needed anymore and can be removed from your code.
And in your program main:
static void Main()
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
System.Windows.Forms.Application.Run(GetForm<HomeView, IHomeView>(container));
}
private static void Bootstrap()
{
// Create the container
container = new Container();
// Register types
// NOTE: We register HomeView as concrete type; not by its interface.
container.Register<HomeView>(Lifestyle.Singleton);
// Here we batch-register all presenters with one line of code and
// since the forms depend on them, they need to be singletons as well.
container.Register(typeof(IPresenter<>), AppDomain.CurrentDomain.GetAssemblies(),
Lifestyle.Singleton);
...
// Verify the container
container.Verify();
}
private static TForm GetForm<TForm, TView>() where TForm : Form, TView
{
var form = container.GetInstance<TForm>();
container.GetInstance<IPresenter<TView>>().View = form;
return form;
}
The factory class is now replaced with the GetForm method that is part of the composition root; Forms don't have access to it. The generic types allow us to resolve the proper presenter, while keeping the code type-safe.

Using Ninject with MVVM Light

Using MVVM Light in a WPF MVVM application.
I want to use Ninject instead of SimpleIOC.
Even in a brand new WPF/MVVM Light v4 project, I get a null reference for MainViewModel when the Main Property in the ViewModelLocator is called by the XAML.
private static readonly StandardKernel kernel;
static ViewModelLocator()
{
if (ViewModelBase.IsInDesignModeStatic)
{
}
else
{
kernel = new StandardKernel(new mymodule());
}
}
public MainViewModel Main
{
get { return kernel.Get<MainViewModel>(); }
}
MyModule looks like this:
public class mymodule:NinjectModule
{
public override void Load()
{
Bind<MainViewModel>().ToSelf();
}
}
I've also tried
public class mymodule:NinjectModule
{
public override void Load()
{
Bind<MainViewModel>().To<MainViewModel();
}
}
Ninject kernel's .Get<T> does not return null.
Except in case you explicitly tell it to by doing:
Bind<T>().ToConstant(null);
Bind<T>().ToMethod(x => null);
Bind<T>().ToProvider<TProvider>() --> and TProvider.Create(...) returns null
It's very unlikely you have any of these.
So if there's a NullReferenceException when accessing the Main property, it must be because private static readonly StandardKernel kernel is null.
Now if the code you've provided us is a Minimal, Complete, and Verifiable example, that means ViewModelBase.IsInDesignModeStatic returns true.

How to Inject daoFactory into NHibernate EventListener

I need to Inject some global service (daoFactory) into EventListenet subscribed on PostUpdate event. I`ve read that it is possible to do this way:
public class YourPostInsertListener : IPostInsertEventListener
{
private readonly IPersistentAuditor auditor;
public YourPostInsertListener(IPersistentAuditor auditor)
{
this.auditor = auditor;
}
public void OnPostInsert(PostInsertEvent #event)
But this code just throws exception: no parameterless constructor was specified for EventListener. And this is understandable behavior, because I haven`t added my service to any container. So how can I specify the IoC contauner in NHibernate?
The IoC that I've been using is Ninject. The best way I found so far is to take advantage of the ServiceLocator provdided by the Microsoft Patterns and Practices guys:
internal class YourPostInsertListener : IPostInsertEventListener
{
IKernel Kernel
{
get
{
return ServiceLocator.Current.GetInstance<IKernel>();
}
}
IPersistentAuditor
{
get
{
return Kernel.Get<IPersistentAuditor>();
}
}
// ... Rest of class
}
In the class that sets up your IoC container you would do this:
ServiceLocator.SetLocatorProvider( () => new NinjectServiceLocator( kernel ) );

Categories

Resources