Ninject not creating a new instance with constructor arguments in WCF - ninject

Here is the scenario. I have a WCF service, when this service is called it passes control to an instance of another class (created via Ninject). In that class I need to do some work, specifically with Entity Framework and repositories. To cut a long story short, I have the following binding declared.
Bind<IGenericProductRepository>()
.To<GenericProductRepository>()
.WithConstructorArgument( "context", new StagingDataContext());
When I want to use this repository I have the following.
using (var genericProductRepository = IoC.Resolve<IGenericProductRepository>())
The problem is, that I only get a new instance of genericProductRepository if it's a brand new request, if the method is called multiple times in the same request I get an error stating that the context (the EF context) is already disposed, this is because it seems like I am getting the same instance back that was already disposed in the using statement. To explain it another way, using the Microsoft WCF Test Client, if I invoke it the first time, the code runs fine, if I push the invoke button again (without restarting the test client, i.e. the same request) then it throws this error about it being disposed already.
I have tried to play around with the various "scopes" that come with Ninject, but clearly I am missing something.
So my basic question is, how do I get a new repository whenever it hits that line, instead of using the same one ? Help would be greatly appreciated, I'm really trying to push for my company to adopt Ninject and drop Spring.

Look at your binding again. Even without any knowledge about Ninject you should notice that the instance of your context is created exactly once at the time the binding is defined. But what you want is have a new context on every resolve. Best it is done by not using WithConstructorArgument and let Ninject create the instance. Therefore you have to define a additional binding for the type of context. If this is not possible for some reason you have to use the lazy version of WithConstructorArgument
WithConstructorArgument("context", ctx => new StagingDataContext())
Furthermore, you might want to try The WCF extension for Ninject:
https://github.com/ninject/ninject.extensions.wcf
That way you can get rid of the ServiceLocator like usage.

Related

Can I create an object from the DI container/Lamar in .NET 6.0 minimal hosting, preserving singletons?

We have migrated from a windows Framework 4.7 application to .NET 6.0. Lamar is added for Dependency Injection. We are trying to finalize a refactor to the latest "one-file" program.cs but are getting unexpected System.ObjectDisposedException: 'Cannot access a disposed object'. In all cases, the error is against a Func<T> during object creation.
All our tests are running correctly using the same environment, except to start the tests we (a) create the DI container and (b) use the container to create an object that loads the singletons (from MongoDB):
Container = new Container(registry);
var start = Container.GetInstance<HomeService>();
In the program.cs, we configure the container, but do not get to see it created, or access it inside program.cs. Instead we create HomeService from IServiceProvider during the first use of a controller. Here we were trying to limit the lifecyle scope during creation:
using (var scope = _container.CreateScope())
{
scope.ServiceProvider.GetService<INewHomeService>();
}
For test, we use the same loading steps, except for adding controllers/mvc, of course (i.e. NOT using builder.Services.AddControllers(); and builder.Services.AddMvc() for (integration) testing).
We have tried a lot of different things, like creating our object independently to the startup, but that did not align the singletons. We can get functionality by using static instead, but then we lose dynamic change access.
Some great tips like Resolving instances with ASP.NET Core DI from within ConfigureServices and https://andrewlock.net/exploring-dotnet-6-part-10-new-dependency-injection-features-in-dotnet-6/ but I can't see the specific example to get the live container just after initial creation.
Is it possible that the issue is just the difference between the lifecycle management of the new .NET DI implementation? As this is configuration at the composition root, if we can configure as per our testing approach, it should solve our problem. Other solutions welcome!
The problem 'Cannot access a disposed object' was being caused by a lifecycle mismatch between retained context and the controller access. The code retained a handle on the state object, that had a handle on the factory using FUNC. As we did not configure the Func as anything, it was transient during the controller graph creation, and so was disposed when the controller request ended.
To solve, we tried registering ALL of the FUNC, per How to use Func<T> in built-in dependency injection which was a large task as we had a few factories throughout an old codebase.
The better solution was to create a factory in the composition root, and use an injected IserviceProvider (or with Lamar an IContainer). This is a simple workaround.
With our creation concern, the creation of our object after the completion of the startup process is working correctly as a lazy validation of the first controller access.

Change implementation of ninject dependency after singleton instantiation

So, I have a viewmodel class in a xamarin project that I inject some dependencies into via ninject binding on app start. One of these is an IDialogService.
When my MainPage in my application changes it raises a property changed event and I rebind the implementation of the dialog service since it is tied to the MainPage.
If my viewmodel has already been created with lets say DialogServiceA and then when MainPage changes we rebind to DialogServiceB, will my viewmodel be using service A or B? I think it is using A and therefore does not display in the UI because it is tied to a MainPage that no longer exists.
So, if this is the case how can I dynamically change my dialog service but then update classes that have already been instantiated without changing everything to get the current dialog service from the container every time its used (therefore not injecting it at all really, and doing more of a servicelocator)
Also, if this approach is completely wrong, set me straight.
You're right. Re-configuration of the container does not affect already instanciated objects.
If you want to change dependencies without re-instanciating the dependent (parent ViewModel) there's a few possibilities for you:
use a factory to instanciate the service every time. Implement an Abstract Factory (Site by Mark Seeman) or use Ninject.Extensions.Factory to do so
instead of injecting a service directly, inject an adapter. The adapter then redirects the request to the currently appropriate service. To do so, either all service can be injected into the adapter, or you can use a factory as with the possibility above.
instead of inject a service directly, inject a proxy. The proxy is quite similar to the adapter, but instead of coding every method / property redirection specifically, you code a generic redirect by an interceptor. Here's a tutorial on castle dynamic proxy
At the end of the day, however, i believe you'll also need a way to manage when to change the service / which it should be. There's probably a design alternative which doesn't rely on exchanging objects in such a manner.. which would make it an easier (and thus better?) design.
Edit: i just saw that you also tagged the question as xamarin-forms. In that case it most likely won't be an option to use either a dynamic proxy nor ninject.extensions.factory (it relies on dynamic proxies, too). Why? dynamic proxy / IL emitting is not supported on all platforms, AFAIR specifically on Apple devices this can't be done.

