SIgnalR- not use singleton pattern - c#

In my application, I am sending real-time updates to each client based on his subscriptions.
So e.g. if a client is subscribed to items 1,2 & 3 he should only see updates from these items while at the same time if another client is subscribed to items 4,5 & 6 then he should be able to receive real-time updates for those items.
My problem is as soon as I connect with the second id SignalR forgets about the old group and starts notification of new ids only.
I guess it's because there's only one instance of real-time updates is running and it's being shared among all connected clients. Is there a way that each connected client has its own instance of a real-time object?
public class DataHub : Hub
{
private readonly RealTimeData data;
public DataHub() : this(RealTimeData.Instance) { }
public DataHub(RealTimeData rdata)
{
data = rdata; //can I instantiate RealTimeData object here?
}
public void Start(Int64 routerId)
{
data.StartTimer(routerId);
}
}
public class RealTimeData
{
private readonly static Lazy<RealTimeData> _instance = new Lazy<RealTimeData>(() => new RealTimeData(GlobalHost.ConnectionManager.GetHubContext<DataHub>().Clients)); //will avoiding this create a separate instance for each client?
private IHubConnectionContext Clients;
public Timer timer;
private readonly int updateInterval = 1000;
private readonly object updateRecievedDataLock = new object();
private bool updateReceivedData = false;
List<Items> allItems = new List<Items>();
private RealTimeData()
{
}
private RealTimeData(IHubConnectionContext clients)
{
Clients = clients;
}
public static RealTimeData Instance
{
get
{
return _instance.Value;
}
}
public void StartTimer(Int64 routerId)
{
this.routerId = routerId;
timer = new Timer(GetDataForAllItems, null, updateInterval, updateInterval);
}
public void GetDataForAllItems(object state)
{
if (updateReceivedData)
{
return;
}
lock (updateRecievedDataLock)
{
if (!updateReceivedData)
{
updateReceivedData = true;
//get data from database
allItems = Mapper.Instance.GetDataForAllItems(routerId);
updateReceivedData = false;
//send it to the browser for update
BroadcastData(allItems);
}
}
}
}

I think you are attacking the problem from a wrong angle. Instead of polling the DB each second let the action that saves to the DB publish a message on a message bus that you forward to the Clients.
Have a look at this library,
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy
Demo project
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/tree/master/SignalR.EventAggregatorProxy.Demo.MVC4
Disclaimer: I'm the author of the library

Group subscriptions in SignalR v2 are handled by using the this.Groups.Add and this.Groups.Remove methods in the Hub > HubBase ancestor class.
These methods could be used to subscribe to group 1,2,3 or 4,5,6 in your example by using something like this.
public class DataHub : Hub
{
public async Task Register(int groupNumber)
{
await this.Groups.Add(this.Context.ConnectionId, groupNumber.ToString());
}
public async Task Unregister(int groupNumber)
{
await this.Groups.Remove(this.Context.ConnectionId, groupNumber.ToString());
}
}
On the client this would be called by passing a group number to the Register/Unregister methods. An example might be:
this._DataHub.Invoke("Register", "1");
From you RealTimeData singleton or other business class that publishes the update, you would reference GlobalHost.ConnectionManager.GetHubContext<DataHub>() and call then use .Clients.Group("1").<clientMethod> to invoke the client-side method.
For example:
var hubContext = GlobalHost.ConnectionManager.GetHubContext<DataHub>();
hubContext.Clients.Group("1").UpdateDisplay("New tweet");
To read up a bit more of this have a look at http://www.asp.net/signalr/overview
I hope this answers the question.

Related

Triggering DynamicData cache update using Reactive Subject

