Replacing Mvvm Lights SimpleIoc with Unity IoC - c#

I am having some trouble to get things up and running after replaced SimpleIoc with the unity IoC. I followed these instructions referring how to implement the IServiceLocator for unity.
However my application fails to function properly. For example I'm unable to get the dataGrids _selectedDevice to be anything else than null. With SimpleIoc, everything worked fine.
Here's my ViewModelLocator:
using System;
using System.Windows;
using GalaSoft.MvvmLight.Ioc;
using GalaSoft.MvvmLight.Messaging;
using Microsoft.Practices.ServiceLocation;
using Microsoft.Practices.Unity;
namespace FxEditorDatabaseStructure.ViewModel
{
/// <summary>
/// This class contains static references to all the view models in the
/// application and provides an entry point for the bindings.
/// </summary>
public class ViewModelLocator
{
#region Constructor
/// <summary>
/// Initializes a new instance of the ViewModelLocator class.
/// </summary>
public ViewModelLocator()
{
// Register the IOC container as SimpleIoc
//ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
// Register Unity as the IOC container
var unityContainer = new UnityContainer();
ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(unityContainer));
//If we wish use another IoC we must implement the IServiceLocator interface
// Create new UnitOfWork for all the views IOC - CREATED AT registration
//SimpleIoc.Default.Register<IUnitOfWork, UnitOfWork>(true);
unityContainer.RegisterType<IUnitOfWork, UnitOfWork>(new InjectionConstructor(new FxContext()));
/*
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<DeviceDatabaseViewModel>();
SimpleIoc.Default.Register<ProjectDeviceDatabaseViewModel>();
*/
unityContainer.RegisterType<MainViewModel>();
unityContainer.RegisterType<DeviceDatabaseViewModel>();
}
#endregion
#region ViewModels
[NotNull]
public MainViewModel MainViewModel
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
private set { if (value == null) throw new ArgumentNullException(nameof(value)); }
}
[NotNull]
public DeviceDatabaseViewModel DeviceDatabaseViewModel
{
get { return ServiceLocator.Current.GetInstance<DeviceDatabaseViewModel>(); }
private set { if (value == null) throw new ArgumentNullException(nameof(value)); }
}
/// <summary>
/// Retrieves this instance from the application's resources and exposes it to other objects.
/// </summary>
public static ViewModelLocator Instance
{
get
{
return Application.Current.Resources["Locator"] as ViewModelLocator;
}
}
#endregion
#region cleanup
public static void Cleanup()
{
// TODO Clear the ViewModels
}
#endregion
}
}
All the ViewModels call this IoC like this:
private readonly IUnitOfWork _context = ServiceLocator.Current.GetInstance<IUnitOfWork>();
Is there something wrong with this line?
unityContainer.RegisterType<IUnitOfWork, UnitOfWork>(new InjectionConstructor(new FxContext()));
I'm trying to initialise one instance of FxContext and share this to all the ViewModels which all call ServiceLocator.Current.GetInstance<IUnitOfWork>()
EDIT:
Basically I want to be able to use the same UnitOfWork for two different sets of database, like in the following:
var deviceDatabase = new DeviceContext();
var projectDatabase = new ProjectContext();
unityContainer.RegisterType<IUnitOfWork, UnitOfWork>(new InjectionConstructor(deviceDatabase));
unityContainer.RegisterType<IUnitOfWork, UnitOfWork>(new InjectionConstructor(projectDatabase));

Seems like to the answer to register the views similar to SimpleIoc is by following line:
unityContainer.RegisterType<MainViewModel>(new ContainerControlledLifetimeManager());
where the ContainerControlledLifetimeManager() was the key when using RegisterType method.

Related

interface and cannot be constructed on Unity config

