I use unity container in my WinForms application and register interfaces and classes. but when open other forms it's not working for fetching data. It's just working for form1.
How to resolve all forms?
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
RegisterType(new UnityContainer());
}
public static void RegisterType(IUnityContainer container)
{
container.RegisterType<IBlogRepository, BlogRepository>();
container.RegisterType<IPostRepository, PostRepository>();
Application.Run(container.Resolve<Form1>());
}
}
This is constructor injection in form1():
public partial class Form1: Form
{
public Form1()
{
InitializeComponent();
}
private readonly IBlogRepository _blogRepository;
public Form1(IBlogRepository blogRepository) : this()
{
_blogRepository = blogRepository;
}
}
and this is constructor injection in formAddUpdate():
public partial class FormAddUpdate : Form
{
public FormAddUpdate()
{
InitializeComponent();
}
private readonly IBlogRepository _blogRepository;
private readonly IPostRepository _postRepository;
public FormAddUpdate(IBlogRepository blogRepository, IPostRepository postRepository) : this()
{
_blogRepository = blogRepository;
_postRepository = postRepository;
}
}
now when the run application I can retrieve data from from1 but when switch to add/update form, it returns error: {"Object reference not set to an instance of an object."}
How to resolve all forms in my application?
If you look at your code, you resolve exactly one type (Form1) from your container. After that, poor container dies.
RegisterType(new UnityContainer());
}
public static void RegisterType(IUnityContainer container)
{
container.RegisterType<IBlogRepository, BlogRepository>();
container.RegisterType<IPostRepository, PostRepository>();
Application.Run(container.Resolve<Form1>());
}
When you create another container somewhere else to resolve, say, Form2 it knows nothing of the registrations made with the first container, so it can resolve neither BlogRepository nor PostRepository.
So the solution is to keep the one and only container around, the one that you do all registrations with. And use that one to do all your resolving, preferentially not by passing the container around or referencing a static service locator, but instead resolve just one root object and inject factories that do all the resolving needed.
Related
I have a form1 (not mdi) which displays dialog on button click event, dialog basically is a pop up form which shows data on datagridview control.
I am using simple injector.
PopUpForm has a property called LocationData which is a datatable. I need to set that property in form1 (parent) so that data can be displayed on the PopUpForm when it is displayed on the screen.
Sorry, i am new to simple injector and still learning, any help or guidence would be appreciated. I even don't know if i am doing in a right way.
form1
On button click event
this._formOpener.ShowModalForm<PopUpForm>();
PopUpForm
public partial class PopUpForm : Form
{
public DataTable LocationData { get; set; }
public PopUpForm()
{
InitializeComponent();
}
private void PopUpForm_Load(object sender, EventArgs e)
{
dgvNearestLocations.DataSource = LocationData;
}
}
program class
static class Program
{
private static Container container;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(container.GetInstance<Form1>());
}
private static void Bootstrap()
{
// Create the container as usual.
container = new Container();
// Register your types, for instance:
container.RegisterSingleton<IFormOpener, FormOpener>();
container.Register<Form1>(Lifestyle.Singleton); ;
container.Register<PopUpForm>(Lifestyle.Singleton); ;
// Optionally verify the container.
container.Verify();
}
}
FormOpener
public class FormOpener : IFormOpener
{
private readonly Container container;
private readonly Dictionary<Type, Form> openedForms;
public FormOpener(Container container)
{
this.container = container;
this.openedForms = new Dictionary<Type, Form>();
}
public DialogResult ShowModalForm<TForm>() where TForm : Form
{
using (var form = this.GetForm<TForm>())
{
return form.ShowDialog();
}
}
private Form GetForm<TForm>() where TForm : Form
{
return this.container.GetInstance<TForm>();
}
}
First of all, you copied the FormOpener probably from this answer. But you missed the part about Forms needing to be transient. Don't register your forms as Singleton. Especially because you dispose them, this will work one and exactly one time. The next time you would want to show a Form you will get an ObjectDisposedException.
When you register the Forms as Transient Simple Injector will tell you that the forms implement IDisposable and this is (of course) correct. But because you take care of disposing in the FormOpener you can safely suppress this warning. Register your forms like this:
private static void RegisterWindowsForms(
this Container container, IEnumerable<Assembly> assemblies)
{
var formTypes =
from assembly in assemblies
from type in assembly.GetTypes()
where type.IsSubclassOf(typeof(Form))
where !type.IsAbstract
select type;
foreach (var type in formTypes)
{
var registration = Lifestyle.Transient.CreateRegistration(type, container);
registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
"Forms are disposed by application code. Letting Simple Injector do this " +
"is problematic because that would need a scope, which is impossible to do.");
container.AddRegistration(type, registration);
}
}
To come to your question:
What you need is some extra infrastructure to initialize the Form.
By letting your forms implement an interface IFormInit<T> you can pass data to the form and directly show it.
public interface IFormInit<T> : IDisposable
{
DialogResult InitAndShowForm(T data);
}
To let Simple Injector create the forms based on this interface we need to register them in the container. We can let Simple Injector search for all closed implementations by supplying a list of assemblies, like this:
container.Register(typeof(IFormInit<>), assemblies, Lifestyle.Transient);
Notice that Simple Injector will automatically merge these registrations with the ones from RegisterWindowsForms. So you can now get an instance of Form by calling:
container.GetInstance<PopupForm>();
or
container.GetInstance<IFormInit<SomeDataClass>>();
You can now add this code to your FormOpener class:
public DialogResult ShowModalForm<TData>(TData data)
{
Type formType = typeof(IFormInit<>).MakeGenericType(typeof(TData));
dynamic initForm = this.container.GetInstance(formType);
DialogResult result = (DialogResult) initForm.InitAndShowForm(data);
initForm.Dispose();
return result;
}
This will get the Form from the container based on the IFormInit<T> type that it implements. When you get the form, you call the function on the interface instead of directly call Form.ShowDialog(). When the form is closed you dispose of the Form.
Note: The use of dynamic typing maybe needs clarification. Why it is needed is inspired by the QueryHandler pattern described here.
Usage is as follows:
// Add a specific class to pass to the form
public class LocationDataWrapper
{
public DataTable LocationData { get; set; }
}
public partial class PopUpForm : Form, IFormInit<LocationDataWrapper>
{
public PopUpForm() => InitializeComponent();
// Implement the interface, the loaded event can be removed
public DialogResult InitAndShowForm(LocationDataWrapper data)
{
dgvNearestLocations.DataSource = data.LocationData;
return this.ShowDialog();
}
}
On button click event
DialogResult result = this._formOpener.ShowModalForm(new LocationDataWrapper
{
LocationData = locationDataTable,
});
You can create wrapper or data classes for each form and it will automatically show the correct form, when you let this Form implement IFormInit<ThisSpecificDataClass>.
I have this class:
public class Observador : iObservador
{
private List<Form> Forms = new List<Form>();
public void DeSubscribirse(Form form)
{
Forms.Remove(form);
}
public void Limpiar()
{
Forms.Clear();
}
public void Subscribirse(Form form)
{
Forms.Add(form);
}
public List<Form> DevolverSubscriptos()
{
return this.Forms;
}
}
Which is used on a base form I have like this:
public partial class FormBase : Form
{
public EE.Observador Watcher = new Observador();
public FormBase()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.Hide();
}
}
Which I use for the rest of my forms to be inherited from.
My idea is to have in all the forms a reference to the object Watcher from every place, with it having a reference for every form which is subscribed to it. So I can do for example, from FormB know that FormA is already subscribed with the method DevolverSubscriptos() (this means return subscribers) and access it to make it visible again after closing FormB.
The problem is that when I start FormB the list of Watcher with the whole forms is set back to 0.
What am I doing wrong? How can I solve it?
public partial class AdminUIGI : FormBase.FormBase
That's how I reference it.
Short answer: you're using an instance field. Each form is a separate instance, hence each has it's own copy of the EE.Observador.
So a quick and dirty fix would be to make this field static, i.e. shared by all instances of the given class. And if you want to improve, you might then consider reading about the Singleton pattern (mainly because you'll see it used a lot - but read on :) ), then read why using Singleton as a global variable is in fact an anti-pattern and move on to reading about dependency injection and IoC - which is how (in vacuum at least) your code should probably end up. (Note: for a quick and dirty solution static field is all you need).
#decPL I made it work with the singleton pattern doing this ` public sealed class Singleton
{
Singleton()
{
}
private static readonly object padlock = new object();
private static Singleton instance = null;
public static EE.Observador watcher = new Observador();
private Usuario userInstance = null;`
I am having to re-write a large WinForms application and I want to use MVC to allow increased testing capability etc. I want to also adopt Ninject as my IoC container as it is lightweight, fast and will increase the exstensibility of my application going forward.
I have done a great deal of reading and I have managed to make a start on the arcitecture of this new application. However, I am not sure i have the right idea when using Ninject. The code...
Starting with Program.cs and related classes...
static class Program
{
[STAThread]
static void Main()
{
FileLogHandler fileLogHandler = new FileLogHandler(Utils.GetLogFilePath());
Log.LogHandler = fileLogHandler;
Log.Trace("Program.Main(): Logging initialized");
CompositionRoot.Initialize(new ApplicationModule());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(CompositionRoot.Resolve<ApplicationShellView>());
}
}
public class CompositionRoot
{
private static IKernel _ninjectKernel;
public static void Initialize(INinjectModule module)
{
_ninjectKernel = new StandardKernel(module);
}
public static T Resolve<T>()
{
return _ninjectKernel.Get<T>();
}
}
public class ApplicationModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IApplicationShellView)).To(typeof(ApplicationShellView));
}
}
An my ApplicationShellView is
public partial class ApplicationShellView : Form, IApplicationShellView
{
public ApplicationShellView()
{
InitializeComponent();
}
public void InitializeView()
{
dockPanel.Theme = vS2012LightTheme;
}
}
with interface
public interface IApplicationShellView
{
void InitializeView();
}
The controller for this view is
public class ApplicationShellController
{
private IApplicationShellView view;
public ApplicationShellController(IApplicationShellView view)
{
view.InitializeView();
}
}
Currently the controller is redundant, and although this code works and my view displays, I have some important questions...
Should I be using the ApplicationShellController to initialize my form, currently this is not using MVC "pattern"?
It feels like I have written a Service Locator, and from what I have read, this is bad. How else should I be using Ninject for IoC to initialize my application?
Any other advice as to what I am doing right[if anything!]/wrong?
Thanks very much for your time.
No you should not be initializing your controller, this exactly what IoC and Ninject are for. When you initialize your view/form, Ninject should make the view fetch the controller it depends on, which will auto fetch controllers it depends on and so on.
Of course this won't work like you've set it up right now. For starters, your view needs to know the controller it depends on.
public partial class ApplicationShellView : Form, IApplicationShellView
{
private IApplicationShellController _controller;
public ApplicationShellView()
{
InitializeComponent();
init();
//InitializeView()
}
private void init() {
_controller = NinjectProgram.Kernel.Get<IApplicationShellController>();
//Because your view knows the controller you can always pass himself as parameter or even use setter to inject
//For example: _controller.SetView1(this);
}
public void InitializeView()
{
dockPanel.Theme = vS2012LightTheme;
}
}
public class ApplicationShellController : IApplicationShellController
{
//Implementes functionality for the MainForm.
public ApplicationShellController()
{
//Also possible to add other controllers with DI
}
}
This does indeed look like a Service Locator, simply initializing your view should do be sufficient.
public class NinjectProgram
{
//Gets the inject kernal for the program.
public static IKernel Kernel { get; protected set; }
}
public class Program : NinjectProgram
{
[STAThread]
private static void Main()
{
Kernel = new StandardKernel();
Kernel.Load(new ApplicationModule());
Application.Run(new ApplicationShellView());
}
}
public class ApplicationModule : NinjectModule
{
public override void Load()
{
//Here is where we define what implementations map to what interfaces.
Bind<IApplicationShellController>().To<ApplicationShellController>();
//We can also load other modules this project depends on.
Kernel.Load(new NinjectModule());
}
}
Don't try and make it too complicated, a good start is important but you can always apply changes when and where needed during development.
I believe the following GitHub project might be a good starting point: Example of how you might use Ninject within a WinForms application.
If you have any more questions, just leave a comment and I'll try to answer them as soon as possible
I have a very simple C# Windows Forms application that I have decided to convert to use Dependency Injection via Ninject.
The entry point for my application looks like this:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// initialize dependency injection
var kernel = new NinjectKernel();
kernel.ApplyBindings();
var form = kernel.GetForm();
Application.Run(form);
}
And my Form looks like this:
public partial class MainForm : Form
{
private readonly ISomething Something;
public MainForm()
{
Something = new Something(this);
InitializeComponent();
CreateControl();
Something.Init();
}
}
My problem is as follows: I want to call "Something" to do basic initialization work for my Form (e.g. Load grid data, set label text...etc)
However, I only have access to the Form components in my MainForm class. I basically need to inject my MainForm instance into "Something" so that it can apply the modifications.
What I have tried is as follows:
public class Something: ISomething
{
private MainForm Form { get; set; }
public Something(MainForm form)
{
Form = form;
}
public void Init()
{
Form.Label1.Text = "Change some text!";
}
}
This appears to work, but something tells me that this isn't using DI properly. Can somebody shed more light on the proper approach using DI with Windows Forms?
I'm trying to use Ninject for dependency injection in my MVP application. However, I have a problem because I have two types that depend on each other, thus creating a cyclic dependency. At first, I understand that it was a problem, because I had both types require each other in their constructors. Therefore, I moved one of the dependencies to a property injection instead, but I'm still getting the error message. What am I doing wrong?
This is the presenter:
public class LoginPresenter : Presenter<ILoginView>, ILoginPresenter
{
private ISettings _settings;
private IViewProvider _viewProvider;
private IDataProvider _dataProvider;
public LoginPresenter(
ILoginView view,
ISettings settings,
IViewProvider viewProvider,
IDataProvider dataProvider )
: base( view )
{
_settings = settings;
_viewProvider = viewProvider;
_dataProvider = dataProvider;
}
}
and this is the view:
public partial class LoginForm : Form, ILoginView
{
[Inject]
public ILoginPresenter Presenter { private get; set; }
public LoginForm()
{
InitializeComponent();
}
}
And here's the code that causes the exception:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[MTAThread]
static void Main()
{
// Show the login form
Views.LoginForm loginForm = Kernel.Get<Views.Interfaces.ILoginView>() as Views.LoginForm;
Application.Run( loginForm );
}
}
The exception happens on the line with the Kernel.Get<>() call. Here it is:
Error activating ILoginPresenter using binding from ILoginPresenter to LoginPresenter
A cyclical dependency was detected between the constructors of two services.
Activation path:
4) Injection of dependency ILoginPresenter into property Presenter of type LoginForm
3) Injection of dependency ILoginView into parameter view of constructor of type LoginPresenter
2) Injection of dependency ILoginPresenter into property Presenter of type LoginForm
1) Request for ILoginView
Suggestions:
1) Ensure that you have not declared a dependency for ILoginPresenter on any implementations of the service.
2) Consider combining the services into a single one to remove the cycle.
3) Use property injection instead of constructor injection, and implement IInitializable
if you need initialization logic to be run after property values have been injected.
Why doesn't Ninject understand that since one is constructor injection and the other is property injection, this can work just fine? I even read somewhere looking for the solution to this problem that Ninject supposedly gets this right as long as the cyclic dependency isn't both in the constructors. Apparently not, though. Any help resolving this would be much appreciated.
According to Wikipedia, it's common for the View to manually instantiate its concrete presenter, but I can't do that in my case because as you can see, the presenter has other dependencies that need to be resolved as well.
I got "around" the issue by creating a "PresenterProvider":
public interface IPresenterProvider
{
P Get<P, V>( V view )
where V : IView
where P : IPresenter<V>;
}
public class PresenterProvider : IPresenterProvider
{
private IKernel _kernel;
public PresenterProvider( IKernel kernel )
{
_kernel = kernel;
}
#region IPresenterProvider Members
public P Get<P, V>( V view )
where P : IPresenter<V>
where V : IView
{
return _kernel.Get<P>( new ConstructorArgument( "view", view ) );
}
#endregion
}
Then, in the view I do this:
public partial class LoginForm : Form, ILoginView
{
private ILoginPresenter _presenter;
public LoginForm( IPresenterProvider presenterProvider )
{
InitializeComponent();
_presenter = presenterProvider.Get<ILoginPresenter, ILoginView>( this );
}
}
The presenter stays the same. This way, I'm "solving" the cyclic dependency manually. Better suggestions are still welcome, of course.