IoC Registration differences between Unity and Simple Injector - c#

I have one project functioning perfectly using Unity. I try switching to use Simple Injector instead and now NO changes ever get saved in my database. I believe it has to do with the lifetime of the registered components. Here is the Unity container registration:
private IUnityContainer GetUnityContainer()
{
IUnityContainer container = new UnityContainer()
.RegisterType<IDatabaseFactory, DatabaseFactory>(
new HttpContextLifetimeManager<IDatabaseFactory>())
.RegisterType<IUnitOfWork, UnitOfWork>(
new HttpContextLifetimeManager<IUnitOfWork>())
.RegisterType<ICategoryRepository, CategoryRepository>(
new HttpContextLifetimeManager<ICategoryRepository>())
.RegisterType<ICategoryService, CategoryService>(
new HttpContextLifetimeManager<ICategoryService>());
return container;
}
And here is the new Simple Injector registration.
container.Register<IDatabaseFactory, DatabaseFactory>();
container.Register<IUnitOfWork, UnitOfWork>();
container.Register<ICategoryRepository, CategoryRepository>();
container.Register<ICategoryService, CategoryService>();
I'm not sure how the HttpContextLifetimeManager comes into play with Simple Injector. MVC is the client for the unity example, but I'm changing to a WPF project and Simple Injector. Any suggestions are much appreciated. Thanks.
#Steven. Thanks for your comment. I just discovered that since my RepositoryBase and my UnitOfWork inject an IDatabaseFactory in their constructors that I needed to use container.RegisterSingle<IDatabaseFactory, DatabaseFactory>(). This resolved one issue. I still have a problem with lifetime though. Since my consuming app is WPF, how will the RegisterPerWebRequest work?
My project has a DataLayer >> BusinessLayer >> WcfService >> WPF Front end. Simple Injector is set on the WcfService project and the business layer has Boostrapper to register items there. As of now, my WPF client will GetAllCountries() and display in a grid. If I change the name of one and try to update, I get the "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key." error. I've done some debugging and find that after the GetCountries service call in the WPF client, when I go back to try to update, I see ALL of the countries are attached to the context via dbContext.ChangeTracker.Entries(). At this point I should have NO entities being tracked as my context should have been disposed after the first unit of work.
In an MVC app the RegisterPerWebRequest fixes that, but what is the equivalent for WPF? I'm going to install the extension now and try it anyway but I have a feeling it isn't the solution I'm looking for.. or is it? Thanks again for the help.
OK. I did a bit more digging and found a solution that works. I'm just not sure if it's the correct one. Anyway, now in my BLL where there is a bootstrapper to register things, I can register like this:
container.RegisterPerWcfOperation<IDatabaseFactory, DatabaseFactory>();
container.RegisterPerWcfOperation<IUnitOfWork, UnitOfWork>();
container.RegisterPerWcfOperation<ICountryRepository, CountryRepository>();
That gives me what I was looking for. Only a single instance of DatabaseFactory is ever created and thus my repository and unit of work share it like they should. Also, after GetCountries() on the client, when I do my second call to the service to perform and update, I check the dbContext.ChangeTracker.Entries() and see that there are NO entities being tracked, which is correct. I can now attach, set to modify, and call SaveChanges without getting the duplicate key error. Does this seem ok? Thanks.

