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();
Related
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.
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.
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;
I am using NServiceBus is an azure worker role via convention by having configuration in app.config and azure Queue details in .csdef.
I have a rest service that accesses the IBus by doing this:
Configure.Instance.Builder.Build<IBus>()
and works fine!
I have a class that implements IWantToRunAtStartup where I do the configure bootstrapper as follows:
Bootstrapper.With.StructureMap()
.UsingAutoRegistration()
.And.AutoMapper().Start();
I'm losing the IBus reference if I then use the bootstrap container:
Configure.Instance.StructureMapBuilder((IContainer) Bootstrapper.Container);
How do I use Bootsrtrapper.StructureMap and NServiceBus?
Telling us which container you want to use needs to be done from a IConfigureThisEndpoint and IWantCustomInitialization class, example:
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
public void Init()
{
Configure.With()
.StructureMapBuilder((IContainer) Bootstrapper.Container);
}
}
I am using Log4Net as a service which is injected into other services using StructureMap.
How do I ensure the log file includes the calling service class context (class name and/or thread) which is making the log4net calls?
Surely the calling class or thread will always be the logging service which doesn't help me understand where the logging calls are really coming from.
EDIT:
Register code:
ObjectFactory.Initialize(x =>
{
x.For<ILog>().AlwaysUnique().Use(s => s.ParentType == null ?
LogManager.GetLogger(s.BuildStack.Current.ConcreteType) :
LogManager.GetLogger(s.ParentType));
});
Service layer:
public class LoggerService : ILoggerService
{
private readonly ILog log;
public LoggerService(ILog logger)
{
log = logger;
log.Info("Logger started {0}".With(logger.Logger.Name));
}
public void Info(string message)
{
log.Info(message);
}
}
In the logging, I am still always getting the LoggerService as the context so I'll never see what actually called the logger. It doesn't seem to be working correctly. I feel like I'm missing something here...
Edit 2:
I've added a pastie link for a console app here:
http://pastie.org/1897389
I would expect the parent class to be logged but it isn't working at the simplest of levels.
You might want to have a look at Castle Dynamic proxy in order to solve it using AOP. There is an example of using it with Structure Map on the Structure Map Google Group.
Ayende has an example of AOP based logging using Log4Net and Windsor.
I use StructureMap in a lot of the code I generate and I have a StructureMap registry which I use to hook the logger into the context of the class that it is injected into.
For Reference, I'm using the 2.6.2 version of StructureMap but should be fine with 2.5+ where the new .For<>().Use<>() format is utilized.
public class CommonsRegistry : Registry
{
public CommonsRegistry()
{
For<ILogger>().AlwaysUnique().Use(s => s.ParentType == null ? new Log4NetLogger(s.BuildStack.Current.ConcreteType) : new Log4NetLogger(s.ParentType.UnderlyingSystemType.Name));
XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(Path.GetDirectoryName(Assembly.GetAssembly(GetType()).Location), "Log.config")));
}
}
What this registry is doing is for anywhere the ILogger is injected, use the class that it's injected into is where the logging messages are logged to/context of.
*Also, in the second line (XmlConfigurator.ConfigureAndWatch) is where I tell Log4Net to get the logging information from the file "Log.config" instead of the application configuration file, you may or may not like that and can be omitted.
The code I use is a common IOC.Startup routine where I would pass if I would like to use the default registery.
ObjectFactory.Initialize(x =>
{
x.AddRegistry<CommonsRegistry>();
...
}
This gives me the calling class name in the logging instance where messages are logged to automatically and all that is required is to inject the logger into the class.
class foo
{
private readonly ILogger _log;
public foo(ILogger log)
{
_log = log;
}
}
Now the messages are logged as context/class "foo".