C# Covariance on Subclass Return Types

How to register Windows Forms with Simple Injector

Ideally, you would want to register your forms as Singleton. In my experience, however, this will result in hard to debug errors, especially when you use a BindingSource for binding your data to whatever.

A second problem with using Singleton as the lifestyle is that if your application uses modeless windows, this windows will throw an ObjectDisposedException when opened a second time, because the Windows Forms Application framework will dispose the Form on the first close, while Simple Injector should be in charge of that. So Simple Injector will create one–and exactly one–instance, if registered as Singleton. If somebody else (e.g. your application, the windows forms framework) will dispose the object, it won't be recreated.

The most easy solution, which is also easy to understand, is to register your forms as Transient. And yes, you need to suppress the diagnostic warnings. The reason for this diagnostic warning according to the documentation:

A component that implements IDisposable would usually need deterministic clean-up but Simple Injector does not implicitly track and dispose components registered with the transient lifestyle.

Simple Injector is unable to dispose a transient component because it is unable to determine when the object should be disposed. This means, however, that forms that are opened in a modal fashion with a call to .ShowDialog() will never be disposed! And because a windows forms application typically runs for a long time, maybe even a week or month, this will eventually result in a 'Win32Exception' with a message: "Error Creating Window Handle". Which essentially means you exhausted all resources of the computer.

Disposing of the forms is therefore important. And although Simple Injector is able to do this job if you would use a Scope, this is with Windows Forms not so easy to implement. So you yourself have to take care of disposing the closed Forms which have been shown using ShowDialog().

Depending on your specific use case there are several ways to implement a FormOpener or NavigationService. One way to do it:

public interface IFormOpener
{
void ShowModelessForm<TForm>() where TForm : Form;
DialogResult ShowModalForm<TForm>() where TForm : Form;
}

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 void ShowModelessForm<TForm>() where TForm : Form
{
Form form;
if (this.openedForms.ContainsKey(typeof(TForm)))
{
// a form can be held open in the background, somewhat like
// singleton behavior, and reopened/reshown this way
// when a form is 'closed' using form.Hide()
form = this.openedForms[typeof(TForm)];
}
else
{
form = this.GetForm<TForm>();
this.openedForms.Add(form.GetType(), form);
// the form will be closed and disposed when form.Closed is called
// Remove it from the cached instances so it can be recreated
form.Closed += (s, e) => this.openedForms.Remove(form.GetType());
}

form.Show();
}

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>();
}
}

This class must be registered as Singleton:

container.RegisterSingleton<IFormOpener, FormOpener>();

And can be used by injecting this service in for example your root form of the application:

public partial class RootForm : Form
{
private readonly IFormOpener formOpener;

public RootForm(IFormOpener formOpener)
{
this.formOpener = formOpener;
this.InitializeComponent();
}

private void ShowCustomers_Click(object sender, EventArgs e)
{
this.formOpener.ShowModelessForm<AllCustomersForm>();
}

private void EditCustomer_Click(object sender, EventArgs e)
{
var result = this.formOpener.ShowModalForm<EditCustomerForm>();
// do something with result
}
}

Simple Injector Property Injection in User Control Windows Forms

My problem is when using drag and drop to design UI, the user control is automatically generated using the new operator, and property injection doesn't work.

This is exactly why the documentation refers to property injection. Property injection allows to be applied on externally created instances (as user controls are created by the UI framework, not the DI Container).

What the documentation fails to mention, however, is how to initialize a created instance with dependencies. Simple Injector contains an InitializeInstance for this. The following code allows initializing user controls that use explicit property injection:

private static Container container;

public static void InitializeControl(UserControl control)
{
var producer = container.GetRegistration(control.GetType(), true);
producer.Registration.InitializeInstance(control);
}

This, unfortunately, is far from perfect because it requires forms and user controls to depend on the DI Container. To prevent this, you can pass on dependencies from the containing form to the user control through Method Injection instead, but the downside of this is that you'd easily have to pass many dependencies, causing the consuming form's constructor to explode.

Alternatively, contrary to what the documentation states, it is possible to resolve user controls from the DI Container and circumvent using the designer as stated here by Ron. This might have consequences of its own, however, and I have no experience with this.

Using Simple Injector with Unit Of Work & Repository Pattern in Windows Form

The problem you have is the difference in lifestyles between your service, repository, unitofwork and dbcontext.