The Register overloads over Simple Injector register types using the transient lifestyle (which means no caching). Every time you request an instance (or inject an instance) a new instance is created. In Unity this is the same; the default lifestyle is transient.
It seems that registering those types with a Per Web Request lifestyle is quite essential. It's not strange that changes are not committed to the database when the class that does those commits on an IUnitOfWork gets a different instance than the class who actually makes the changes to the IUnitOfWork.
Simple Injector's equivalent to Unity's HttpContextLifetimeManager is the WebRequestLifestyle. This lifestyle is not part of the core library, but is available as NuGet package.
After you included this in your project, you can do the following registration:
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.Register<IDatabaseFactory, DatabaseFactory>(Lifestyle.Scoped);
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
container.Register<ICategoryRepository, CategoryRepository>(Lifestyle.Scoped);
container.Register<ICategoryService, CategoryService>(Lifestyle.Scoped);
Or the equivalent:
Lifestyle lifestyle = new WebRequestLifestyle();
container.Register<IDatabaseFactory, DatabaseFactory>(lifestyle);
container.Register<IUnitOfWork, UnitOfWork>(lifestyle);
container.Register<ICategoryRepository, CategoryRepository>(lifestyle);
container.Register<ICategoryService, CategoryService>(lifestyle);
The default behavior of the WebRequestLifestyle is to dispose created instances when the web request ends. No special registration for this is required (Simple Injector hooks up an HttpModule for you when the application starts).
UPDATE:
My apologies for not reading your question to the last line. I missed the fact that you want to configure it using a WPF client.
As you probably know, since your client is a different application than the WCF service is, you'll have two Composition Roots in your system; one for the client, one for the service. Their registration will probably be quite different. Starting with Simple Injector v4.1, for a WCF service, you would indeed need a AsyncScopedLifestyle or when you follow the reference architecture at dotnetjunkie/solidservices, you'll find it as easy to use ThreadScopedLifestyle and define a scope explicitly in your two Execute methods.
I find managing the lifetime of objects in clients of two tier applications (client -> database) rather hard, since it is hard to define a unit of work for a certain scope. Since you are using the command/handler + query/handler approach, things will get so much easier. There won't be any unit of work on the client. Just on the server. Your presenter can just depend on several IQueryHandler<TQuery, TResult> and ICommandHandler<TCommand> interfaces and you're done. A query doesn't change state and a command should be an atomic operation. In other words, a unit of work is only needed within the boundary of an executing command.

Related

Minmal API DI reconstructs dependencies even when registered as singleton

Started working on a windows background service in .net that will host a restful service. As I worked on it, it seemed like Minimal APIs were a good fit (it was one of the things I was able to get a working prototype with, I couldn't get other stuff to work). However, I'm not sure if I'm misunderstanding something here. When I inspect one of my injected services, I'm noticing that it's being reconstructed each time the endpoint is hit. I didn't think that would happen if I register my services as singletons. Something tells me that due to the nature of Minimal API, there is no way around that. Am I missing something?
I'm using MessagePipe for .net.
SquareService implements IAsyncRequestHandler<LocationByNameRequest, LocationResponse>
The registration.
builder.Services.AddMessagePipe();
builder.Services.AddSingleton<SquareService>();
The injection.
app.MapPut("/pos",
async (POS station,
IAsyncRequestHandler<LocationByNameRequest, LocationResponse> handler) => { ...});
I made sure that Visual Studio wasn't just randomly ouputing log messages, so I set up a GUID in the constructor to verify if the instances might be different (they are).
How else would I host an api in a windows service? Been having problems integrating this, and I think it's because I'm not getting the same references as I was expecting. Any guidance would be greatly appreciated.
That has nothing to do with Minimal APIs per se. First of all builder.Services.AddSingleton<SquareService>(); will register just SquareService, not the interfaces it implements, if you resolve SquareService in the handler you will get exactly the same instance every time:
app.MapPut("/pos", async (POS station, SquareService handler) => ...);
It seems that MessagePipe has it's own custom DI/Lifetime handling. For publishers/subscribers you manipulate the registration type individually by using corresponding interfaces - see this part of the doc:
I(Async)Publisher(Subscriber)'s lifetime is belonging MessagePipeOptions.InstanceLifetime. However if declare with ISingletonPublisher<TMessage>/ISingletonSubscriber<TKey, TMessage>, ISingletonAsyncPublisher<TMessage>/ISingletonAsyncSubscriber<TKey, TMessage> then used singleton lifetime. Also IScopedPublisher<TMessage>/IScopedSubscriber<TKey, TMessage>, IScopedAsyncPublisher<TMessage>/IScopedAsyncSubscriber<TKey, TMessage> uses scoped lifetime.
But for handlers the only option is to set it globally for all the handlers via MessagePipeOptions (docs):
Configure IRequestHandler/IAsyncRequestHandler's lifetime of DI container. You can choose Singleton or Scoped or Transient. Default is Scoped.
services.AddMessagePipe(options => options.RequestHandlerLifetime = InstanceLifetime.Singleton);

Register vs RegisterInstance vs RegisterSingleton in Prism 7 DI

I am trying to register a service for DI in Prism 7. I find that all of the following methods work, which is the correct way to do it? What is the case for each?
public class AndroidInitializer : IPlatformInitializer
{
static OpenAppService openAppService = new OpenAppService();
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterInstance<IOpenAppService>(openAppService);
containerRegistry.Register<IFacebookLoginService, FacebookLoginService>();
containerRegistry.RegisterSingleton<IAppleSignInService, AppleSignInService>();
}
}
First of all, what each of these methods does totally depends on the actual container used, especially when you go beyond the totally trivial things. That's probably the main cause why there's no documentation for this stuff.
That being said...
Register says that the given service should be used when the given interface is injected, and that a new instance will be created for each single injection.
RegisterSingleton differs in that the same instance is used for all injections.
RegisterInstance is the same as RegisterSingleton, but you have to provide an instance.
which is the correct way to do it? What is the case for each?
So, most of the time services are registered as singletons, because you want viewmodels to be able to communicate through the service. Example: the EventAggregator - when one view models publishes an event, you expect others to receive it, which is only possible if they subscribe using the same instance as the publisher publishes on. A WCF client, though, doesn't need to be a singleton, because the communication happens on the server side.
You don't want to register instances because this mixes up registration and resolving, and you have to make absolutely sure that all dependencies of the instance have been registered already when creating the instance to register it (through a call to Resolve, which in itself has a touch of evil). This is less of a problem if you register everything in one method, but becomes a lot more of a headache if you have multiple (interdependent) modules.