Ninject provider can't resolve types registered within a named scope

I am using the NamedScoped Ninject extension in an attempt to create object graphs that are constructed everytime a command handler is constructed by the container. In other words, I want a fresh object graph for every command that might get processed by its corresponding handler.
I have used the .DefinesNamedScope("TopLevelOrhcestrator") binding when registering my "command handlers" as they are the top level for command processing.
A type in this named scope needs to be injected with the result of a method call on a type already registered in this named scope. I thought the best way to do this would be with a ninject provider.
Inside the provider I attempt to resolve the type in hopes I can call a method on it to pass into another object I am creating within this named scope. The problem I'm having is that when I ask the IContext for the instance inside the customer provider I get an exception that says "No matching scopes are available, and the type is declared InNamedScope(TopLevelOrchestrator).
context.Kernel.Get<TypeAlreadyRegisteredInScope>().MethodThatGetsAnotherDependency()
Is it possible to get types from the container inside a Ninject provider when they are registered inside a named scope?
EDIT
I apologize if the use case seems a bit odd, I am experimenting with some ideas about how to manage my units of work and other services/managers that may need a handle to the uow to complete a business usecase. I know its common for the unit of work to be "started" and then passed into all dependencies that may need to take part in a larger process. I was thinking I'd rather let my orchestrator take a unit of work factory so that it could deterministically destroy the UOW and it would be clear who the owner of a usecase is. What would get supplied to the managers/services would be a proxy to the unit of work that would be null until a real unit of work was started by the orchestrator. That's why I was attempting to link the proxy from the already registered type in my provider. This is all very experimental at this point and was testing some ideas.
I'd be happy to hear any further thoughts.
For MethodThatGetsAnotherDependency() to be able to .Get<>() an instance that is bound .InNamedScope(...) you will need to add the Context Preservation Extension.
This is because NamedScope is adding a parameter to the request context of the binding that has .DefinesNamedScope(...). As soon as that request is over, that context and it's parameters are forgotten. Now with the ContextPreservation extension the context is kept and reused for late / factory creations (Func<>, interface factory with .ToFactory() binding...). It think it should also work with providers.
If not, just switch to a factory instead of a provider.
However i have to admit that i don't fully understand why/what you are trying to achieve. There might be simpler ways.

Using one LINQ to SQL DataContext per WCF request and automatically calling SubmitChanges?

I've been scouring the web/SO for hours now so exuse me if I missed it...
I am looking for a concrete example of how to hook into the WCF pipeline when running as a WAS hosted in IIS so that a new LINQ to SQL DataContext is automatically created and disposed when the WCF request begins and ends.
Also, when the DataContext is being disposed would it be possible/ok to call SubmitChanges() at that point to commit any changes that have been made over the course of the request?
My main goals here are to:
Have the DataContext lifecycle be tied to the request
Hide the DataContext from my domain layer so that it is easily testable.
One way to go about it would be to extend the OperationContext instance which gets created for each operation invoked in WCF. You can add extension to OperationContext. This extension can contain the DataContext instance which can be accessed and used at different location. Look at this post

NHibernate Session gets disposed off on each wcf service method call

I am using Wcf in Sharp Architecture. I have configured my project following northwind sample using WcfSessionStorage etc. I have a method in the wcf service that gets a list of business object using Repository<>.GetAll(). I am testing the service method using WcfTestClient. When the method is called the very first time, everything works fine. However on the subsequent call, I get the following exception on the Repository<>.GetAll() method
[System.ObjectDisposedException]
Session is closed!
Object name: 'ISession'
It seems like the NHibernate session gets disposed after each call. I have got around this problem by decorating my service with the following attribute
[ServiceBehavior( InstanceContextMode = InstanceContextMode.PerCall )]
public class WcfService : IWcfService
{
}
However this means, an instance of the service will be created on each call that in turn will create a new nhibernate session etc. In my scenario there is no need of creating a new service instance per call and I think its an expensive process and not the right solution. I would like to know what is the best practice in my scenario and how to get this thing work with creating a new service instace per call.
Thanks
Nabeel
The easiest way is to create a new instance every time and it's not an expensive process, because creating a new object in .NET is like 0.00000000000000001 second (I read that on Ayande's blog or somewhere).
I use Autofac DI in my projects and I usually make ISession as container scoped (one per request). And then every class that uses (directly or indirectly) ISession has to be container scoped or lower (factory scoped == every class usage get's a new instance). If a class that uses ISession is higer scoped (session scoped == singleton) you'll run into problems that you currently have.
If your service is singleton service:
At first run the service is created, this service uses ISession, which should be container scoped, and it is on the first run.
The next request to service (service is now created) has still a reference to created ISession (which was closed on previous end request), so now it's closed.
I don't recomend using the same ISession that you'll open/close (it's not recomended in the NHibernate documentation), just use container scoped (I do and I don't have any performance issues), or you should create ISession manually in every method in your service like:
using(ISession s = ISessionFactory.OpenSession())
using(ITransaction t = .....)
....
But that isn't nice at all...
Please take a look at my answer to my own similar question: WCF/S#arpArch: underlying ISession is closed after the first call within a request.
#dmonlord is right that the creation of additional session instances within the same request is very cheap in this case.