Best strategy for creating a child container (or isolated scope) with Microsoft.Extensions.DependencyInjection - asp.net-core

In my AspNetCore application, I process messages that arrive from a queue. In order to process a message, I need to resolve some services. Some of those services have a dependency on ITenantId, which I bind using information from the received message. To solve this, the processing of a messages starts with the creation of a child container, which I then use to create an IServiceScope from which I resolve all the needed dependencies.
The messages can be processed in parallel, so the scopes must be isolated from each other.
I can see to ways of creating the child container, but I'm not sure which is best in terms of performance, memory chrurn etc:
Option A: Each time a message arrives, clone the IServiceCollection into a new ServiceCollection, and rebind ITenantId on the cloned instance.
Option B: When the program starts, create an immutable copy of the IServiceCollection (using ImmutableList<ServiceDescriptor> or ImmutableArray<ServiceDescriptor>). Each time a message arrives, replace ITenantId (resulting in a new instance of ImmutableList<ServiceDescriptor>) and call CreateScope() on the new immutable instance.
The thing I don't like about option A is that the whole collection of services needs to be cloned every time a message arrives. I'm not sure if the immutable collections in option B handles this in a smarter way?

Both options cause the creation of a new container instance for each incoming messages. Although this allows each message to run in a completely isolated bubble, this has severe implications on performance and memory use of the application. Creating container instances is expensive and resolving a registered instance for the first time (per container) causes generation of expression trees, compilation of delegates, and JIT compiling them. This can even cause memory leaks.
Besides, it also means that any registered singleton class, will have a lifetime that equals that of any scoped classes. State can't be shared any longer.
So instead, I propose Option 3:
Use only one Container instance and don't call BuildProvider more than once
Create a ITenantId implementation that allows setting the Id after instantiation
Register that implementation as Scoped
At the start of every new IServiceScope, resolve that implementation and set its id.
This might look as follows:
// Code
class TenentIdImpl : ITenantId
{
public Guid Id { get; set; } // settable
}
// Startup:
services.AddScoped<TenentIdImpl>();
services.AddScoped<ITenantId>(c => c.GetRequiredService<TenantIdImpl>());
// In message pipeline
using (var scope = provider.CreateScope())
{
var tenant = scope.ServiceProvider.GetRequiredService<TenantIdImpl>();
tenant.Id = messageEnvelope.TenantId;
var handler =
scope.ServiceProvider.GetRequiredService<IMessageHandler<TMessage>>();
handler.Handle(messageEnvelope.Message);
}
This particular model, where you store state inside your object graph, which I explain in my blog, is called the Closure Composition Model.

Related

Asp.Net Core: creating a new scoped IServiceProvider