I have trouble to use Unity on this project.
The error is
The current type, Business.Interfaces.IPersonnelBusiness, is an
interface and cannot be constructed. Are you missing a type mapping?
I've updated the Unity to thge latest version because of stackoverflow issueand I saw that RegisterComponents has changed to lazy loaded one
here is the Global asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// Unity settings
//UnityConfig.RegisterComponents();
// For logging
//SetupSemanticLoggingApplicationBlock();
}
Here is the UnityConfig file:
public static class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container =
new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Configured Unity Container.
/// </summary>
public static IUnityContainer Container
{
get
{
return container.Value;
}
}
#endregion
/// <summary>
/// Registers the type mappings with the Unity container.
/// </summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>
/// There is no need to register concrete types such as controllers or
/// API controllers (unless you want to change the defaults), as Unity
/// allows resolving a concrete type even if it was not previously
/// registered.
/// </remarks>
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below.
// Make sure to add a Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your type's mappings here.
// container.RegisterType<IProductRepository, ProductRepository>();
container = new UnityContainer();
// Identity managment
container.RegisterType<DbContext, ApplicationDbContext>(new HierarchicalLifetimeManager());
container.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<AccountController>(new InjectionConstructor());
container.RegisterType<PersonnelController>(new InjectionConstructor());
container.RegisterType<UsersAdminController>(new InjectionConstructor());
// Business Layer
container.RegisterType<ILogBusiness, LogBusiness>();
container.RegisterType<IAnomalyBusiness, AnomalyBusiness>();
container.RegisterType<ICockpitStatBusiness, CockpitStatsBusiness>();
container.RegisterType<IDocumentBusiness, DocumentBusiness>();
container.RegisterType<IEmailBusiness, EmailBusiness>();
container.RegisterType<IMessageBusiness, MessageBusiness>();
container.RegisterType<INatureBusiness, NatureBusiness>();
container.RegisterType<IPersonnelBusiness, PersonnelBusiness>();
container.RegisterType<ISAPBusiness, SAPBusiness>();
// Set resolver
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
Thanks folks
EDIT:
here is the stack and the code where it is thrown:
StackTrace:
[ResolutionFailedException: Resolution of the dependency failed, type = 'APPI.WEB.Controllers.HomeController', name = '(none)'.
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, APPI.Business.Interfaces.IPersonnelBusiness, is an interface and cannot be constructed. Are you missing a type mapping?
-----------------------------------------------
At the time of the exception, the container was:
Resolving APPI.WEB.Controllers.HomeController,(none)
Resolving parameter 'personnelRepo' of constructor APPI.WEB.Controllers.HomeController(APPI.Business.Interfaces.IPersonnelBusiness personnelRepo, APPI.Business.Interfaces.IAnomalyBusiness anomalyRepo, APPI.Business.Interfaces.IDocumentBusiness docRepo, APPI.Business.Interfaces.IMessageBusiness msgRepo, APPI.Business.Interfaces.ICockpitStatBusiness cockpitStatRepo, APPI.Business.Interfaces.INatureBusiness natureRepo)
Resolving APPI.Business.Interfaces.IPersonnelBusiness,(none)
]
Controller:
public class HomeController : BaseController
{
private readonly IPersonnelBusiness _IPersonnelBusinessRepo;
private readonly IAnomalyBusiness _IAnomalyBusinessRepo;
private readonly IDocumentBusiness _IDocumentBusinessRepo;
private readonly IMessageBusiness _IMessageBusinessRepo;
private readonly ICockpitStatBusiness _ICockpitStatBusinessRepo;
private readonly INatureBusiness _INatureBusinessRepo;
// Unity inject references
public HomeController(IPersonnelBusiness personnelRepo, IAnomalyBusiness anomalyRepo, IDocumentBusiness docRepo,
IMessageBusiness msgRepo, ICockpitStatBusiness cockpitStatRepo, INatureBusiness natureRepo)
{
_IPersonnelBusinessRepo = personnelRepo;
_IAnomalyBusinessRepo = anomalyRepo;
_IDocumentBusinessRepo = docRepo;
_IMessageBusinessRepo = msgRepo;
_ICockpitStatBusinessRepo = cockpitStatRepo;
_INatureBusinessRepo = natureRepo;
}
public HomeController()
{
}
public ActionResult Index()
{
return RedirectToActionPermanent("Cockpit", "Home");
}
There is also the UnityActivator that is called before starting app thanks to
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(APPI.WEB.UnityMvcActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(APPI.WEB.UnityMvcActivator), "Shutdown")]
UnityActivator:
public static class UnityMvcActivator
{
/// <summary>
/// Integrates Unity when the application starts.
/// </summary>
public static void Start()
{
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(UnityConfig.Container));
DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfig.Container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
// Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
/// <summary>
/// Disposes the Unity container when the application is shut down.
/// </summary>
public static void Shutdown()
{
UnityConfig.Container.Dispose();
}
}
As pointed out in the comments, the issue is that you are instantiating 2 different containers, once in your initializer:
private static Lazy<IUnityContainer> container =
new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer(); // <-- new container here
RegisterTypes(container);
return container;
});
And once in your RegisterTypes method:
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below.
// Make sure to add a Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your type's mappings here.
// container.RegisterType<IProductRepository, ProductRepository>();
container = new UnityContainer(); // <-- new container here
...
The type mappings are added in the RegisterTypes method to a different instance than the container you are passing in as an argument.
To make it work right, you should remove the instantiation of the container in RegisterTypes so it can use the instance that is passed in the parameter.
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below.
// Make sure to add a Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your type's mappings here.
// container.RegisterType<IProductRepository, ProductRepository>();
// container = new UnityContainer(); // <-- Remove this
...