As a caveat I'm a novice with Rx (2 weeks) and have been experimenting with using Rx, RxUI and Roland Pheasant's DynamicData.
I have a service that initially loads data from local persistence and then, upon some user (or system) instruction will contact the server (TriggerServer in the example) to get additional or replacement data. The solution I've come up with uses a Subject and I've come across many a site discussing the pros/cons of using them. Although I understand the basics of hot/cold it's all based on reading rather than real world.
So, using the below as a simplified version, is this 'right' way of going about this problem or is there something I haven't properly understood somewhere?
NB: I'm not sure how important it is, but the actual code is taken from a Xamarin.Forms app, that uses RxUI, the user input being a ReactiveCommand.
Example:
using DynamicData;
using System;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
public class MyService : IDisposable
{
private CompositeDisposable _cleanup;
private Subject<Unit> _serverSubject = new Subject<Unit>();
public MyService()
{
var data = Initialise().Publish();
AllData = data.AsObservableCache();
_cleanup = new CompositeDisposable(AllData, data.Connect());
}
public IObservableCache<MyData, Guid> AllData { get; }
public void TriggerServer()
{
// This is what I'm not sure about...
_serverSubject.OnNext(Unit.Default);
}
private IObservable<IChangeSet<MyData, Guid>> Initialise()
{
return ObservableChangeSet.Create<MyData, Guid>(async cache =>
{
// inital load - is this okay?
cache.AddOrUpdate(await LoadLocalData());
// is this a valid way of doing this?
var sync = _serverSubject.Select(_ => GetDataFromServer())
.Subscribe(async task =>
{
var data = await task.ConfigureAwait(false);
cache.AddOrUpdate(data);
});
return new CompositeDisposable(sync);
}, d=> d.Id);
}
private IObservable<MyData> LoadLocalData()
{
return Observable.Timer(TimeSpan.FromSeconds(3)).Select(_ => new MyData("localdata"));
}
private async Task<MyData> GetDataFromServer()
{
await Task.Delay(2000).ConfigureAwait(true);
return new MyData("serverdata");
}
public void Dispose()
{
_cleanup?.Dispose();
}
}
public class MyData
{
public MyData(string value)
{
Value = value;
}
public Guid Id { get; } = Guid.NewGuid();
public string Value { get; set; }
}
And a simple Console app to run:
public static class TestProgram
{
public static void Main()
{
var service = new MyService();
service.AllData.Connect()
.Bind(out var myData)
.Subscribe(_=> Console.WriteLine("data in"), ()=> Console.WriteLine("COMPLETE"));
while (Continue())
{
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine($"Triggering Server Call, current data is: {string.Join(", ", myData.Select(x=> x.Value))}");
service.TriggerServer();
}
}
private static bool Continue()
{
Console.WriteLine("Press any key to call server, x to exit");
var key = Console.ReadKey();
return key.Key != ConsoleKey.X;
}
}
Looks very good for first try with Rx
I would suggest few changes:
1) Remove the Initialize() call from the constructor and make it a public method - helps a lot with unit tests and now you can await it if you need to
public static void Main()
{
var service = new MyService();
service.Initialize();
2) Add Throttle to you trigger - this fixes parallel calls to the server returning the same results
3) Don't do anything that can throw in Subscribe, use Do instead:
var sync = _serverSubject
.Throttle(Timespan.FromSeconds(0.5), RxApp.TaskPoolScheduler) // you can pass a scheduler via arguments, or use TestScheduler in unit tests to make time pass faster
.Do(async _ =>
{
var data = await GetDataFromServer().ConfigureAwait(false); // I just think this is more readable, your way was also correct
cache.AddOrUpdate(data);
})
// .Retry(); // or anything alese to handle failures
.Subscribe();
I'm putting what I've come to as my solution just in case there's others that find this while they're wandering the internets.
I ended up removing the Subjects all together and chaining together several SourceCache, so when one changed it pushed into the other and so on. I've removed some code for brevity:
public class MyService : IDisposable
{
private SourceCache<MyData, Guid> _localCache = new SourceCache<MyData, Guid>(x=> x.Id);
private SourceCache<MyData, Guid> _serverCache = new SourceCache<MyData, Guid>(x=> x.Id);
public MyService()
{
var localdata = _localCache.Connect();
var serverdata = _serverCache.Connect();
var alldata = localdata.Merge(serverdata);
AllData = alldata.AsObservableCache();
}
public IObservableCache<MyData, Guid> AllData { get; }
public IObservable<Unit> TriggerLocal()
{
return LoadLocalAsync().ToObservable();
}
public IObservable<Unit> TriggerServer()
{
return LoadServerAsync().ToObservable();
}
}
EDIT: I've changed this again to remove any chaining of caches - I just manage the one cache internally. Lesson is not to post too early.