Simple Injector 3 sees a registration as transient, even with `RegisterSingleton()`

I'm building an application (Xamarin.Forms, PCL and iOS, in case it's relevant) that uses Simple Injector for dependency injection throughout. So far, it's been great to work with, and with the recent release of Simple Injector 3 I'm updating my code to work with the new API. Unfortunately, I'm having a little trouble with one particular registration.
Here's the basic flow:
register an ISQLitePlatform (Windows, iOS, Android, etc) to handle the platform-specific bits (SQLite API, file I/O etc.)
register a bootstrapper which will be responsible for creating the database file, setting up all the table/type mappings etc.
register a lambda that will create our data access provider, use the bootstrapper to set up the database, and return the access provider
The app can then use the data access provider to open transactions on the database - the IDataAccessProvider interface just has one method, NewTransaction(), which returns a unit-of-work object with generic CRUD methods. The IDataAccessProvider also implements IDisposable, and the Dispose() methods handle the cleanup, closing of open connections/transactions, etc.
The issue is with these registrations:
container.RegisterSingleton<ISQLitePlatform, SQLitePlatformIOS>();
container.RegisterSingleton<ILocalDataBootstrapper, SQLiteDataBootstrapper>();
container.RegisterSingleton<IDataAccessProvider>(
() => container.GetInstance<ILocalDataBootstrapper>().DataAccessProvider);
For some reason, on startup I get the diagnostic warning that SQLiteDataAccessProvider is IDisposable and has been registered as transient. I can handle this - the disposal is being handled in the correct place - but what's confusing me is that it's definitely not being registered as transient, given that I'm using RegisterSingleton().
Is this a quirk of using RegisterSingleton() with a creation lambda instead of an instance? Is it a bug? Or am I missing something I'm supposed to do?
The most likely reason why this is happening is that somewhere in your code you make the following call:
container.GetInstance<SQLiteDataAccessProvider>();
Or you have a constructor that depends on this concrete type instead of the abstraction (in which case you can expect other warnings about this as well).
Since SQLiteDataAccessProvider is not registered 'as itself' (but merely by its IDataAccessProvider abstraction), Simple Injector will resolve this type for you and by default Simple Injector will make this type transient.
By doing so, a new registration is added to Simple Injector; you will be able to see that in the debugger. There is a singleton registration for IDataAccessProvider and a transient registration for SQLiteDataAccessProvider.
Now because there is a transient registration for SQLiteDataAccessProvider, Simple Injector will warn you that this instance will not get disposed automatically.
The solution is to remove the GetInstance<SQLiteDataAccessProvider>() call (or changge the ctor argument to use the abstraction) and replace it with a call to GetInstance<IDataAccessProvider>().

