I am trying to implement Dependency injection in my Global.asax file. Below is the code-
public class MvcApplication : System.Web.HttpApplication
{
private readonly IJobTimerBS _objTimer;
// want to replace this constructor injection code. How ????
//public MvcApplication(IJobTimerBS jobTimerBS)
//{
// _objTimer = jobTimerBS;
//}
protected void Application_Start()
{
UnityConfig.RegisterComponents();
processingTimer_Elapsed();
}
void processingTimer_Elapsed()
{
_objTimer.QuoteDeleteJobTimer();
}
}
Code in Business layer-
public class JobTimerBS : IJobTimerBS
{
private readonly IUnitofWork _unitOfWork;
private IJobTimerRepository _jobTimerRepository;
public JobTimerBS(IJobTimerRepository jobTimerRepository, IUnitofWork unitOfWork)
{
_unitOfWork = unitOfWork;
_jobTimerRepository = jobTimerRepository;
_jobTimerRepository.UnitOfWork = unitOfWork;
}
public void QuoteDeleteJobTimer()
{
_jobTimerRepository.JobTimer();
}
}
My question is how can I implement the dependency injection in this case when I can't use constructor injection. How to instantiate the JobTimerBS class in Global.asax present in Business layer.
Related
This is going to be a bit lengthy, so hold on tight.
I have a project that uses Caliburn.Micro to implement MVVM pattern. For IoC, I am using MEF. All the ViewModels are marked with attribute [Export(typeof(IScreen))] . IScreen is defined in Caliburn.Micro.
In my BootStrapper file I have set up MEF like so:
private CompositionContainer container;
protected override void Configure()
{
//Set up MEF
container = new CompositionContainer(new AggregateCatalog``AssemblySource.Instance.Select``(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));
var batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(container);
container.Compose(batch);
//Other stuff
}
Now, I show the first ViewModel using
protected override void OnStartup(object sender, StartupEventArgs e) => DisplayRootViewFor<ViewModels.Main.MainViewModel>();
All that is fine and dandy. Now, the problem starts when I want to switch from one ViewModel to another.
An example of a ViewModel is :
[PartCreationPolicy(CreationPolicy.NonShared), Export(typeof(IScreen))]
sealed class SampleViewModel: ScreenVMwithUoW<IAddItemUoW>
{
[ImportingConstructor]
public SampleViewModel(IAddItemUoW uow, IEventAggregator eventAggregator) : base(uow, eventAggregator)
{
}
//bla bla bla
}
Let's say I want to open SampleViewModel and close my MainViewModel. How do I do it using MEF?
Here is what I am doing now:
[Export(typeof(IScreenFactory))]
class ScreenFactory : IScreenFactory
{
private Dictionary<Type, ExportFactory<IScreen>> _screenDictionary { get; set; }
private IEnumerable<ExportFactory<IScreen>> _screenfactoryCollection { get; set; }
private ExportLifetimeContext<IScreen> _currentScreenLifeTimeCtx { get; set; }
[ImportingConstructor]
public ScreenFactory([ImportMany(AllowRecomposition = true)] IEnumerable<ExportFactory<IScreen>> screenList)
{
_screenfactoryCollection = screenList;
_reportfactoryCollection = reportsList;
}
public IScreen GetScreen(Type t)
{
if (_screenDictionary == null)
{
PopulateScreenDictionary(_screenfactoryCollection);
}
_currentScreenLifeTimeCtx = _screenDictionary[t].CreateExport();
return _currentScreenLifeTimeCtx.Value;
}
private void PopulateScreenDictionary(IEnumerable<ExportFactory<IScreen>> screenfactories)
{
_screenDictionary = screenfactories.ToDictionary(c => c.CreateExport().Value.GetType(), c => c);
}
public void DisposeCurrentScreenContext()
{
_currentScreenLifeTimeCtx?.Dispose();
}
public void Dispose()
{
DisposeCurrentScreenContext();
}
}
Whenever I need a new instance of a ViewModel, I just do:
DeactivateItem(ActiveItem, true);
_vmFactory.DisposeCurrentScreenContext();
ActivateItem(_vmFactory.GetScreen(NextViewModelName));
This CANNOT be the normal way to do so. Also, this also adds a huge hit in performance, especially the startup time of the application, when the number of ViewModels increase to about 25-30.
I would also like to avoid the Service Locator Pattern, if possible. I am also open to using a proper IoC Container instead of MEF, but MEF allows me to add ViewModels with very little effort. Just adding the annotation [Export(typeof(IScreen))] does the job.
I have implemented the Repository pattern in my WinForms Application:
UnitOfWork:
using RCCGSPP.Core;
using RCCGSPP.Persistence.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
namespace RCCGSPP.Persistence
{
//Implements the Logic for Methods in the IUnitOfWork Interface
public class UnitOfWork
{
//Our App contextClassName
private readonly SPPContext _context;
private DbContext dbContext;
//Recieves our App ContextClassName
public UnitOfWork(SPPContext context)
{
//stores our App ContextName in _context
_context = context;
//Then uses the context to initialise both Repositories
Persons = new PersonRepository(_context);
SundayServices = new SundayServiceRepository(_context);
UserPasses = new UserRepository(_context);
NewComers = new NewComerRepository(_context);
}
public UnitOfWork(DbContext dbContext)
{
this.dbContext = dbContext;
}
//properties
public PersonRepository Persons { get; private set; }
public SundayServiceRepository SundayServices { get; private set; }
public UserRepository UserPasses { get; private set; }
public NewComerRepository NewComers { get; private set; }
//Calls the SaveChanges on the Context
public int Complete()
{
return _context.SaveChanges();
}
//Implementation of the Dispose Method to Dispose the Context
public void Dispose()
{
_context.Dispose();
}
}
}
My Form whwere I want to use my UnitOfWork, I have declared it as a readonly property so I have included it in the contructor to initialise it but since by form is load from another at the click of a Button I get "There is no argument given that corresponds to the required formal parameter 'unitOfWork'"
Form Where To Use UNITOFWORK
public partial class Register : MaterialForm
{
private readonly IUnitOfWork _unitOfWork;
string userName;
string psswrd;
string Confirmpsswrd;
public Register(IUnitOfWork unitOfWork)
{
InitializeComponent();
//Set your preferred colors &theme (Material Skin)
var materialSkinManager = MaterialSkinManager.Instance;
materialSkinManager.AddFormToManage(this);
materialSkinManager.Theme = MaterialSkinManager.Themes.DARK;
materialSkinManager.ColorScheme = new ColorScheme(Primary.Blue400, Primary.Red900, Primary.Brown900, Accent.LightBlue200, TextShade.BLACK);
//prevent Form from Resizing
Sizable = false;
//UnitOfWork
_unitOfWork = unitOfWork;
}
private void Register_Load(object sender, EventArgs e)
{
}
private void btnSubmit_Click(object sender, EventArgs e)
{
//Get the User email and Password to register in the DB
userName = textEmail.Text;
psswrd = textPassword.Text;
Confirmpsswrd = textConfirmPassword.Text;
//Compare the password
bool conRes = ComparePassword(psswrd, Confirmpsswrd);
if (conRes)
{
//Insert to db using the UnitOfWork
UserPass userToDb = new UserPass
{
UserName = this.userName,
password = this.psswrd,
};
_unitOfWork.UserPasses.Add(userToDb);
//Commit calling complete()
_unitOfWork.Complete();
//FeedBack Registered Sucessfull
LabelErrorPassword.Text = "Successful, Login!";
}
else
{
LabelErrorPassword.BackColor = Color.Red;
LabelErrorPassword.Text = "The Passwords don't match!"; //show in the Label that password are not the same
}
}
/**********Method to compare Password**********************/
public bool ComparePassword(string pss1, string pss2)
{
if (pss1.Equals(pss2))
{
return true;
}
else return false;
}
}
lOADING MY fORM :
private void BtnRegister_Click(object sender, EventArgs e)
{
//lOAD THE rEGISTER fORM,
Register nForm = new Register();
nForm.Show();
}
How can I make use of my UnitOfWork in my WinForm Application.
As #stuartd said, the parameterless contructor for a Form in WinForms is recommended. But of course you can add a constructor with arguments.
public Register()
{
InitializeComponent();
//Set your preferred colors &theme (Material Skin)
var materialSkinManager = MaterialSkinManager.Instance;
materialSkinManager.AddFormToManage(this);
materialSkinManager.Theme = MaterialSkinManager.Themes.DARK;
materialSkinManager.ColorScheme = new ColorScheme(Primary.Blue400, Primary.Red900, Primary.Brown900, Accent.LightBlue200, TextShade.BLACK);
//prevent Form from Resizing
Sizable = false;
//UnitOfWork, not initialized here
//_unitOfWork = unitOfWork;
}
public Register(IUnitOfWork unitOfWork) : this() // call default constructor!
{
_unitOfWork = unitOfWork;
}
I strongly recommend to leave all the auto-generated and custom initialization code in the default (parameterless) constructor. So, the WinForms designer does not stop working.
We use this strategy in combination with DI containers in several projects without any problem.
Thank You all.
I have used the Simple Ijector package to Inject the UnitOfWork into my Program.cs as Follow:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
//Get instance of my Registered HomeForm
Application.Run((container.GetInstance<Home>()));
}
private static void Bootstrap()
{
// Create the container as usual.
container = new Container();
// Register my types, for instance:
container.Register<UnitOfWork, UnitOfWork>();
//Register my HomeForm
container.Register<Home>();
// Optionally verify the container.
//container.Verify();
}
}
Then in my Principal Form: I injected the registered UnitOfWork in it's constructor:
//Declare my UnitOfwORK
private readonly UnitOfWork _unitOfWork;
public Home(UnitOfWork unitOfWork)
{
InitializeComponent();
this._unitOfWork = unitOfWork;
}
Then I pass it to the New Register Form that will be loaded at the click of the Register Button, inside of which I will use the UnitOfWork to persist and commit to the DB
//lOAD THE rEGISTER fORM,
Register nForm = new Register(this._unitOfWork);
nForm.Show();
}
Finally in the Register I use this UnitOfWork to perform my CRUD Operations and Commit to the DB:
public partial class Register : MaterialForm
{
//Declare my UnitOfwORK
private readonly UnitOfWork _unitOfWork;
string userName;
string psswrd;
string Confirmpsswrd;
//I Inject IUnitOfOfClass with the Help of Simple Injector dependency injection library
public Register(UnitOfWork unitOfWork)
{
InitializeComponent();
//Set your preferred colors &theme (Material Skin)
var materialSkinManager = MaterialSkinManager.Instance;
materialSkinManager.AddFormToManage(this);
materialSkinManager.Theme = MaterialSkinManager.Themes.DARK;
materialSkinManager.ColorScheme = new ColorScheme(Primary.Blue400, Primary.Red900, Primary.Brown900, Accent.LightBlue200, TextShade.BLACK);
//prevent Form from Resizing
Sizable = false;
_unitOfWork = unitOfWork;
}
private void SetUnitOfWork()
{
}
private void Register_Load(object sender, EventArgs e)
{
}
private void btnSubmit_Click(object sender, EventArgs e)
{
//Get the User email and Password to register in the DB
userName = textEmail.Text;
psswrd = textPassword.Text;
Confirmpsswrd = textConfirmPassword.Text;
//Compare the password
bool conRes = ComparePassword(psswrd, Confirmpsswrd);
if (conRes)
{
//Insert to db using the UnitOfWork
UserPass userToDb = new UserPass
{
UserName = this.userName,
password = this.psswrd,
LastAcess = DateTime.Now
};
_unitOfWork.UserPasses.Add(userToDb);
//Commit calling complete()
_unitOfWork.Complete();
//FeedBack Registered Sucessfull
LabelErrorPassword.Text = "Successful, Login!";
}
else
{
LabelErrorPassword.BackColor = Color.Red;
LabelErrorPassword.Text = "The Passwords don't match!"; //show in the Label that password are not the same
}
}
/**********Method to compare Password**********************/
public bool ComparePassword(string pss1, string pss2)
{
if (pss1.Equals(pss2))
{
return true;
}
else return false;
}
}
It might not be the best way to implement it but It works absolutely fine, I have tested it and I could see the data in the database.
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.
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?
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;
}
}