Because the MemberRepository has a Singleton lifestyle, Simple Injector will create one instance which will be reused for the duration of the application, which could be days, even weeks or months with a WinForms application. The direct consequence from registering the MemberRepository as Singleton is that all dependencies of this class will become Singletons as well, no matter what lifestyle is used in the registration. This is a common problem called Captive Dependency.

As a side note: The diagnostic services of Simple Injector are able to spot this configuration mistake and will show/throw a Potential Lifestyle Mismatch warning.

So the MemberRepository is Singleton and has one and the same DbContext throughout the application lifetime. But the UnitOfWork, which has a dependency also on DbContext will receive a different instance of the DbContext, because the registration for DbContext is Transient. This context will, in your example, never save the newly created Member because this DbContext does not have any newly created Member, the member is created in a different DbContext.

When you change the registration of DbContext to RegisterSingleton it will start working, because now every service, class or whatever depending on DbContext will get the same instance.

But this is certainly not the solution because having one DbContext for the lifetime of the application will get you into trouble, as you probably already know. This is explained in great detail in this post.

The solution you need is using a Scoped instance of the DbContext, which you already tried. You are missing some information on how to use the lifetime scope feature of Simple Injector (and most of the other containers out there). When using a Scoped lifestyle there must be an active scope as the exception message clearly states. Starting a lifetime scope is pretty simple:

using (ThreadScopedLifestyle.BeginScope(container)) 
{
// all instances resolved within this scope
// with a ThreadScopedLifestyleLifestyle
// will be the same instance
}

You can read in detail here.

Changing the registrations to:

var container = new Container();
container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();

container.Register<IMemberRepository, MemberRepository>(Lifestyle.Scoped);
container.Register<IMemberService, MemberService>(Lifestyle.Scoped);
container.Register<DbContext, MemberContext>(Lifestyle.Scoped);
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);

and changing the code from btnSaveClick() to:

private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;

using (ThreadScopedLifestyle.BeginScope(container))
{
var memberService = container.GetInstance<IMemberService>();
memberService.Save(member);
}
}

is basically what you need.

But we have now introduced a new problem. We are now using the Service Locator anti pattern to get a Scoped instance of the IMemberService implementation. Therefore we need some infrastructural object which will handle this for us as a Cross-Cutting Concern in the application. A Decorator is a perfect way to implement this. See also here. This will look like:

public class ThreadScopedMemberServiceDecorator : IMemberService
{
private readonly Func<IMemberService> decorateeFactory;
private readonly Container container;

public ThreadScopedMemberServiceDecorator(Func<IMemberService> decorateeFactory,
Container container)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}

public void Save(List<Member> members)
{
using (ThreadScopedLifestyle.BeginScope(container))
{
IMemberService service = this.decorateeFactory.Invoke();

service.Save(members);
}
}
}

You now register this as a (Singleton) Decorator in the Simple Injector Container like this:

container.RegisterDecorator(
typeof(IMemberService),
typeof(ThreadScopedMemberServiceDecorator),
Lifestyle.Singleton);

The container will provide a class which depends on IMemberService with this ThreadScopedMemberServiceDecorator. In this the container will inject a Func<IMemberService> which, when invoked, will return an instance from the container using the configured lifestyle.

Adding this Decorator (and its registration) and changing the lifestyles will fix the issue from your example.

I expect however that your application will in the end have an IMemberService, IUserService, ICustomerService, etc... So you need a decorator for each and every IXXXService, not very DRY if you ask me. If all services will implement Save(List<T> items) you could consider creating an open generic interface:

public interface IService<T>
{
void Save(List<T> items);
}

public class MemberService : IService<Member>
{
// same code as before
}

You register all implementations in one line using Batch-Registration:

container.Register(typeof(IService<>),
new[] { Assembly.GetExecutingAssembly() },
Lifestyle.Scoped);

And you can wrap all these instances into a single open generic implementation of the above mentioned ThreadScopedServiceDecorator.

It would IMO even be better to use the command / handler pattern (you should really read the link!) for this type of work. In very short: In this pattern every use case is translated to a message object (a command) which is handled by a single command handler, which can be decorated by e.g. a SaveChangesCommandHandlerDecorator and a ThreadScopedCommandHandlerDecorator and LoggingDecorator and so on.

Your example would then look like:

public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}

public class CreateMemberCommand
{
public string MemberName { get; set; }
}