Web API ContainerControlledLifetimeManager - not what expected

I have an ASP.NET MVC application, which serving http pages and provides REST API using Web API.
I have a "service" class, which supposed to be a singleton and to be used both in ASP.NET MVC and Web API parts.
For dependency injection, I using Unity. I installed from NuGet Unity, Unity.AspNet.Mvc and Unity.AspNet.WebApi packages.
I registering my service as singleton:
container.RegisterType<IService, ServiceImp>(new ContainerControlledLifetimeManager());
What I see is that different instances of "ServiceImp" created for ASP.NET MVC and for Web API. The constructor called twice. It looks like there are two separate containers there...
All contents of UnityConfig.cs, UnityMvcActivator.cs and UnityWebApiActivator.cs remained unchanged as initial template, except the place where I register my services.
Any idea how to solve this issue? What I doing wrong?
UnityConfig.cs
namespace Management.App_Start
{
/// <summary>
/// Specifies the Unity configuration for the main container.
/// </summary>
public class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
#endregion
/// <summary>Registers the type mappings with the Unity container.</summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to
/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IService, ServiceImp>(new ContainerControlledLifetimeManager());
}
}
}
UnityMvcActivator.cs
using System.Linq;
using System.Web.Mvc;
using Microsoft.Practices.Unity.Mvc;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Management.App_Start.UnityWebActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(Management.App_Start.UnityWebActivator), "Shutdown")]
namespace Management.App_Start
{
/// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
public static class UnityWebActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
// Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
}
UnityWebApiActivator.cs
using System.Web.Http;
using Microsoft.Practices.Unity.WebApi;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Management.App_Start.UnityWebApiActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(Management.App_Start.UnityWebApiActivator), "Shutdown")]
namespace Management.App_Start
{
/// <summary>Provides the bootstrapping for integrating Unity with WebApi when it is hosted in ASP.NET</summary>
public static class UnityWebApiActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
// Use UnityHierarchicalDependencyResolver if you want to use a new child container for each IHttpController resolution.
// var resolver = new UnityHierarchicalDependencyResolver(UnityConfig.GetConfiguredContainer());
var resolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
}
UPDATE 9.9.17
After some digging, I see that Application_Start called twice - first time when any http page requested and second time when REST API called. As a result, everything initialized twice, including Unity. Now I need to find out why this happens...

Unity LifeTime manager for Quartz.net