Proper way to rise an event from one class and handle it in other class

I am building api for one application. what i want is when I get a new order, i have to insert it in DB and I want to rise an event (without blocking my api call may be async). so that latter in other class i can handle that event and do the other work like send the new order notification to account and send order update to user using pubnub.
public class OrderService : IOrderService
{
public delegate void OrderEventHandler(Order order,bool isNewOrder);
public static event OrderEventHandler OrderEvents = delegate { };
public OrderService()
{
OrderEventListener listener = new OrderEventListener();
OrderEvents += new OrderEventHandler(listener.HandleOrderEvents);
}
#region Methods
public void Test()
{
INPRODataFacade facade = new NPRODataFacade();
var unitOfWork = facade.GetUnitOfWork();
var order = unitOfWork.OrderRepository.Find(o => o.OrderID == 1).FirstOrDefault();
unitOfWork.Commit();
facade.ReturnUnitOfWork();
RiseEvent(order,true);
}
private async System.Threading.Tasks.Task RiseEvent(Order order,bool isNewOrder)
{
if (order == null)
{
return;
}
OrderEvents(order,isNewOrder);
}
}
public class OrderEventListener
{
PubNub.PubNub pubNub = null;
const string ChanelPrifix = "fasttract";
public OrderEventListener()
{
pubNub = new PubNub.PubNub(ConfigurationSettings.PubNub_SubscribeKey, ConfigurationSettings.PubNub_PublishKey, ConfigurationSettings.PubNub_SecretKey, ConfigurationSettings.PubNub_SSlOn);
}
public void HandleOrderEvents(Order order, bool isNewOrder)
{
string chanelName = isNewOrder ? string.Format("{0}_{1}", ChanelPrifix, order.AccountID)
: string.Format("{0}_{1}_{2}", ChanelPrifix, order.AccountID, order.OrderID);
var channel = pubNub.Channel(chanelName);
channel.Publish(new PubNubMessageModel { Message = GetMessage( order, isNewOrder) });
}
public string GetMessage(Order order,bool isNewOrder)
{
string message = string.Empty;
if(isNewOrder)
{
message = "You have recieved a new order #" + order.OrderID;
return message;
}
message = order.Status.ToString();
return message;
}
}
Here have noticed that it is blocking my api call. means I am not getting api response back until event handler finished its execution. is this the right way to handle events ? I think there should be a way that i just add events while getting new order and then in listener i process that events anytime without blocking api call.

Create a Notification Object (Email or Page) At Run Time -- Dependency Injection or Factory

