I am using MvvmCross' IoC property injection, initialized in my respective Setup.cs-classes:
protected override IMvxIocOptions CreateIocOptions()
{
return new MvxIocOptions {
PropertyInjectorOptions = MvxPropertyInjectorOptions.All
};
}
In my view models I then have several public interface properties like this:
public void IDataService DataService { get; set; }
Everything works when I run the app, but the unit tests fail because DataService is null.
How can I set up property injection correctly when using MvxIoCSupportingTest?
Got it working based on Stuart's answer, which I had to modify to avoid private fields and methods:
protected new IMvxIoCProvider Ioc { get; private set; }
protected override void ClearAll()
{
// fake set up of the IoC
MvxSingleton.ClearAllSingletons();
var iocOptions = new MvxIocOptions {
PropertyInjectorOptions = MvxPropertyInjectorOptions.All
};
Ioc = MvxSimpleIoCContainer.Initialize(iocOptions);
Ioc.RegisterSingleton(Ioc);
Ioc.RegisterSingleton<IMvxTrace>(new TestTrace());
MvxSingletonCache.Initialize();
Ioc.RegisterSingleton<IMvxSettings>(new MvxSettings());
MvxTrace.Initialize();
AdditionalSetup();
}
I also submitted a pull request for overriding CreateIocOptions directly, which would make it easier: https://github.com/MvvmCross/MvvmCross/pull/897/files
To override the Ioc options used in MvxIoCSupportingTest, you'll need to override ClearAll():
protected override void ClearAll()
{
// fake set up of the IoC
MvxSingleton.ClearAllSingletons();
_ioc = MvxSimpleIoCContainer.Initialize(/* YOUR OPTIONS HERE */);
_ioc.RegisterSingleton(_ioc);
_ioc.RegisterSingleton<IMvxTrace>(new TestTrace());
InitializeSingletonCache();
InitializeMvxSettings();
MvxTrace.Initialize();
AdditionalSetup();
}
from https://github.com/MvvmCross/MvvmCross/blob/3.5/Cirrious/Test/Cirrious.MvvmCross.Test.Core/MvxIoCSupportingTest.cs#L33
It would definitely be nicer if that Test class had a CreateIoCOptions() virtual method instead.
It must be showing error:
Failed to construct and initialize ViewModel for type Viewmodel. You might be missing :
public override void Initialize() {
CreatableTypes()
.EndingWith("Service")
.AsTypes()
.RegisterAsSingleton();
}
For detailed reference you can check out following link.
https://stackoverflow.com/a/18946672/4373895
Hope this helps you.
Related
I'm currently trying to work with dependency injection and so far I love. But it's one thing I can't really get my head around and where my current solution just seems wrong.
I'm working with WPF, MVVM and many of the classes I inject need an instance of a project configuration class that isn't initialized until the user create or open a new project in the application.
So my current solution is to have a "ConfigurationHandler" with load/save method and a property that hold an instance of the configuration class after it's loaded. I inject ConfigurationHandler to the others classes and then they can access the configuration after it's loaded. But it seems weird to let classes that never should save/load configuration handle the whole "ConfigurationHandler" and 100% they would just use it to access the configuration instance likt this:
var configuration = configurationHandler.Configuration;
Another problem is that if they try to access the configuration before it's loaded they will get exception (should not really happen as you can't do anything before a project is created/loaded, but still).
But the only other solution I can think of is to use "intialize" methods after a project is created/open but that seems just as bad.
So how do you usually handle cases like this?
Edit: Should add that this configuration class handle information like project path, project name, etc so have nothing to do with the dependency injection itself.
If your configuration is static (read: It's only read during startup of your application, such as from project.json or Web.Config), you can also set it during app startup/the composition root.
The new ASP.NET 5 uses it heavily and it works very well. Basically you will have an IConfiguration<T> interface and a POCO class, which you set up during the app startup and can resolve/inject it into your services.
public interface IConfiguration<T> where T : class
{
T Configuration { get; }
}
And it's default implementation
public interface DefaultConfiguration<T> where T : class
{
private readonly T configuration;
public T Configuration {
return configuration;
}
public DefaultConfiguration<T>(T config)
{
this.configuration = this.configuration;
}
}
And your POCO class
public class AppConfiguration
{
public string OneOption { get; set; }
public string OtherOption { get; set; }
}
In your composition root, you would then register it, like
// read Web.Config
Configuration rootWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);
container.AddSingleton<IConfiguration<AppConfiguration>>(new DefaultConfiguration<AppConfiguration>(
new AppConfiguration
{
OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
})
);
And finally, all you have to declare in your services is
public class MyService : IMyService
{
public MyService(IUserRepository, IConfiguration<AppConfiguration> appConfig)
{
...
if(appConfig.OneOption=="someValue") {
// do something
};
}
}
Finally you can make this a bit easier to configure, if you write an extension method like
public static class MyContainerExtension
{
public static void Configure<T>(this IMyContainer container, Action<T> config) where T : class, new()
{
var t = new T();
config(t);
container.AddSingelton<IConfiguration<T>>(t);
}
}
Then all you need to do is
container.Configure<AppConfiguration>(
config =>
{
config.OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
config.OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
})
);
to set it up
Instead of Constructor Injection, consider using an Ambient Context approach.
The last type of DI we’ll discuss is making dependencies available
through a static accessor. It is also called injection through the
ambient context. It is used when implementing cross-cutting concerns.
This is a good option if the classes that need access to your configuration are of different types in different layers or libraries - i.e. is a true cross-cutting concern.
(Quote source)
Example, based on the classic Time Provider one from [Dependency Injection in .NET][2]
abstract class CustomConfiguration
{
//current dependency stored in static field
private static CustomConfiguration current;
//static property which gives access to dependency
public static CustomConfiguration Current
{
get
{
if (current == null)
{
//Ambient Context can't return null, so we assign a Local Default
current = new DefaultCustomConfiguration();
}
return current;
}
set
{
//allows to set different implementation of abstraction than Local Default
current = (value == null) ? new DefaultCustomConfiguration() : value;
}
}
//service which should be override by subclass
public virtual string SomeSetting { get; }
}
//Local Default
class DefaultCustomConfiguration : CustomConfiguration
{
public override string SomeSetting
{
get { return "setting"; }
}
}
Usage
CustomConfiguration.Current.SomeSetting;
There are other DI Patterns that could be used, but require changes to the class that need it. If Configuration is a cross cutting concern Ambient Context could be the best fit.
Constructor Injection Example
public SomeClass(IConfiguration config)
{
}
Property Injection
public SomeClass()
{
IConfiguration configuration { get; set; }
}
Method Injection
public SomeClass()
{
public void DoSomethingNeedingConfiguation(IConfiguration config)
{
}
}
There is also Service Locator, but Service Locator is (IMO) an anti-pattern.
I Am very new to Caliburn and have to expand an existing program, using caliburn.micro
I need my DataContext in a View to be set to a ViewModel which has some propertyinjected parameters. All this should work, so i only need to build it up.
however it does not! here is the code where i try to bulid:
public ProductionMainView()
{
InitializeComponent();
var gg = IoC.Get<ProductionMainViewModel>();
IoC.BuildUp(gg);
this.DataContext = gg;
}
As far as i can understand I need to get the object and then build it.
Now I should get a view "Containing" my ViewModel, but the View is blank,
I hope i have explained myself well enough.
Best regards
First off you are using a really old version, present version is 2.0.2, and you still need to have overrides for GetInstance, GetAllInstances, BuildUp methods in your BootStrapper or a variant for use with Ninject
http://putridparrot.com/blog/caliburn-micro-and-inversion-of-control-using-ninject/
Link above has some source for this.
Remember there is nearly no code in the Codebehind of the View... It will all go into the ViewModels (for the most part). ShellView => ShellViewModel with in ShellViewModel var gg = IoC.Get<ProductViewModel>() depending on you are intent is with that you can bind it to a <ContentControl x:Name="ProductViewModel" /> with a property in yoru viewmodel called exactly that. CM will go out and fine that ViewModel and associated view and mash them together automagically. Expected results on the screen should be your ProductViewModel in that contentcontrol location.
public class ShellViewModel : Screen
{
private ProductViewModel _productViewModel;
public ShellViewModel (){
}
protected override void OnActivate(){
ProductViewModel = IoC.Get<ProductViewModel>();
}
public ProductViewModel ProductViewModel {
get{ return _productViewModel;}
set{
_productViewModel = value;
NotifyOfPropertyChanged (); // 2.0.2 feature...
}
}
}
Now, if you decide to move to the latest version there are subtle changes one Bootstrapper<T> does not exist anymore it was refactored into BootstrapperBase. Next Initialize() will be placed into the ctor of your Bootstrapper(). From there everything will be based on your starting screen is after Initialize() is called in the CTOR you will call DisplayRootViewFor<ShellViewModel>() in the OnStartup override.
Some have said and I tend to agree over using IoC.Get<T>() can be anti-pattern, caution when using it. Sometimes things change unexpectedly. Those tend to DI the items via the CTOR and use from there accordingly.
/*version 1.52*/
public class Bootstrapper : BootStrapper<LoginViewModel>{
public Bootstrapper(){
Start();
}
protected override Configure(){
/* -- your Ninject configurations -- */
}
protected override object GetInstance(Type service, string Key){
if(service == null)
throw new ArgumentNullException("Service");
return _kernel.Get(service);
}
protected override IEnumerable<object> GetAllInstances(Type service){
return _kernel.GetAll(service);
}
protected override void BuildUp(object instance){
_kernel.Inject(instance);
}
protected override void OnExit(object sender, EventArgs e)
{
kernel.Dispose();
base.OnExit(sender, e);
}
}
To clarify do you have to login to get to the ProductionMainViewModel? What determines your logic for getting to ProductionMainViewModel to even display?
I have a Web API project where I bind to all my classes.
//NinjectWebCommon.cs
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<DAL.IDAL>().To<DAL.MyDAL>();
kernel.Bind<BUS.IService>().To<BUS.MyService>();
kernel.Bind<DAL.IUser>().To<API.User>().InSingletonScope();
}
This works fine.
I tried to set up my Unit Tests for my DAL using the following.
//Test1.cs
public DAL.IDAL db { private get; set; }
[TestInitialize]
public void InitializeTests()
{
var kernel = new Ninject.StandardKernel();
db = kernel.Get<DAL.MyDAL>();
kernel.Bind<DAL.IUser>().To<Test.User>().InSingletonScope();;
}
I get the error
Error activating IUser
No matching bindings are available and the type is not self-bindable.
Activation Path:
2) Injection of dependency IUser into property user of type MyDAL
1) Request for MyDAL
I have IUser in the MyDAL class. I'm not sure exactly what is going on here.
//MyDAL.cs
public class MyDAL
{
[Inject]
public IUser user { get; set; }
//other functions
//...
}
"Flip" these 2 lines.
db = kernel.Get<DAL.MyDAL>();
kernel.Bind<DAL.IUser>().To<Test.User>().InSingletonScope();
Aka:
kernel.Bind<DAL.IUser>().To<Test.User>().InSingletonScope();
db = kernel.Get<DAL.MyDAL>();
You have to "define" things before you invoke.
OK, I figured it out. Thanks to this Cheat Sheet
Basically I need to specifically inject my value into my class.
public DAL.IDAL db { private get; set; }
[TestInitialize]
public void InitializeTests()
{
var kernel = new Ninject.StandardKernel();
db = kernel.Get<DAL.MyDAL>(new PropertyValue("user", new Test.User());
}
Injecting dependencies in Global.asax does not seem to always work. Sometimes it does, sometimes I get a ContextDisposedException (it seems that the problem occurs when I'm doing a Page.Redirect ??). I'm in an ASP.NET WebForm context.
Here is my code:
public class Global : HttpApplication
{
[Inject]
public UserManager UserManager { get; set; }
private void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
GlobalSecurityContext.SetPrincipal(User);
string path = Request.AppRelativeCurrentExecutionFilePath;
if (path.Contains(".aspx"))
{
// Get the current user
var userData = UserManager.GetByIdWithLogin(User.Identity.Name);
if (userData != null)
{
LoginDataDTO data = userData.LoginData;
if (data.XXX && ...)
{
Response.Redirect(...);
}
}
}
}
}
protected void Session_End(Object sender, EventArgs e)
{
UserManager.Logout();
}
}
In this post How to inject dependencies into the global.asax.cs, Mark Seemann says that one should not use Dependency Injection in global.asax because global.asax IS the Composition Root.
So what is the best way to solve my problem since I don't want to directly call my UserManager because the constructor needs a repository
public UserManager(IGenericRepository repository) : base(repository)
{
}
and the GenericRepository has itself a constructor that needs a IContext
public GenericRepository(IContext context)
{
}
I could probably do new UserManager(new GenericRepository(new MyContext)) but
I will not reuse the same context for the whole request
I need to add a reference on my AccessLayer in the GUI, what I would like to avoid
Just as an information, currently I'm injecting the Context like this:
// Dynamically load the context so that we dont have a direct reference on it!
string contextType = // read type from web.config
if (!String.IsNullOrEmpty(contextType))
{
Type context = Type.GetType(contextType);
Bind<IContext>().To(context).InRequestScope();
}
Any help would be greatly appreciated !
[Edit]:
Changing the UserProperty property like this works:
public UserManager UserManager
{
get { return ServiceLocator.Current.GetInstance<UserManager>(); }
}
In this case you can build your Ninject container, and use it a Service Locator for this particular instance (since you're in the Composition Root - you can't inject anything at this point).
Have been learning about MVP and have tried writing a test app using it in WinForms. I'm struggling to find a well explained example on how to navigate between my forms/views. As an example, the program starts and I want to show a login dialog then go into my main view if the login was successful. At the moment, my Main method looks something like this:
static void Main()
{
var loginView = Injector.Resolve<ILoginView>();
if (loginView.DoLogin() != LoginResult.OK) return;
var mainView = Injector.Resolve<IMainView>();
Application.Run(mainView); // won't work as mainView isn't a form
}
The Injector object is just a wrapper around an IoC tool (currently StructureMap). The thing is, I've read that I shouldn't really be manually creating instances via the Injector as they should really be done via constructor injection.
I've managed to do this up to a point but not when it comes to navigation. I can't think of an elegant way of moving through my views and was wondering if anyone here might shed some light on this? I've read a little on application controllers but have not found an example to show it clearly.
In regards to the navigation question:
I've managed to do this up to a point but not when it comes to
navigation. I can't think of an elegant way of moving through my views
and was wondering if anyone here might shed some light on this? I've
read a little on application controllers but have not found an example
to show it clearly.
Below is a simplified version of a construct I've used. Note that the setup and tear down hooks are called automatically when the NavigateTo method is called. Also, +1 to #AlexBurtsev, as his answer hints at this very same approach.
// Presenter can and should offer common services for the
// subclasses
abstract class Presenter
{
public void Display()
{
OnDisplay();
}
public void Dismiss()
{
OnDismiss();
}
protected virtual OnDisplay() // hook for subclass
{
}
protected virtual OnDismiss() // hook for subclass
{
}
private NavigationManager _navMgr;
internal NavigationMgr NavigationManager
{
get
{
return _navMgr;
}
set
{
_navMgr = value;
}
}
}
// NavigationManager is used to transition (or navigate)
// between views
class NavigationManager
{
Presenter _current;
// use this override if your Presenter are non-persistent (transient)
public void NavigateTo(Type nextPresenterType, object args)
{
Presenter nextPresenter = Activator.CreateInstance(nextPresenterType);
NavigateTo(nextPresenter);
}
// use this override if your Presenter are persistent (long-lived)
public void NavigateTo(Presenter nextPresenter, object args)
{
if (_current != null)
{
_current.Dismiss()
_current.NavigationMgr = null;
_current = null;
}
if (nextPresenter != null)
{
_current = nextPresenter;
_current.NavigationMgr = this;
_current.Display(args);
}
}
}
class MainMenuPresenter : Presenter
{
private IMainMenuView _mainMenuView = null;
// OnDisplay is your startup hook
protected override void OnDisplay()
{
// get your view from where ever (injection, etc)
_mainMenuView = GetView();
// configure your view
_mainMenuView.Title = GetMainTitleInCurrentLanguage();
// etc
// etc
// listen for relevent events from the view
_mainMenuView.NewWorkOrderSelected += new EventHandler(MainMenuView_NewWorkOrderSelected);
// display to the user
_mainMenuView.Show();
}
protected override void OnDismiss()
{
// cleanup
_mainMenuView.NewWorkOrderSelected -= new EventHandler(MainMenuView_NewWorkOrderSelected);
_mainMenuView.Close();
_mainMenuView = null;
}
// respond to the various view events
private void MainMenuView_NewWorkOrderSelected(object src, EventArgs e)
{
// example of transitioning to a new view here...
NavigationMgr.NavigateTo(NewWorkOrderPresenter, null);
}
}
class NewWorkOrderPresenter : Presenter
{
protected override void OnDisplay()
{
// get the view, configure it, listen for its events, and show it
}
protected override void OnDismiss()
{
// unlisten for events and release the view
}
}
I haven't used WinForms for a long time, but I'll try to answer this. I would use the same strategy as WPF Prism do.
About MainView and Application.Run:
Create a main Region (root Form), with empty container inside which can hold UserControl (I forgot exact class names), then when you need to switch root view, you do RootView.SetView(UserControl view) which will do something like Form.Clear(), Form.AddChild(view).
About the navigation and using container:
You could create a service for navigation: INavigationService which you inject in constructors with method like INavigationService.NavigateView(String(or Type) viewName, params object[] additionalData)
You can insert a method in mainView that returns the actual form.Then you can call
Mainview:IMainView
{
Form GetView()
{
//return new Form();
}
}
In Main you can call ,
Application.Run(mainView.GetView())