I'm trying to use Quartz.Net in a asp.NET MVC application. I'm using Unity as DI, with PerRequestLifeTimeManager.
Quartz.Net, however, doesn't work with PerRequestLifeTimeManager because, well, it doesn't have a request to begin with. Any dependency I try to resolve with it returns null.
I've created a class like an adapter to use two life time managers depending on the context as following:
class CustomLifetimeManager : LifetimeManager
{
private readonly string _key = "CustomLifetimeManagerKey" + Guid.NewGuid();
private readonly PerResolveLifetimeManager _perResolveLifetimeManager = new PerResolveLifetimeManager();
private bool IsWebContext => HttpContext.Current != null;
public override object GetValue()
{
return IsWebContext
? HttpContext.Current.Items[_key]
: _perResolveLifetimeManager.GetValue();
}
public override void SetValue(object newValue)
{
if (IsWebContext)
HttpContext.Current.Items[_key] = newValue;
else
_perResolveLifetimeManager.SetValue(newValue);
}
public override void RemoveValue()
{
if (IsWebContext)
HttpContext.Current.Items[_key] = null;
else
_perResolveLifetimeManager.RemoveValue();
}
}
I've tried PerThreadLifetimeManager, it executes fine for the first time, then the subsequent executions fails with the message
The operation cannot be completed because the DbContext has been
disposed.
I've tried changing to PerResolveLifeTimeManager, but it fails with
An entity object cannot be referenced by multiple instances of
IEntityChangeTracker
My job is pretty straightforward, similar to the following:
[DisallowConcurrentExecution]
class MyJob
{
IFooRepository _fooRepository;
IBarRepository _barRepository;
public MyJob(IFooRepository fooRepository, IBarRepository barRepository)
{
_fooRepository = fooRepository;
_barRepository = barRepository;
}
public void Execute(IJobExecutionContext context)
{
var foos = _fooRepository.Where(x => !x.Processed);
foreach(var foo in foos)
{
var bar = _barRepository.Where(x => x.Baz == foo.Baz);
foo.DoMagic(bar);
foo.Processed = true;
_fooRepository.Save(foo);
}
}
}
And my job factory is
public class UnityJobFactory : IJobFactory
{
private readonly IUnityContainer _container;
public UnityJobFactory(IUnityContainer container)
{
_container = container;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return (IJob)_container.Resolve(bundle.JobDetail.JobType);
}
public void ReturnJob(IJob job)
{
}
}
How do I correctly manage dependency life time in a Quartz job?
I had the same issue with Castle.Windsor and Quartz.Net. The only applicable way i found was a ScopedLifetime, but you have to control the Scope by yourself. If a new Request comes in, open a scope and all service will be resolved in this scope (the so called UnitOfWork ;)) and when the request ends, close it.
The job handling is a little bit more trickier. But you have two ways to solve that. For both ways you need a Factory that can start scopes.
Your Job gets a Factory in the constructor and in Execute(IJobExecutionContext context) the factory starts a scope, resolves your service (repositories...) executes whatever the job does and closes the scope. A using(Factory.BeginScope()) works great for this. the downside of this is, it is considered as bad practice because of using the service locator pattern.
public class MyJob
{
private readonly Factory Factory;
public MyJob(Factory factory)
{
Factory = factory;
}
public void Execute(IJobExecutionContext context)
{
using (Factory.BeginScope())
{
var repo = Factory.Create<IFooRepository>();
// Do stuff
Factory.Release(repo);
}
}
}
Your Job gets a Factory or something that can start a scope and your service as function like: Func<IFooRepository> repositoryFunc. Then in your Execute method, start the scope (again with a using) and invoke your repository, it will return your real repository in that scope and you can work with it like you want. This should be the best way. Please note, that this is not considered as Service Locator Pattern, because you give your job the Func<> for the service and you just control the scope.
public class MyJob
{
private readonly Factory Factory;
private readonly Func<IFooRepository> RepositoryFunc;
public MyJob(Factory factory, Func<IFooRepository> repositoryFunc)
{
Factory = factory;
RepositoryFunc= repositoryFunc;
}
public void Execute(IJobExecutionContext context)
{
using (Factory.BeginScope())
{
var repo = RepositoryFunc();
// Do Stuff
}
}
}
The Problem
PerThreadLifetimeManager
The operation cannot be completed because the DbContext has been disposed.
This comes because Quartz uses a MainThread and per default a ThreadPool with 10 Threads. All Jobs are created in the MainThread and then executed in a free thread from the pool. If you start a job, the DBContext is bound to the MainThread. When you start another job, then there is already a DBContext bound to this Thread, no matter if it is disposed or closed and the LifeTimeManager will resolve this already used context. If you start your Job the first time, the Thread is new and you current DBContext is bound to this Thread. When you start the next job and it executes in the same Thread, then there was always a DBContext bound to this Thread. The LifeTimeManager resolves this allready used context, but you can't use it, because its closed.
PerResolveLifeTimeManager
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
This issue comes from EF. Each service that you resolve gets an new Scope, even if you resolve different services with the same constructor. This results in that every Repository you use, have its own DBContext. And EF forbids to use different DBContexts with the same entity.
Got this to work long time ago with simpleinjector.
This was with an older version of Quartz though, hope it can still help
You need to create a custom LifetimeScope
public class LifetimeScopeJobDecorator : IJob
{
private readonly IJob _decoratee;
private readonly Container _container;
public LifetimeScopeJobDecorator(IJob decoratee, Container container)
{
_decoratee = decoratee;
_container = container;
}
public void Execute(IJobExecutionContext context)
{
using (_container.BeginLifetimeScope())
{
_decoratee.Execute(context);
}
}
}
That you call into your job factory
public class SimpleInjectorJobFactory : IJobFactory
{
private readonly Container _container;
public SimpleInjectorJobFactory(Container container)
{
_container = container;
_container.Verify();
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
IJobDetail jobDetail = bundle.JobDetail;
Type jobType = jobDetail.JobType;
var job = (IJob)_container.GetInstance(jobType);
return new LifetimeScopeJobDecorator(job, _container);
}
public void ReturnJob(IJob job)
{
}
}
Then you can initialize your custom Quartz Container
public static class QuartzScheduler
{
private static Container _quartzContainer { get; set; }
private static void Initialize()
{
Container container = new Container();
container.RegisterLifetimeScope<IUnitOfWork, SqlUnitOfWork>();
container.Register<ILogger, NLogLogger>();
//To enable lifetime scoping, please make sure the EnableLifetimeScoping extension method is called during the configuration of the container.
container.EnableLifetimeScoping();
container.Verify();
_quartzContainer = new Container();
var schedulerFactory = new StdSchedulerFactory();
_quartzContainer.RegisterSingle<IJobFactory>(() => new SimpleInjectorJobFactory(container));
_quartzContainer.RegisterSingle<ISchedulerFactory>(schedulerFactory);
_quartzContainer.Register<IScheduler>(() =>
{
var scheduler = schedulerFactory.GetScheduler();
scheduler.JobFactory = _quartzContainer.GetInstance<IJobFactory>();
return scheduler;
}
);
_quartzContainer.Verify();
Start the scheduler
public static void StartJobs()
{
Initialize();
//Ask the scheduler factory for a scheduler
IScheduler scheduler = _quartzContainer.GetInstance<IScheduler>();
scheduler.Start();
}
Please take a look at Quartz.Unity nuget package https://github.com/hbiarge/Quartz.Unity, this unity package has a decent implementation of ScopedLifetime.
In addition to the above nuget package, if you use multiple unity container instances and pass the lifetimemanager as a delegate, it will allow you to properly handle the disposable types such as DBContext for each quartz job as well as for each http request.
You have to setup a separate IUnityContainer instance for the asp.net mvc / web api and another instance of IUnityContainer for Quartz scheduler.
Here is a full working sample
https://github.com/vinodres/DITestingWithQuartz
If you look at QuartzStartup.cs, I have used it to initialize Quartz Scheduler. For simplicity purposes, lets assume IHelloService is a disposable type and it must be disposed at the end of each job as well as at the end of each http request. Here I am creating a separate instance of
IUnityContainer assigned to QuartzContainer and added new extension called QuartzUnityExtention from Quartz.Unity nuget package. Also invoked a .Configure extension method that I created inside another file called unityconfig.cs. This method take Func as a parameter. This parameter allows you to pass different life time manager instances based on the execution path.
Here is QuartzStartup.cs
[assembly: OwinStartup(typeof(DiTestingApp.QuartzStartup))]
namespace DiTestingApp
{
/// <summary>
///
/// </summary>
public class QuartzStartup
{
private static readonly ILog Log = LogManager.GetLogger(typeof(QuartzStartup));
/// <summary>
/// Get the hangfire container.
/// </summary>
private static readonly Lazy<IUnityContainer> QuartzContainer = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
container.AddNewExtension<QuartzUnityExtension>();
container.Configure(() => new HierarchicalLifetimeManager());
return container;
});
/// <summary>
///
/// </summary>
/// <param name="app"></param>
public void Configuration(IAppBuilder app)
{
Log.Info("Quartz Startup Intitializing...");
var container = QuartzContainer.Value;
InitScheduler(container);
Log.Info("Quartz Startup Intialization Complete...");
var properties = new AppProperties(app.Properties);
var cancellationToken = properties.OnAppDisposing;
if (cancellationToken != CancellationToken.None)
{
cancellationToken.Register(() =>
{
QuartzContainer.Value.Dispose();
Log.Info("Quartz container disposed (app pool shutdown).");
});
}
}
private void InitScheduler(IUnityContainer container)
{
try
{
var scheduler = container.Resolve<IScheduler>();
scheduler.Start();
IJobDetail job = JobBuilder.Create<HelloWorldJob>().Build();
ITrigger trigger = TriggerBuilder.Create()
.WithSimpleSchedule(x => x.WithIntervalInSeconds(20).RepeatForever())
.Build();
scheduler.ScheduleJob(job, trigger);
}
catch (Exception ex)
{
Log.Error(ex);
}
}
}
}
A similar setup I have for asp.net mvc / web api dependency resolver configuration. I created a file called UnityMvcActivator.cs, here when I call .Configure extension method, I am passing PerRequestLifetimeManager.
UnityMvcActivator.cs
using System;
using System.Linq;
using System.Web.Http;
using System.Web.Mvc;
using Common.Logging;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Mvc;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(DiTestingApp.App_Start.UnityWebActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(DiTestingApp.App_Start.UnityWebActivator), "Shutdown")]
namespace DiTestingApp.App_Start
{
/// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
public static class UnityWebActivator
{
private static readonly ILog Log = LogManager.GetLogger(typeof(UnityWebActivator));
/// <summary>
/// Get the hangfire container.
/// </summary>
private static readonly Lazy<IUnityContainer> WebContainer = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
container.Configure(() => new PerRequestLifetimeManager());
return container;
});
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
Log.Info("Web api DI container intializing.");
var container = WebContainer.Value;
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
var resolver = new Microsoft.Practices.Unity.WebApi.UnityDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
Log.Info("Web api DI container intialization complete.");
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
Log.Info("Web api DI container disposing.");
var container = WebContainer.Value;
container.Dispose();
}
}
}
Now comes the part where you register your types with IUnityContainer. Here is the implementation of configure method inside UnityConfig.cs. Here I have registered IHelloService to use the disposableLifetimeManager delegate. When the delegate is invoked, a proper lifetime manager is supplied depending on your execution path. It will be PerRequestLifetimeManager, if IHelloService is used with in context of asp.net mvc / web api. And it will be HierarchicalLifetimeManager if it is used inside a Quartz Job.
UnityConfig.cs
using System;
using DiTestingApp.Models;
using Microsoft.Practices.Unity;
using Quartz;
using Testing.Scheduler;
namespace DiTestingApp
{
/// <summary>
/// Specifies the Unity configuration for the main container.
/// </summary>
public static class UnityConfig
{
/// <summary>
///
/// </summary>
/// <param name="container"></param>
/// <param name="disposableLifetimeManager"></param>
/// <returns></returns>
public static IUnityContainer Configure(this IUnityContainer container, Func<LifetimeManager> disposableLifetimeManager )
{
container.RegisterType<IJob, HelloWorldJob>();
container.RegisterType<IHelloService, HelloService>(disposableLifetimeManager());
return container;
}
}
}
HierarchicalLifetimeManager is used for Quartz execution path, so that any disposable types will be properly disposed at the end of each job.
If Quartz.Unity implementation is not sufficient for your use cases, you can always customize it further.