With the following handlers:

public class CreateMemberCommandHandler : ICommandHandler<CreateMemberCommand>
{
//notice that the need for MemberRepository is zero IMO
private readonly IGenericRepository<Member> memberRepository;

public CreateMemberCommandHandler(IGenericRepository<Member> memberRepository)
{
this.memberRepository = memberRepository;
}

public void Handle(CreateMemberCommand command)
{
var member = new Member { Name = command.MemberName };
this.memberRepository.Insert(member);
}
}

public class SaveChangesCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> decoratee;
private DbContext db;

public SaveChangesCommandHandlerDecorator(
ICommandHandler<TCommand> decoratee, DbContext db)
{
this.decoratee = decoratee;
this.db = db;
}

public void Handle(TCommand command)
{
this.decoratee.Handle(command);
this.db.SaveChanges();
}
}

And the form can now depend on ICommandHandler<T>:

public partial class frmMember : Form
{
private readonly ICommandHandler<CreateMemberCommand> commandHandler;

public frmMember(ICommandHandler<CreateMemberCommand> commandHandler)
{
InitializeComponent();
this.commandHandler = commandHandler;
}

private void btnSave_Click(object sender, EventArgs e)
{
this.commandHandler.Handle(
new CreateMemberCommand { MemberName = txtName.Text });
}
}

This can all be registered as follows:

container.Register(typeof(IGenericRepository<>), 
typeof(GenericRepository<>));
container.Register(typeof(ICommandHandler<>),
new[] { Assembly.GetExecutingAssembly() });

container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(SaveChangesCommandHandlerDecorator<>));
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(ThreadScopedCommandHandlerDecorator<>),
Lifestyle.Singleton);

This design will remove the need for UnitOfWork and a (specific) service completely.

Simple injector how to register /resolve collection of singletons against same interface

You are calling the wrong Register<T> overload. You are actually calling Register<T>(params T[] singletons), instead of calling Register<T>(IEnumerable<Registration> registrations). This causes the registrations to be made as a collection of Registration instances, instead of a collection of IGlobalExchangeRateLimitProvider instances, as can be seen when hovering over the verified container:

Simple Injector's debug view showing the root registrations

Instead, include the type of the collection when calling Collection.Register

var container = new Container();
container.Collection.Register<IGlobalExchangeRateLimitProvider>(new[]
{
Lifestyle.Singleton.CreateRegistration<IGlobalExchangeRateLimitProvider>(
() => new GlobalExchangeRateLimitProvider("A"), container),
Lifestyle.Singleton.CreateRegistration<IGlobalExchangeRateLimitProvider>(
() => new GlobalExchangeRateLimitProvider("B"), container)
});
container.Verify();

set child winform properties from a parent form when using simple injector c#

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>.

Simple Injector - Registering ASP.NET Identity

The amount of error information given by Simple Injector can be a bit overwhelming, but you can distill the information down to two separate problems:

  • ApplicationUserManager is registered as Transient
  • Types incorrectly depend on unregistered type ApplicationSignInManager (Transient) instead of SignInManager<ApplicationUser, String> (Web Request).

You should certainly read the Diagnostic Services documentation page in the Simple Injector documentation and especially read about Lifestyle Mismatches, Disposable Transient Components and Short-Circuited Dependencies to understand what Simple Injector is warning about and how to fix the problem.

In short, the fix is two-fold:

  1. Change the registration of ApplicationUserManager from Transient to Scoped to prevent it from having a too-short lifetime and to ensure it is disposed of. Also read this part of the documentation to learn the difference between Transient and Scoped from the context of Simple Injector.
  2. Make sure that types (i.e. AccountController and ManageController) don't depend on ApplicationSignInManager (in their constructor), but instead depend on its base type SignInManager<ApplicationUser, String>.

Form1 is registered as transient, but implements IDisposable

I changed my Code in this line

container.Register<Form1>(); 

to

container.Register<Form1>(Lifestyle.Singleton);

and it works fine .You can see full code in below

 private static void Bootstrap()
{
// Create the container as usual.
container = new Container();
// container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

// Register your types, for instance:
container.Register<IStudentService, StudentService>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<IStudentRepository, StudentRepository>(Lifestyle.Singleton);
container.Register<Form1>(Lifestyle.Singleton);

// Optionally verify the container.
container.Verify();

}


Related Topics



Leave a reply



Submit