I have some code that emails me a notification when something happens. Now I am trying to add a Page and ALSO remove the dependency on Email.
For reference; I have the name of the notification I want to send stored as a string in the database. At runtime I have a list of people and a string representation of what they want to receive.
I initially thought dependency injection with ninject, but the kernel bindings got large and it seemed like I was hacking it together.
Then I thought simple factory, with Activator.CreateInstance(Email/Page) as INotifcation, but I don't know how to handle the differing constructor parameters (unless I use a common, complex property, like Employee, which has all the information I need).
So far I have something like this:
public interface INotification
{
void SendMessage();
}
public class Email: INotification
{
private readonly string _toEmailAddress;
private string Body
{
get
{
return "Email";
}
}
private static string SmtpHost
{
get
{
return ConfigurationManager.AppSettings["SmtpHost"];
}
}
public Email( string toEmailAddress)
{
_toEmailAddress = toEmailAddress;
}
public void SendMessage()
{
var requestEmail = new MailMessage
{
From = new MailAddress(FromEmailAddress, FromDisplayName),
};
requestEmail.To.Add(new MailAddress(_toEmailAddress));
var smtp = new SmtpClient { Host = SmtpHost };
smtp.Send(requestEmail);
}
}
public class Page : INotification
{
private string ToPagerNumber;
public Page(string toPagerNumber)
{
ToPagerNumber = toPagerNumber;
}
private static string IpAddress
{
get
{
var host = new IPHostEntry();
return host.AddressList.Where(a => a.AddressFamily == AddressFamily.InterNetwork).ToString();
}
}
public void SendMessage()
{
var pageProxy = new Pager();
var serviceResult = pageProxy.SendPage(ToPagerNumber, "Test", true, IpAddress);
}
I certainly appreciate all the feedback. I feel like I could have accomplished this several times over, but finding that perfect solution (though I contend there may not be one) has proven onerous.
Thanks everyone!

How can Ninject be configured to always deactivate pooled references?

We're using a library that uses pooled objects (ServiceStack.Redis's PooledRedisClientManager). Objects are created and reused for multiple web requests. However, Dispose should be called after each use to release the object back into the pool.
By default, Ninject only deactivates an object reference if it has not been deactivated before.
What happens is that the pool instantiates an object and marks it as active. Ninject then runs the activation pipeline. At the end of the request (a web request), Ninject runs the deactivation pipeline which calls Dispose (and thus the pool marks the object as inactive). The next request: the first pooled instance is used and the pool marks it as active. However, at the end of the request, Ninject does not run its deactivation pipeline because the ActivationCache has already marked this instance as deactivated (this is in the Pipeline).
Here's a simple sample that we've added in a new MVC project to demonstrate this problem:
public interface IFooFactory
{
IFooClient GetClient();
void DisposeClient(FooClient client);
}
public class PooledFooClientFactory : IFooFactory
{
private readonly List<FooClient> pool = new List<FooClient>();
public IFooClient GetClient()
{
lock (pool)
{
var client = pool.SingleOrDefault(c => !c.Active);
if (client == null)
{
client = new FooClient(pool.Count + 1);
client.Factory = this;
pool.Add(client);
}
client.Active = true;
return client;
}
}
public void DisposeClient(FooClient client)
{
client.Active = false;
}
}
public interface IFooClient
{
void Use();
}
public class FooClient : IFooClient, IDisposable
{
internal IFooFactory Factory { get; set; }
internal bool Active { get; set; }
internal int Id { get; private set; }
public FooClient(int id)
{
this.Id = id;
}
public void Dispose()
{
if (Factory != null)
{
Factory.DisposeClient(this);
}
}
public void Use()
{
Console.WriteLine("Using...");
}
}
public class HomeController : Controller
{
private IFooClient foo;
public HomeController(IFooClient foo)
{
this.foo = foo;
}
public ActionResult Index()
{
foo.Use();
return View();
}
public ActionResult About()
{
return View();
}
}
// In the Ninject configuration (NinjectWebCommon.cs)
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFooFactory>()
.To<PooledFooClientFactory>()
.InSingletonScope();
kernel.Bind<IFooClient>()
.ToMethod(ctx => ctx.Kernel.Get<IFooFactory>().GetClient())
.InRequestScope();
}
The solutions that we've come up with thus far are:
Mark these objects as InTransientScope() and use other deactivation mechanism (like an MVC ActionFilter to dispose of the object after each request). We'd lose the benefits of Ninject's deactivation process and require an indirect approach to disposing of the object.
Write a custom IActivationCache that checks the pool to see if the object is active. Here's what I've written so far, but I'd like some one else's eyes to see how robust it is:
public class PooledFooClientActivationCache : DisposableObject, IActivationCache, INinjectComponent, IDisposable, IPruneable
{
private readonly ActivationCache realCache;
public PooledFooClientActivationCache(ICachePruner cachePruner)
{
realCache = new ActivationCache(cachePruner);
}
public void AddActivatedInstance(object instance)
{
realCache.AddActivatedInstance(instance);
}
public void AddDeactivatedInstance(object instance)
{
realCache.AddDeactivatedInstance(instance);
}
public void Clear()
{
realCache.Clear();
}
public bool IsActivated(object instance)
{
lock (realCache)
{
var fooClient = instance as FooClient;
if (fooClient != null) return fooClient.Active;
return realCache.IsActivated(instance);
}
}
public bool IsDeactivated(object instance)
{
lock (realCache)
{
var fooClient = instance as FooClient;
if (fooClient != null) return !fooClient.Active;
return realCache.IsDeactivated(instance);
}
}
public Ninject.INinjectSettings Settings
{
get
{
return realCache.Settings;
}
set
{
realCache.Settings = value;
}
}
public void Prune()
{
realCache.Prune();
}
}
// Wire it up:
kernel.Components.RemoveAll<IActivationCache>();
kernel.Components.Add<IActivationCache, PooledFooClientActivationCache>();
Specifically for ServiceStack.Redis's: use the PooledRedisClientManager.DisposablePooledClient<RedisClient> wrapper so we always get a new object instance. Then let the client object become transient since the wrapper takes care of disposing it. This approach does not tackle the broader concept of pooled objects with Ninject and only fixes it for ServiceStack.Redis.
var clientManager = new PooledRedisClientManager();
kernel.Bind<PooledRedisClientManager.DisposablePooledClient<RedisClient>>()
.ToMethod(ctx => clientManager.GetDisposableClient<RedisClient>())
.InRequestScope();
kernel.Bind<IRedisClient>()
.ToMethod(ctx => ctx.Kernel.Get<PooledRedisClientManager.DisposablePooledClient<RedisClient>>().Client)
.InTransientScope();
Is one of these approaches more appropriate than the other?
I have not use Redis so far so I can not tell you how to do it correctly. But I can give you some input in general:
Disposing is not the only thing that is done by the ActivationPipeline. (E.g. it also does property/method injection and excuting activation/deactivation actions.) By using a custom activation cache that returns false even though it has been activated before will cause that these other actions are executed again (E.g. resulting in property injection done again.)