Ninject not resolving dependencies for a Controller

I have no idea what is going on with this. It makes no sense to me.
I have a controller that throws the following error:
System.InvalidOperationException: An error occurred when trying to create a controller of type 'LandingController'. Make sure that the controller has a parameterless public constructor. ---> Ninject.ActivationException: Error activating IApiService using binding from IApiService to ApiService No constructor was available to create an instance of the implementation type. Activation path: 2) Injection of dependency IApiService into parameter apiService of constructor of type LandingController 1) Request for LandingController Suggestions: 1) Ensure that the implementation type has a public constructor. 2) If you have implemented the Singleton pattern, use a binding with InSingletonScope() instead.
No matter what I do nothing works.
If I have:
no constructors in the controller
one constructor with the service
two constructors with the service and parameterless
If I hope for the parameterless constructor to work, then it does not resolve the IApiService.
I have the following setup in NinjectWebCommon:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IApiService>().To<ApiService>();
kernel.Bind<IMembersClient>().To<MembersClient>();
}
Controller is:
public class LandingController : Controller
{
IApiService _apiService;
LandingController(IApiService apiService)
{
_apiService = apiService;
}
// GET: Landing
public ActionResult Index()
{
var avm = new ApplicationViewModel();
_apiService.GetAcc();
return View(avm);
}
}
API Service is:
public class ApiService : IApiService
{
private readonly IMembersClient _membersClient;
ApiService(IMembersClient membersClient)
{
_membersClient = membersClient;
}
public void GetAcc()
{
_membersClient.Test();
}
}
Member Client is:
public class MembersClient : IMembersClient
{
public MembersClient()
{
public void Test()
{
}
}
}
This was the best post I found:
Ninject Dependency Injection with Asp.Net MVC3 or MVC4
But it never helped solve the issue.
EDIT: Full NinjectWebCommon
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IApiService>().To<ApiService>();
kernel.Bind<IMembersClient>().To<MembersClient>();
}
EDIT : Trying Property Injection
Code for property injection:
[Inject]
public IApiService ApiServiceC { private get; set; }
Updated Error:
System.InvalidOperationException: An error occurred when trying to create a controller of type 'LandingController'. Make sure that the controller has a parameterless public constructor. ---> Ninject.ActivationException: Error activating IApiService using binding from IApiService to ApiService No constructor was available to create an instance of the implementation type. Activation path: 2) Injection of dependency IApiService into property ApiServiceC of type LandingController 1) Request for LandingController Suggestions: 1) Ensure that the implementation type has a public constructor. 2) If you have implemented the Singleton pattern, use a binding with InSingletonScope() instead.
Well.... after much testing and trying different things.
The solution was to delete IApiService and ApiService completely and recreate them.
That successfully made everything wire up correctly again.

