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

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 for Unit Of Work and EF DbContext per Request

If LPCContext is a concrete type with a single constructor, technically speaking, you don't have to register it, because Simple Injector can auto-create it for you, and since the UnitOfWork is created as scoped, it will drag allong the LPCContext as scoped lifestyle as well. However...

Simple Injector will auto-register a concrete unregistered type for you using the transient lifestyle. But now your scoped registration of UnitOfWork depends on a registration with a shorer lifestyle (transient), Simple Injector will throw an exception, explaining there is a Lifestyle Mismatch.

Although in your particular case this wouldn't be a problem per see, it is still important to fix the problem, because it can easily lead to problems later on, when you start injecting the LPCContext into other consumers as well. In that case, each consumer will get its own LPCContext instance, which is typically not what you want.

So to solve this, it's best to register the LPCContext class explicitly using the scoped lifestyle:

string conString = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
container.Register<LPCContext>(() => new LPCContext(conString), Lifestyle.Scoped);

Implement Simple Injector with generic repository

The Register<TService, TImpementation>() method allows you to specify a concrete type (TImplementation) that will be created by Simple Injector when the specified service (TService) is requested. The specified implementation Repository<SequoiaEntities, Portal> however is marked as abstract. This disallows Simple Injector from creating it; abstract classes can not be created. The CLR does not permit this.

You do have a concrete type PortalRepository however, and I believe it is your goal to return that type. Your configuration should therefore look as follows:

container.Register<IRepository<Portal>, PortalRepository>();

Alternatively, you can make use of Simple Injector's batch-registration facilities and register all your repositories in one call:

Assembly[] assemblies = new[] { typeof(PortalRepository).Assembly };

container.Register(typeof(IRepository<>), assemblies);

How to implement unit of work pattern with IServiceProvider injected in repositories?

As the error shows, you should not inject scoped lifetime dependencies into singletons. DbContexts are usually registered as scoped.

If the repositories depend on the context then they should be scoped as well.

For example.

services.AddScope<IUnitOfWork, UnitOfWork>(); 
services.AddScope<IRepositoryA, RepositoryA>();
services.AddScope<IRepositoryB, RepositoryB>();
services.AddDbContext<ApiContext>(options => options.UseInMemoryDatabase("Database"));

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

Unit of Work and Repository Pattern in MVC controller constructor injection using Unity not doing any changes to database

It looks like your issue is the scope of your DbContext. Your UnitOfWork and GenericRepository<T> classes are getting different instances.

Not super familiar with Unity, but it looks like you want to use something like this for your DbContext registration:

container.RegisterType<DbContext, DashboadContext>(new PerRequestLifetimeManager());

This will create a single DashboardContext for each request, and your UnitOfWork and GenericRepository<T> classes will be working within the same context.

Using Simple Injector with Background worker in WinForms to Save to DB using EF6

I am expecting a new DbContext to be created for each thread

This is not how TheadScopedLifestyle works. With the ThreadScopedLifestyle, there will be one instance of your registration within the context of an explicitly started Scope and this scope is thread-specific. This means that one thread can have many instances of that service, since a thread can live for a long time, while a Scope will typically only live for a short amount of time.

A typical use for ThreadScopedLifestyle is the following:

void MethodThatRunsInABackGroundThread()
{
using (ThreadScopedLifestyle.BeginScope(container))
{
var service = container.GetInstance<ISomeService>();
service.DoWork();
}
}

When you resolve Scoped instances (or some object graph that contains scoped instances) outside an active scope, Simple Injector will throw an exception.



Related Topics



Leave a reply



Submit