Objective
Create a asp.net core based solution that permits plugins loaded in runtime, way after IServiceCollection/IServiceProvider have been locked down to change.
Issue
IServiceCollection is configured at startup, from which IServiceProvider is developed, then both are locked for change before run is started.
I'm sure there are great reasons to do this....but I rue the day they came up with it being the only way to do things... so:
Attempt #1
Was based on using Autofac's ability to make child containers, falling back to parent containers for whatever is not specific to the child container,
where, right after uploading the new plugin, I create a new ILifetimeScope so that I can add Services given its containerBuilder:
moduleLifetimeScope = _lifetimeScope.BeginLifetimeScope(autoFacContainerBuilder =>
{
//can add services now
autoFacContainerBuilder.AddSingleton(serviceType, tInterface);
}
save the scope and its Container in a dictionary, against controllerTypes found in the dll, so that:
later can use a custom implementation of IControllerActivator to first try with the default IServiceProvider before falling back to try in the child plugin's child container.
The upside was, Holy cow, with a bit of hacking around, slowly got Controllers to work, then DI into Controllers, then OData....
The downside was that its custom to a specific DI library, and the Startup extensions (AddDbContext, AddOData) were not available as autoFacContainerBuilder doesn't implement IServiceCollection, so it became a huge foray into innards...that sooner or later couldn't keep on being pushed uphill (eg: couldn't figure out how to port AddDbContext)
Attempts #2
At startup, save a singleton copy of the original ISourceCollectionin theISourceCollection` (to easily re-get it later)
Later, upon loading a new plugin,
Clone the original ISourceCollection
Add to the clonedServiceCollection new Plugin Services/Controllers found in by Reflection
Use standard extension methods to AddDbContext and AddOData, etc.
Use a custom implementation of IControllerActivator as per above, falling back to the child IServiceProvider
Holy cow. Controllers work, OData works, DbContext works...
Hum...it's not working perfectly. Whereas the Controllers and being created new on every request, it's the same DbContext every time, because it's not being disposed, because it's not scoped by some form of scopefactory.
Attempt #3
Same thing as #2, but instead of making the IServiceProvider when the module is loaded, now -- in the custom IControllerActivator making a new IServiceProvider on each request.
No idea how much memory/time this is wasting, but I'm guessing its ...not brilliant
But sure...but I've really just pushed the problem a bit further along, not gotten rid of it:
A new IServiceProvider is being created...but nothing is actually disposing of it either.
backed by the fact that I'm watching memory usage increase slowly but surely....
Attempt #4
Same as above, but instead of creating a new IServiceProvider on every request, I'm keeping the IServiceProvider that i first built when I uploaded the module, but
using it to built a new Scope, and get its nested IServiceProvider,
hold on to the scope for later disposal.
It's a hack as follows:
public class AppServiceBasedControllerActivator : IControllerActivator {
public object Create(ControllerContext actionContext)
{
...
find the cached (ControllerType->module Service Provider)
...
var scope = scopeDictionaryEntry.ServiceProvider.CreateScope();
httpController = serviceProvider.GetService(controllerType);
actionContext.HttpContext.Items["SAVEMEFROMME"] = scope;
return httpController;
}
public virtual void Release(ControllerContext context, object controller)
{
var scope = context.HttpContext.Items["SAVEMEFROMME"] as IServiceScope;
if (scope == null){return;}
context.HttpContext.Items.Remove("SAVEMEFROMME");
scope.Dispose(); //Memory should go back down..but doesn't.
}
}
}
Attempt #5
No idea. Hence this Question.
I feel like I'm a little further along...but just not closing the chasm to success.
What would you suggest to permit this, in a memory safe way?
Background Musings/Questions in case it helps?
As I understand it, the default IServiceProvider doesn't have a notion of child lifespan/containers, like Autofac can create.
I see a IServiceScopeFactory makes a new IServiceProvider.
I understand there is some middleware (what name?) that invokes IServiceScopeFactory to make a IServiceProvider on every single request (correct?)
are these per-request IServiceProviders really separate/duplicate, and don't 'descend' from a parent one and falls back to parent if a asked for a singleton?
What is the Middleware doing different to dispose/reduce memory at the end of the call?
Should I be thinking about replacing the middleware? But even if it could -- it's so early that I only would have an url, not yet a Controller Type, therefore don't know what Plugin Assembly the Controller came from, therefore don't know what IServiceProvider to use for it...therefore too early to be of use?
Thank you
Getting a real grip on adding plugin sourced scoped services/controllers/DbContexts would be...wow. Been looking for this capability for several months now.
Thanks.
Other Posts
some similarity to:
Use custom IServiceProvider implementation in asp.net core
but I don't see how his disposing is any different to what I'm doing, so are they too having memory issues?

NServiceBus Removing IBus - Utilising IPipelineContext and IMessageSession

I am in the process of migrating NServiceBus up to v6 and am at a roadblock in the process of removing reference to IBus.
We build upon a common library for many of our applications (Website, Micro Services etc) and this library has the concept of IEventPublisher which is essentially a Send and Publish interface. This library has no knowledge of NSB.
We can then supply the implementation of this IEventPublisher using DI from the application, this allows the library's message passing to be replaced with another technology very easily.
So what we end up with is an implementation similar to
public class NsbEventPublisher : IEventPublisher
{
IEndpointInstance _instance;
public NsbEventPublisher(IEndpointInstance endpoint)
{
instance = endpoint;
}
public void Send(object message)
{
instance.Send(message, sendOptions);
}
public void Publish(object message)
{
instance.Publish(message, sendOptions);
}
}
This is a simplification of what actually happens but illustrates my problem.
Now when the DI container is asked for an IEventPublisher it knows to return a NsbEventPublisher and it knows to resolve the IEndpointInstance as we bind this in the bootstrapper for the website to the container as a singleton.
All is fine and my site runs perfect.
I am now migrating the micro-services (running in NSB.Host) and the DI container is refusing to resolve IEndpointInstance when resolving the dependencies within a message handler. Reading the docs this is intentional and I should be using IMessageHandlerContext when in a message handler.
https://docs.particular.net/nservicebus/upgrades/5to6/moving-away-from-ibus
The docs even elude to the issue I have in the bottom example around the class MyContextAccessingDependency. The suggestion is to pass the message context through the method which puts a hard dependency on the code running in the context of a message handler.
What I would like to do is have access to a sender/publisher and the DI container can give me the correct implementation. The code does not need any concept of the caller and if it was called from a message handler or from a self hosted application that just wants to publish.
I see that there is two interfaces for communicating with the "Bus" IPipelineContext and IMessageSession which IMessageHandlerContext and IEndpointInstance interfaces extend respectively.
What I am wondering is there some unification of the two interfaces that gets bound by NSB into the container so I can accept an interface that sends/publishes messages. In a handler it is an IMessageHandlerContext and on my self hosted application the IEndPointInstance.
For now I am looking to change my implementation of IEventPublisher depending on application hosting. I was just hoping there might be some discussion about how this approach is modeled without a reliable interface to send/publish irrespective of what initiated the execution of the code path.
A few things to note before I get to the code:
The abstraction over abstraction promise, never works. I have never seen the argument of "I'm going to abstract ESB/Messaging/Database/ORM so that I can swap it in future" work. ever.
When you abstract message sending functionality like that, you'll lose some of the features the library provides. In this case, you can't perform 'Conversations' or use 'Sagas' which would hinder your overall experience, e.g. when using monitoring tools and watching diagrams in ServiceInsight, you won't see the whole picture but only nugets of messages passing through the system.
Now in order to make that work, you need to register IEndpointInstance in your container when your endpoint starts up. Then that interface can be used in your dependency injection e.g. in NsbEventPublisher to send the messages.
Something like this (depending which IoC container you're using, here I assume Autofac):
static async Task AsyncMain()
{
IEndpointInstance endpoint = null;
var builder = new ContainerBuilder();
builder.Register(x => endpoint)
.As<IEndpointInstance>()
.SingleInstance();
//Endpoint configuration goes here...
endpoint = await Endpoint.Start(busConfiguration)
.ConfigureAwait(false);
}
The issues with using IEndpointInstance / IMessageSession are mentioned here.

Using Non Serializable objects in Activiti BPMN

I want to use Activiti BPMN process for some database update task. My process is as follows.
Start Event-> Service Task 1 -> Service Task 2 -> Service Task 3 -> End Event
In the service implementation class of Service task 1 : I created a java.sql.Connection for MySQL database. I need to pass the same Connection object to the Service Task 2 and Service Task 3. Basically those two classes will do some insertions for the database using the same Connection object.
I tried as follows (dbConn is the the Class which contains java.sql.Connection type dbConnection)
execution.setVariable("DBConn",dbConn);
But it gives an exception since the connection object is not serializable.
"org.activiti.engine.ActivitiException: Couldn't serialize value"
So what is the best way to pass such non serializable variables between service tasks of a process? Or is there any way to define such common objects to multiple Service Tasks in one place and use them within service Tasks ( Something like global variables for the process)
You can use Thradlocal in Java to pass connection object to different service tasks.
For example use a Base class like below and extend each service task from that. Then you can set the dbConnection and use whenever required by using get method.
public class BaseServiceTask
{
public static final ThreadLocal<Connection> localConnectionContext = new ThreadLocal<Connection>();
public static void initDBConnector(Connection dbConn)
{
localConnectionContext.set(dbConn);
}
public static Connection getDBConnector()
{
return localConnectionContext.get();
}
}
Notice :
This approach assumes all service tasks are executed in the same thread, which is the case for this particular question, but once you include some user task / timer (or any asynchronous logic) this is not a viable solution anymore !
First, you should be aware that there is absolutely no way to serialize a connection instance once it got created according to this.
The reason is that a connection uses a network resource (such as a TCP/IP socket) which uses the network stack on the machine, and eventually the machine's hardware.
Which leaves you only this alternative:
Setup a bean that will store the connection instances for you, let's call it myConnectionRegistry, this bean should be scoped as singleton and injected in all your java delegates (Service task implementations)
In the first task, you create the connection and then register it into myConnectionRegistry with something like this connectionRegistry.register(conn, wfId) which would add the connection instance to a private map ....
In the subsequent tasks, you retrieve your task from that same bean using a method that fetches the connection object from the private map, and throwing an exception if no connection object was registered in the map
Have a boundary event that gets fired on that exception and do whatever is necessary to insure data integrity (the use case i described in my comment for instance)
In the last Service task, un-register your connection (you should also close it) in order to prevent memory leaks
Make sure to take into account the db pool ... etc while designing your solution!
Cheers!

Ninject DependencyCreation and EventBroker extensions. Ensuring a one-to-one subscription

I'm using Ninject Event Broker extensions and I have two services. ServiceOne is the Publisher of an event. ServiceTwo is the subscriber. ServiceOne doesn't have a hard dependency to ServiceTwo, I'm creating the dependency using the DependencyCreation extension.
Here are the requirements:
I want to define a one-to-one event between these two objects. Only the ServiceTwo instance created by DependencyCreation should receive the event.
If there are other instances of ServiceTwo further down in the object
graph they shouldn't receive the event. (this shouldn't be the case
but I want to account for it)
ServiceTwo should be disposed of when ServiceOne is disposed.
This is a web application and the life of ServiceOne should only be
for one request.
Basically I'm just trying to recreate the behaviour of me writing:
var publisher = new Publisher();
var subscriber = new Subscriber();
var subscriber2 = new Subscriber();
publisher.MyEvent += subscriber.MyEventHandler;
One publisher. One subscriber. Subscriber2 doesn't get the event.
Here's my code:
this.Bind<IServiceOne, ServiceOne>().To<ServiceOne>().Named("ServiceOne").OwnsEventBroker("ServiceOne").RegisterOnEventBroker("ServiceOne");
this.Kernel.DefineDependency<IServiceOne, IServiceTwo>();
this.Bind<IServiceTwo>().To<ServiceTwo>().WhenParentNamed("ServiceOne").InDependencyCreatorScope().RegisterOnEventBroker("ServiceOne");
Two questions.
Does this fulfill my requirements?
Is there a better way?
I don't normally like to answer my own question but seeing as this has been quiet for a while, I've been testing my code sample and it appears to work fine. To clean up the creation of these dependencies and the whole event broker registration process I created some extension methods. First off an IsPublisher extension that creates a scoped event broker:
public static ISubscriberBuildingSyntax IsPublisher<TPublisher>(this IBindingWhenInNamedWithOrOnSyntax<TPublisher> syntax)
{
string name = Guid.NewGuid().ToString();
syntax.Named(name);
syntax.OwnsEventBroker(name).RegisterOnEventBroker(name);
return new SubscriberBuildingSyntax<TPublisher>(syntax, name);
}
Secondly, a generic CreateSubscriberDependency method that creates a dependency using Dependency Creator:
public ISubscriberBuildingSyntax CreateSubscriberDependency<TSubscriber>() where TSubscriber : class
{
this.syntax.Kernel.DefineDependency<TPublisher, TSubscriber>();
this.syntax.Kernel.Bind<TSubscriber>().ToSelf().WhenParentNamed(this.name).InDependencyCreatorScope().RegisterOnEventBroker(this.name);
return this;
}
I can then call this like so:
this.Bind<IRegistrationService>().To<RegistrationService>()
.IsPublisher()
.CreateSubscriberDependency<RoleService>();
This creates an Event Broker scoped to the RegistrationService instance with a RoleService dependency that is tied to the life of RegistrationService.
I can then register RegistrationService with InRequestScope to limit this to the life of one request.

How to keep vaadin application instances from interfering with eachother?

I've got a Vaadin application and I'm getting some strange behaviour when running two instances of the application at the same time (one in FF, another in IE). I've already removed most static objects (these caused the application to completely reload when used parallel to another open application) and now I can interact normally with the UI without the complete reset. However, I'm now noticing that I'm getting only one user's data in both interfaces. I assume this is caused by singleton objects I'm using to manage some data caching and a SOAP connection. I'd like to know if it's the singleton pattern itself that's causing the strange output or is it just the static instance object I'm keeping?
I've tried using ThreadLocal with my singleton, but all my variables are always null when I try to use them in my singleton's functions. Currently my singleton contains this, which is probably terribly, terribly wrong since it doesn't work.
private static ThreadLocal<SoapClient> instance = new ThreadLocal<SoapClient>();
public static synchronized SoapClient getInstance(){
if (instance.get() == null) {
instance.set(new SoapClient());
}
return instance.get();
}
I chose a singleton object so I'd always have access to the cached data and my user's soap connection everywhere in my application instance, and the only other way I can think of for doing that is to have a static object somewhere, but the static keyword seems to be the cause of all my problems in the first place. Is there any way around this or is there something else causing it?
A better way to instantiate your thread local would be this
ThreadLocal<SoapClient> instance = new ThreadLocal<String>() {
#Override
protected String initialValue() {
return new SoapClient();
}
}
However, your problem here is web app servers "pool" and re-use threads. In Vaadin terms,not every request for an application is processed same thread - i.e. Thread1 could process requests for both App instance 1 and App Instance 2. If your SoapClient caches information appropriate to App instance 1, the UI for App 2 could end up using the SoapClient for App 1.
Assuming (from your description) that "app specific" information is cached in the SoapClient, I would suggest that you
Create and store the SoapClient on your Application object as a normal field (not static, not threadlocal)
If you need to access the application (in order to get the SoapClient), and it's tricky from where you are, use the ThreadLocal access pattern. See the second example on the link. Note that the ThreadLocal is set at the beginning of the HttpRequest, and "unset" at the end, ensuring that any subsequent requests on the same thread do NOT get the same application instance.