Return data from a call to a client

I have a system connected to a digital scale and I'm trying to use SignalR to pass the weight into other requesting clients.
My Hub looks like this:
public class ScaleHub : Hub
{
private static string ScaleClientId { get; set; }
// the weight object for the client making the request
private static Dictionary<string, WeightDTO> scaleWeights =
new Dictionary<string, WeightDTO>();
public void RegisterScale()
{
ScaleClientId = Context.ConnectionId;
}
public WeightDTO GetWeight()
{
// clear the scale weight for the client making the request
scaleWeights[Context.ConnectionId] = null;
Task updateWeightTask = Clients[ScaleClientId].UpdateWeight(Context.ConnectionId);
// this doesn't wait :-(
updateWeightTask.Wait();
return scaleWeights[Context.ConnectionId];
}
public void UpdateWeight(WeightDTO weight, string clientId)
{
// update the weight for the client making the request
scaleWeights[clientId] = weight;
}
}
The important parts of the client are:
scaleHub.On<string>("UpdateWeight", UpdateWeight);
private void UpdateWeight(string clientId)
{
// this is replaced with code that talks to the scale hardware
var newWeight = new WeightDTO(123, WeightUnitTypes.LB);
scaleHub.Invoke("UpdateWeight", newWeight, clientId).Wait();
}
public Task<WeightDTO> GetWeight()
{
return scaleHub.Invoke<WeightDTO>("GetWeight");
}
I'm still new to SignalR so I'm not sure I'm going about this the right way.
Adding Thread.Sleep(2000) instead of updateWeightTask.Wait() solves the issues, since it gives enough time for the round-trip calls to UpdateWeight to finish. I'd prefer not to make my clients wait 2 seconds to get the weight.
Any suggestions?

Categories

Resources