using DependencyInjection at the top level, how to pass the services down the architecture?

Using an IOC-container like Unity,AutoFac or others you have to Register and Resolve the IInterface to get the instance. This you do in the app class the root of all.
After doing the Register/Resolve stuff I am creating my MainController and pass them ALL resolved Services like:
protected void Application_Start(object sender, EventArgs e)
{
var builder = new ContainerBuilder();
builder.Register<IUserService1, UserService1>();
builder.Register<IUserService2, UserService2>();
builder.Register<IUserService3, UserService3>();
builder.Register<IAnotherService, AnotherService>();
// And many more Services...
_container = builder.Build();
var userService1 = _container.Resolve<IUserService1>();
var userService2 = _container.Resolve<IUserService2>();
var userService3 = _container.Resolve<IUserService3>();
var anotherService = _container.Resolve<IAnotherService>();
var vm = new MainController(userService1,userService2,userService3,anotherService)
}
public class MainController
{
private UserController1 _userVM1;
private UserController2 _userVM2;
private UserController3 _userVM3;
public MainController(IUserService1 userService1,IUserService2 userService2,IUserService3 userService3,anotherService)
{
_userVM1 = new UserController1(userService1,anotherService);
_userVM2 = new UserController2(userService2,...,...);
_userVM3 = new UserController3(userService3,...,...,...);
}
}
// Such a Controller class needs to be created 10 times... and what I do here is typical for all Controllers driving the GUI
public class UserController1
{
private readonly IUserService1 _userService1;
public UserController1(IUserService1 userService1,IAnotherService anotherService)
{
_userService1 = userService1;
//Bind data to GUI
UserData1Collection = ConvertModelIntoViewModelCollection(userService1,anotherService);
}
public ObservableCollection<UserData1> UserData1Collection { get; set; }
private ObservableCollection<UserData1ViewModel> ConvertModelIntoViewModelCollection(IAnotherService anotherService)
{
var userData1ViewModelCollection = new ObservableCollection<UserData1ViewModel>();
_userService1.GetUserData1().ForEach(user =>
{
userData1ViewModelCollection.Add(new UserData1ViewModel(user, anotherService,...));
});
return userData1ViewModelCollection;
}
}
Now the question:
There is a lot of falling through/passing trough services because I have to call services when for example properties of viewmodels change via lost_focus on gui controls.
Is that all right what I do? Do you see any disadvantage? Or how would you do it?
Update
That DI stuff is a massiv attack on my vicious habits :P
Did you meant it that way Can?
Btw. why should I do that controller factory? Why then not a ServiceFactory too... then we are back to the ServiceLocator...
How do I get now that controller instances in my MainViewModel? via extending the Constructor of my MVM with many additional params? ending up with 30 params? ...
protected override void OnStartup(StartupEventArgs e)
{
IContainerBuilder builder = new ContainerBuilder();
// Firstly Register ALL existing Services
builder.Register<IAdminService, AdminService>();
builder.Register<IDocumentService, DocumentService>();
builder.Register<ILessonPlannerService, LessonPlannerService>();
builder.Register<IMediator, Mediator>();
builder.Register<IMainRepository, MainRepository>();
builder.Register<MainViewModel>();
IContainer _container = builder.Build();
// THEN Register ALL Controllers needing the previously registered Services
IControllerFactory factory = new ControllerFactory(builder);
IDailyPlanner controller1 = factory.Create<IDailyPlanner>();
IWeeklyPlanner controller2 = factory.Create<IWeeklyPlanner>();
SchoolclassAdministrationViewModel controller3 = factory.Create<SchoolclassAdministrationViewModel>();
// THEN Register the mainViewModel(MainController) which should take ALL Services and ALL Controller... WOW thats a massive Ctor param count... is that pure? Did you mean it that way???
MainViewModel mainViewModel = _container.Resolve<MainViewModel>();
//MainWindow mainWindow = _container.Resolve<MainWindow>();
//mainWindow.DataContext = mainViewModel;
//mainWindow.ShowDialog();
}
public class ControllerFactory : IControllerFactory
{
private readonly IContainerBuilder _builder;
private readonly IContainer _container;
/// <summary>
/// Takes the IOC container to register all Controllers
/// </summary>
public ControllerFactory(IContainerBuilder builder)
{
_builder = builder;
_builder.Register<SchoolclassAdministrationViewModel>();
_builder.Register<IDailyPlanner, LessonPlannerDailyViewModel>();
_builder.Register<IWeeklyPlanner, LessonPlannerWeeklyViewModel>();
_container = _builder.Build();
}
/// <summary>
/// Returns an Instance of a given Type
/// </summary>
public T Create<T>()
{
return _container.Resolve<T>();
}
}
Update2:
Now I changed my code that the MainViewModel accepts the IControllerFactory as Parameter and added these two lines of code to the App class:
builder.Register<IControllerFactory, ControllerFactory>();
builder.Register<IContainerBuilder, ContainerBuilder>();
That way I dont need to pass all controllers in the MainViewModel Ctor instead the MainViewModel gets the controller instances from the Factory.
Is there anything better I can do here? Or is that an acceptable good solution? I have no experience at all with DI so I ask :)
Update3
OK I did some code refactoring and made comments for others so they understand whats the final solution:
protected override void OnStartup(StartupEventArgs e)
{
IContainerBuilder builder = new ContainerBuilder();
// Firstly Register ALL existing Services
builder.Register<IAdminService, AdminService>();
builder.Register<IDocumentService, DocumentService>();
builder.Register<ILessonPlannerService, LessonPlannerService>();
builder.Register<IMediator, Mediator>();
builder.Register<IMainRepository, MainRepository>();
builder.Register<IControllerFactory, ControllerFactory>();
builder.Register<IDailyPlanner, LessonPlannerDailyViewModel>();
builder.Register<IWeeklyPlanner, LessonPlannerWeeklyViewModel>();
// Just for visual separation THEN register the MainController driving all other Controllers created via the IControllerFactory
builder.Register<MainViewModel>();
// Build the container
IContainer container = builder.Build();
// THEN Register the MainController which should take ALL IServices and the IFactory
MainViewModel mainViewModel = container.Resolve<MainViewModel>();
// LATER in the mainViewModel`s Ctor you can create all 10 Controller instances with the IControllerFactory like this
// _dailyPlannerController = controllerFactory.Create<IDailyPlanner>();
MainWindow mainWindow = new MainWindow();
mainWindow.DataContext = mainViewModel;
mainWindow.ShowDialog();
}
public class ControllerFactory : IControllerFactory
{
private readonly IContainer _container;
/// <summary>
/// Takes the IOC container to resolve all Controllers
/// </summary>
public ControllerFactory(IContainer container)
{
_container = container;
}
/// <summary>
/// Returns an Instance of a given Type
/// </summary>
public T Create<T>()
{
return _container.Resolve<T>();
}
}
Thank you very much for your time, #Can. I have learned a lot!
It seems to me that you have misunderstood how to use an IoC container. Instead of creating instances of your services and passing them as parameters, you need to ask the container to resolve them for you.
For example, you can refactor your code as follows to make use of IoC properly:
protected void Application_Start(object sender, EventArgs e)
{
var builder = new ContainerBuilder();
builder.Register<IUserService1, UserService1>();
builder.Register<IUserService2, UserService2>();
builder.Register<IUserService3, UserService3>();
builder.Register<IAnotherService, AnotherService>();
builder.Register<MainController, MainController>();
// And many more Services...
_container = builder.Build();
//let the container inject all the required dependencies into MainController..
var vm = _container.Resolve<MainController>();
}
The container in this case should control the lifecycle of your MainController object and make sure that all the dependencies (properties and constructor parameters that need to be initialized) are injected and populated.
What will happen is that the container will understand that to create an instance of MainController, it needs IUserService1, IUserService2 and so forth, and in turn will look if it can create any instances of those, by looking at the other types registered with the container. This will be done in a recursive manner to build up a dependency tree until all the dependencies of a class can be satisified. The resulting MainController you get will already have all the dependencies injected in it.
Ideally, you should call Resolve() in as little places as possible in order to structure your application in a way that there is only one root. For an in depth view into Dependency Injection, I strongly recommend the book Dependency Injection in .NET by Mark Seeman, which is in my opinion one of the best introduction to DI one can have.
UPDATE:
The reason why I suggested to use a ControllerFactory was because you had a lot of UserController classes in your MainController, and passing all those as a dependency you would end up with 10+ constructor parameters, not to mention that having to add more when you create new controllers. If your viewmodels only have dependency on one controller, then it doesn't make sense to use the factory in that way and you can have a direct dependency on the required controller.
As for ServiceFactory, it is not needed, because each of your classes are not likely to require ALL the service classes available, just some of them. In that case it is better to specify them explicitly for each service in the constructor.
You should also register all your instances in one place (or in small installer classes) instead of within constructor for different classes.
Here's a question that is more specific to MVVM that should get you going on how to structure your classes and dependencies:
How can I combine MVVM and Dependency Injection in a WPF app?

Categories