MassTransit configured with StructureMap - ContainerScoped not working - structuremap

I've configured a class X with ContainerScope in my StructureMap configuration, but for some reason, when the app initially starts up and MassTransit consumer consumes the initial message, it creates the instance, but on subsequent messages received for that consumer, the consumer is recreated, but not object X (I would expect a new instance is created per message received). I know if I configure it with transient it'll work, but I just want a single instance of that class created for the entirety of the processing of that message.
Any help with this would be greatly appreciated.

When using MassTransit, creating a new consumer instance is the preferred behavior for each message. It is recommended that any state or behavior that needs to be maintained as a single instance across messages is done using a dependency of that consumer (which can be configured in the container by the application developer).
I realize that you are asking how to configure your consumer to be a singleton, and you can probably figure that out, but MassTransit will reconfigure the container to make it scoped for each message if you're using AddMassTransit/AddConsumer.
A better approach is to have your state configured:
public interface IConsumerState
{
}
public class ConsumerState :
IConsumerState
{
}
x.For<IConsumerState>().Use<ConsumerState>().Singleton();
Then, for MassTransit, configure your consumer where your consumer depends upon that interface.
public class Consumer :
IConsume<Message>
{
public Consumer(IConsumerState state)
{
_state = state;
}
public async Consume(ConsumeContext<Message> context)
{
}
}
x.AddMassTransit(m =>
{
m.AddConsumer<Consumer>();
m.AddBus(provider => Bus.Factory.CreateUsingInMemory(cfg =>
{
cfg.ConfigureEndpoints();
}
});
Using this approach, a new consumer is created for each message and the state is maintained/shared by all consumer instances.

Related

Microsoft DI - Are objects referenced within a factory implementation disposed?

Are objects that are referenced, not created, within a factory implementation disposed by the container? See code below:
services.AddTransient(c => OwinContext.ServiceObject);
Will ServiceObject, which implements IDisposable, be disposed by the container considering it isn't created (i.e. new ServiceObject)?
ServiceObject is currently registered as Scoped, but we are getting ObjectDisposedException on the rare occasion. I'm guessing it's getting disposed within OWIN sometimes before our services are able to use it, which is why I was hoping of making it Transient but I'm worried the container will dispose of it more frequently.
Disposable transient registrations are tracked by the container and disposed when their scope ends.
The Microsoft documentation is not always clear about this, as this documentation seems to suggest that "The framework does not dispose of the services automatically" that are "not created by the service container." Although the documentation is not incorrect, as it primarily talks about the registration of instances through the AddSingleton<T>(T instance) extension method — it is misleading because it doesn't hold for:
AddSingleton<T>(Func<IServiceProvider, T>),
AddScoped<T>(Func<IServiceProvider, T>), and
AddTransient<T>(Func<IServiceProvider, T>).
This statement can be easily verified using the following program:
using Microsoft.Extensions.DependencyInjection;
var disposable = new FakeDisposable();
var services = new ServiceCollection();
services.AddTransient(c => disposable);
var provider = services.BuildServiceProvider(validateScopes: true);
using (var scope = provider.CreateScope())
{
scope.ServiceProvider.GetRequiredService<FakeDisposable>();
}
public class FakeDisposable : IDisposable
{
public void Dispose() => Console.WriteLine("Disposed");
}
Output:
Disposed
Conclusion: Yes, transient registrations for disposable objects are disposed of by the container.
There will be little difference between making this registration Transient or Scoped. In both cases the object will get disposed when the scope ends.
In the case of a Transient registration, though, you'll start to see the disposable get disposed of multiple times in case it gets injected multiple times. For instance:
using (var scope = provider.CreateScope())
{
scope.ServiceProvider.GetRequiredService<FakeDisposable>();
scope.ServiceProvider.GetRequiredService<FakeDisposable>();
scope.ServiceProvider.GetRequiredService<FakeDisposable>();
}
Output:
Disposed
Disposed
Disposed
From reliability, however, it's better to stick with a Scoped registration, instead of Transient. This is because MS.DI will prevent Scoped registrations from being injected into Singleton consumers (in case the Service Provider is created by calling BuildServiceProvider(validateScopes: true)). In case your ServiceContext would get injected into a Singleton, it causes it to become a Captive Dependency and keep referenced (and likely used) by that Singleton, long after it got disposed of.
The most likely reason you are getting those ObjectDisposedExceptions is because Owin tries to use the ServiceContext after your (web request) scope is disposed.
The ServiceContext object is likely being controlled and disposed of by OWIN, which doesn't make it a good candidate to be disposed of by the container. But here's the problem: MS.DI will always try to dispose of Transient and Scoped registrations and the only way to prevent this from happening is to not register your ServiceContext.
The solution, therefore, is to wrap it in a "provider" object of some sort. For instance:
// New abstraction
public interface IServiceObjectProvider
{
object ServiceObject { get; }
}
// Implementation part of your Composition Root (see: https://mng.bz/K1qZ)
public class AmbientOwinServiceObjectProvider : IServiceObjectProvider
{
public object ServiceObject => OwinContext.ServiceObject;
}
// Registration:
services.AddScoped<IServiceObjectProvider, AmbientOwinServiceObjectProvider>();
// Usage:
public class MyController : Controller
{
private readonly IServiceObjectProvider provider;
public MyController(IServiceObjectProvider provider)
{
// Only store the dependency here: don't use it,
// see: https://blog.ploeh.dk/2011/03/03/InjectionConstructorsshouldbesimple/
this.provider = provider;
}
public string Index()
{
var so = this.provider.ServiceObject;
// Do something with the Service object
}
}

SignalR with orleans how to pass SignalR from startup to grain

I am very new with orleans and trying to grasp everything with grains and so forth.
What i got is that in my startup.cs file i add the SignalR like this
public IServiceProvider ConfigureServices(IServiceCollection services)
{
Program.WriteConsole("Adding singletons");
services
.AddSingleton(achievementManager)
.AddMvc();
services.AddSingleton(SignalRClient);
return services.BuildServiceProvider();
}
So far everything is fine i can start my host/application and it connects to SignalR as it should. But what i cant wrap my head around is how do i get this down to my grain? if i had a controller i would simply send it down in the constructor on startup but how do i do this with a grain? Or can i even do it like this. Any guidance is appreciated.
In the grain then i want to do something like this
[StatelessWorker]
[Reentrant]
public class NotifierGrain : Grain, INotifierGrain
{
private HubConnection SignalRClient { get; }
public NotifierGrain(HubConnection signalRClient)
{
SignalRClient = signalRClient;
SignalRClient.SendAsync(Methods.RegisterService, Constants.ServiceName);
}
public Task NotifyClients(object message, MessageType type)
{
var registerUserNotification = (RegisterUserNotificationModel)message;
SignalRClient.SendAsync(Methods.RegisterUserToMultipleGroups, registerUserNotification.UserId, registerUserNotification.InfoIds);
}
return Task.CompletedTask;
}
Then i try to call the Notify method from another grain like this
var notifier = GrainFactory.GetGrain<INotifierGrain>(Constants.NotifierGrain);
await notifier.NotifyClients(notification, MessageType.RegisterUser);
But trying to do this ends up with an error like this
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.SignalR.Client.HubConnection' while attempting to activate 'User.Implementation.Grains.NotifierGrain'.
Orleans supports constructor injection, so you can inject the SignalRClient into your grain constructor. In your code you are already correctly registering the client using services.AddSingleton(SignalRClient), so I will focus on how to inject the type into your grain.
I do not know what the type the SignalR client object is, but in this example I assume that the type is "SignalRClient":
[StatelessWorker]
[Reentrant]
public class NotifierGrain : Grain, INotifierGrain
{
private readonly SignalRClient signalRClient;
public NotifierGrain(SignalRClient signalRClient)
{
this.signalRClient = signalRClient;
}
public async Task NotifyClients(object message, MessageType type)
{
var registerUserNotification = (RegisterUserNotificationModel)message;
await this.signalRClient.SendAsync(
MessageMethods.RegisterUserToMultipleGroups,
registerUserNotification.UserId,
registerUserNotification.infoIds);
}
}
Depends how you're thinking to use SignalR Server, if you're going to host your SignalR server with Microsoft Orleans for sure you need to have backplane to handle the Orleans cluster communications.
You can use SignalR Orleans which has everything done out of the box for you :)
Also if you need a reactive SignalR library for the frontend, you can use Sketch7 SignalR Client
PS I m one of the authors of both libraries.

Inject OSGi Services in a non-component class

Usually I have seen in OSGi development that one service binds to another service. However I am trying to inject an OSGi service in a non-service class.
Scenario trying to achieve: I have implemented a MessageBusListener which is an OSGi service and binds to couple of more services like QueueExecutor etc.
Now one of the tasks of the MessageBusListener is to create a FlowListener (non-service class) which would invoke the flows based on the message content. This FlowListener requires OSGi services like QueueExecutor to invoke the flow.
One of the approach I tried was to pass the reference of the services while creating the instance of FlowListener from MessageBusListener. However when the parameterized services are deactivated and activated back, I think OSGi service would create a new instance of a service and bind to MessageBusListener, but FlowListener would still have a stale reference.
#Component
public class MessageBusListener
{
private final AtomicReference<QueueExecutor> queueExecutor = new AtomicReference<>();
#Activate
protected void activate(Map<String, Object> osgiMap)
{
FlowListener f1 = new FlowListener(queueExeciutor)
}
Reference (service = QueueExecutor.class, cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.STATIC)
protected void bindQueueExecutor(QueueExecutor queueExecutor)
{
this.queueExecutor = queueExecutor;
}
}
public class FlowListener
{
private final AtomicReference<QueueExecutor> queueExecutor;
FlowListener(QueueExecutor queueExecutor)
{
this.queueExecutor = queueExecutor;
}
queueExecutor.doSomething() *// This would fail in case the QueueExecutor
service was deactivated and activated again*
}
Looking forward to other approaches which could suffice my requirement.
Your approach is correct you just need to also handle the deactivation if necessary.
If the QueueExecutor disappears the MessageBuslistener will be shut down. You can handle this using a #Deactivate method. In this method you can then also call a sutdown method of FlowListener.
If a new QeueExecutor service comes up then DS will create a new MessageBuslistener so all should be fine.
Btw. you can simply inject the QueueExecutor using:
#Reference
QueueExecutor queueExecutor;

Rebus multiple Queues based on content

Setup: Rebus in asp.net mvc project using SimpleInjector.
I need to create two handlers which receive messages, each from a specific queue. By following what I have found on this SO answer I have created similar code.
In a class library I have a class which implements SimpleInjector IPackage which have a code like this:
public void RegisterServices( Container container ) {
container.Register<IHandleMessages<MyMessage>, MyMessageHandler>( Lifestyle.Scoped );
IContainerAdapter adapter = new SimpleInjectorContainerAdapter( container );
Configure.With( adapter )
.Transport( t => t.UseAzureServiceBus( connectionString, "A_QUEUE_NAME", AzureServiceBusMode.Standard ) )
.Options( oc => {
oc.SetNumberOfWorkers( 1 );
oc.SimpleRetryStrategy( errorQueueAddress: "A_ERROR_QUEUE_NAME", maxDeliveryAttempts: 3 );
} )
.Start();
Configure.With(adapter
.Transport(t => t.UseAzureServiceBus(connectionString, "B_QUEUE_NAME")
.Options( oc => {
oc.SetNumberOfWorkers( 1 );
oc.SimpleRetryStrategy( errorQueueAddress: "B_ERROR_QUEUE_NAME", maxDeliveryAttempts: 3 );
} )
.Start();
}
However when the debugger get to the second Configure.With( ... ) call i terminates with an error saying:
Type IBus has already been registered. If your intention is to resolve a collection of IBus implementations, use the RegisterCollection overloads. More info: https://simpleinjector.org/coll1. If your intention is to replace the existing registration with this new registration, you can allow overriding the current registration by setting Container.Options.AllowOverridingRegistrations to true. More info: https://simpleinjector.org/ovrrd.
Stack trace:
[InvalidOperationException: Type IBus has already been registered. If your intention is to resolve a collection of IBus implementations, use the RegisterCollection overloads. More info: https://simpleinjector.org/coll1. If your intention is to replace the existing registration with this new registration, you can allow overriding the current registration by setting Container.Options.AllowOverridingRegistrations to true. More info: https://simpleinjector.org/ovrrd.]
SimpleInjector.Internals.NonGenericRegistrationEntry.ThrowWhenTypeAlreadyRegistered(InstanceProducer producer) +102
SimpleInjector.Internals.NonGenericRegistrationEntry.Add(InstanceProducer producer) +59
SimpleInjector.Container.AddInstanceProducer(InstanceProducer producer) +105
SimpleInjector.Container.AddRegistrationInternal(Type serviceType, Registration registration) +69
SimpleInjector.Container.AddRegistration(Type serviceType, Registration registration) +131
SimpleInjector.Container.RegisterSingleton(TService instance) +183
Rebus.SimpleInjector.SimpleInjectorContainerAdapter.SetBus(IBus bus) +55
Rebus.Config.RebusConfigurer.Start() +2356
MyModule.RegisterServices(Container container) +497
SimpleInjector.PackageExtensions.RegisterPackages(Container container, IEnumerable`1 assemblies) +50
Myproject.SimpleInjectorInitializer.InitializeContainer(Container container) +35
Myproject.SimpleInjectorInitializer.Initialize() +68
Myproject.Startup.Configuration(IAppBuilder app) +28
EDIT
I have then removed the second Configure.With( ... ) block of code and now when I do a _bus.Send( message ) I get another error in the consumer process which says
Unhandled exception 1 while handling message with ID fef3acca-97f4-4495-b09d-96e6c9f66c4d: SimpleInjector.ActivationException: No registration for type IEnumerable<IHandleMessages<MyMessage>> could be found. There is, however, a registration for IHandleMessages<MyMessage>; Did you mean to call GetInstance<IHandleMessages<MyMessage>>() or depend on IHandleMessages<MyMessage>? Or did you mean to register a collection of types using RegisterCollection?
Stack Trace:
2017-04-13 10:21:03,805 [77] WARN Rebus.Retry.ErrorTracking.InMemErrorTracker -
at SimpleInjector.Container.ThrowMissingInstanceProducerException(Type serviceType)
at SimpleInjector.Container.GetInstanceForRootType[TService]()
at SimpleInjector.Container.GetInstance[TService]()
at SimpleInjector.Container.GetAllInstances[TService]()
at Rebus.SimpleInjector.SimpleInjectorContainerAdapter.<GetHandlers>d__3`1.MoveNext()
I usually recommend keeping only one single IBus per container instance, because the bus can considered "an application" in itself, which happens to fit nicely with the fact that an IoC container is an object that can "host" an application for the duration of its lifetime.
Rebus does not provide a Conforming Container abstraction, because I agree with Mark Seemann that that is a project that is doomed to fail. In fact, as the wiki page mentions, Rebus used to provide automatic registration of handlers, but that turned out to be problematic.
Instead, Rebus encourages you to provide a "container adapter" (implementation of IContainerAdapter) whose responsibilities are:
look up handlers
provide a way to register IBus and IMessageContext in The Correct Way
where container adapters are provided out of the box for Autofac, Castle Windsor, SimpleInjector, etc. However, providing a container adapter is not required – the Configure.With(...) rant is happy with receiving only a "handler activator" (implementation of IHandlerActivator), so if you only want to use your IoC container to look up handlers and take care of registering IBus yourself, you can do that too by implementing IHandlerActivator and looking up handlers in your container.
TL;DR: The Rebus Way is to treat an instance of your IoC container as a separate application, and therefore it makes sense to register only one IBus in it.
It is perfectly fine to new up multiple container instances of you want to host multiple applications (or even multiple instances of your application with different message SLAs) in a single process.
The exception states: "Type IBus has already been registered". According to your stack trace, the second time IBus is being added is inside the SimpleInjectorContainerAdapter. You will have to find out when it was registered for the first time. This is easy to do; just registered a dummy IBus as very first registration after creating the Container and take a look at the stack trace where it blows up.
You cited my SO Answer (question), so I’ll share with you how I implemented it.
As you will see, using specific interfaces, I separated commands from events.
Then, just in the consuming part of the queue, I did this kind of registrations:
public static void Register()
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(i => i.FullName.StartsWith("MySolutionPrefix"))
;
var container = new Container();
// http://simpleinjector.readthedocs.io/en/latest/lifetimes.html#perexecutioncontextscope
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
var serviceType = typeof(IHandleMessages<>).Name;
// this is extension method to get specific handlers
IEnumerable<Type> commandHandlers = assemblies.GetHandlers(serviceType, typeof(ICommand));
container.Register(typeof(IHandleMessages<>), commandHandlers.Concat(new List<Type> { typeof(HistorizeCommandHanlder) }));
// NOTE Just command Handlers
container.RegisterCollection(typeof(IHandleMessages<>), commandHandlers);
var bus = Configure.With(new SimpleInjectorContainerAdapter(container))
//.... logging, transport (I created my own transport on mongoDb), routing, sagas and so on
.Options(o =>
{
// This simply my personal transport as Register<IOneWayClientTransport>
o.ConfigureDecouplingDatabase(db, settings.TopicBasedMessageQueueName);
// this is more complicated because i want that automatically the message is copied on
// a separate topic for each handler
o.EnableHandlerDecoupling(settings.DecouplingHandlersRegistration);
})
.Start();
container.Verify();
// It is necessary because otherwise it sends published messages to no-one
commandHandlers.GetHandledSubTypes(serviceType, typeof(IVersionedEvent))
.ToList()
.ForEach(i => bus.Subscribe(i).Wait());
// NOTE just events handlers
IEnumerable<Type> eventHandlers = assemblies
.GetHandlers(serviceType, typeof(IVersionedEvent))
.Except(commandHandlers)
//.Except(new List<Type> { typeof(TempHandlerLogDecorator) })
;
foreach (var handler in eventHandlers)
ConfigureServiceBus(mongoDbConnectionProvider, db, handler.FullName, new[] { handler });
}
private static IBus ConfigureServiceBus(MongoDbConnectionProvider mongoDbConnectionProvider, IMongoDatabase db, string inputQueueName, IEnumerable<Type> handlers)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
container.RegisterCollection(typeof(IHandleMessages<>), handlers);
var bus = Configure.With(new SimpleInjectorContainerAdapter(container))
.... logging, Subscriptions
// this is a consumer only for inputQueueName
.Transport(t => t.UseMongoDb(db, settings.TopicBasedMessageQueueName, inputQueueName))
.Options(o =>
{
o.ConfigureDecouplingDatabase(db, settings.TopicBasedMessageQueueName);
o.EnableHandlerDecoupling(settings.DecouplingHandlersRegistration);
})
.Start();
container.Verify();
handlers.GetHandledSubTypes(typeof(IHandleMessages<>).Name, typeof(IVersionedEvent))
.ToList()
.ForEach(i => bus.Advanced.Topics.Subscribe(i.GetDecoupledTopic(settings.DecouplingHandlersRegistration)).Wait());
return bus;
}
I'm still using Rebus 3.0.1 and SimpleInjector 3.2.3.

How to use a Singleton Signalr client within an MVC application

I have a need to use a .net client to connect to a Signalr enabled application.
The client class needs to be a singleton and loaded for use globally.
I want to know what is the best technique for using singletons globally within an MVC application.
I have been looking into using the application start to get the singleton, where I keep it is a mystery to me.
The HUB cant be a singleton by design SignalR creates a instance for each incoming request.
On the client I would use a IoC framework and register the client as a Singleton, this way eachb module that tries to get it will get the same instance.
I have made a little lib that takes care of all this for you, install server like
Install-Package SignalR.EventAggregatorProxy
Read here for the few steps to hook it up, it needs a back plate service bus or event aggregator to be able to pickup your events
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/wiki
Once configured install the .NET client in your client project with
Install-Package SignalR.EventAggregatorProxy.Client.DotNet
See here how to set it up
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/wiki/.NET-Client
Once configured any class can register itself as a listener like
public class MyViewModel : IHandle<MyEvent>
{
public MyViewModel(IEventAggregator eventAggregator)
{
eventAggregator.Subscribe(this);
}
public void Handle(MyEvent message)
{
//Act on MyEvent
}
}
On the server you can send a message from outside the hub to all connected clients using the GetClients() method like this:
public MyHub : Hub
{
// (Your hub methods)
public static IHubConnectionContext GetClients()
{
return GlobalHost.ConnectionManager.GetHubContext<MyHub>().Clients;
}
}
You can use it like this:
MyHub.GetClients().All.SomeMethod();

Resources