Singleton Unity Container

I just started getting my head around IOC unity framework. I read couple of articles and videos on MSDN. I have good understanding of how this unity thing works.
1.Create container.
2.Register your interface/classes.
3.Resolve your classes.
I think Steps 1,2 should be abstracted for each project. Is it good idea to create singleton class that creates container and registers interfaces/classes so that unity container will be available in entire project for me to resolve. Please advice.
Except for perhaps a few rare circumstances, you should always have a single container instance for your whole application (app domain). DI containers are thread-safe and are optimized for that scenario. Having multiple containers can cause performance problems and can cause maintenance issues, because some scenarios are very hard to achieve (like having application scoped objects for instance).
Use a singleton. In my current company we are using a singleton wrapper around the Unity container that:
is of course singleton
exposes the most important functionality (like registering and resolve)
takes its configuration from web.config/app.config
but can also be fed at runtime (for instance, for unit testing)
has functionality for default handling in case of unexpected errors during resolve
It works like a charm and makes it easy to focus on the important things.
Don't use a singleton. It encourages you to call resolve all over the place, which is a well-known DI antipattern.
Instead, have a single point in your app (the main function in a desktop app, in the app start function in your web app) where you use the container to resolve your object graph and go from there.
Look at Mark Seeman's discussion of "Composition Root" for more details.

Where to store Ninject IKernel in a web application?

I am new to IOC in general and I'm struggling a little to understand whether what I am trying to do makes any sense. I have a web forms application in which I want to create one module to define some bindings for me. The bindings will be used to inject repositories into my business manager classes, allowing me to unit test the business managers. Also I would like to use the container to inject the Entity Framework context into my repositories that way they all share the same context per http request. So here is what I am wondering:
I understand that I need to have the same kernel instance manage my object creation and their lifetime. For example if I want a one-per-httprequest type scenario I need the instance of the kernel to be available for that period of time. What if I need a singleton? Then it has to be application scoped somehow. So where exactly do I store the IKernel instance? It seems that I might want to make it a static in my Global.asax, is that the right approach and is thread safety a concern?
Since I am using Bind<> to define my bindings, how do I go about making that definition in the Web/UI layer when I shouldn't be referencing my data access layer from the UI? My references look like .Web --> .Business --> DataAccess. It seems like I want to tell the kernel "hey manage my data access instances, but don't have a reference to them at compile time." A binding such as this:
//Any object requesting an instance of AdventureWorksEntities will get an instance per request
Bind<AdventureWorksEntities>().ToSelf().InRequestScope();
I feel like I might be approaching this incorrectly, thank you.
Re part 1- have a look at the Ninject.Web extension - it keeps a Kernel at Application level. You can then manage other resources that have shorter lifetimes within that too.
Also, have a look around here for questions and examples on EF and L2S DataContext management wrt Ninject and DI in general (it's come up[ in the last few weeks)
UPDATE: This answer to another question from the same OP is far more concrete (There's a KernelContainer class with a .Inject( object) and a .Kernel)
It really depends on the complexity of your web app.
It sounds like you have a business and a data access layer; I would personally have an 'infrastructure' layer where I would store my DI repository and helper classes.

Categories

Resources