I have a signalr client that I want to be global.
I think creating the signalr client in the Init() of the endpointconfig would be best.
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
public static HubConnection hubConnection;
public static IHubProxy hubProxy;
public void Init()
{
Configure.With()
.DefiningEventsAs(t => t.Namespace != null && t.Namespace.Contains(".Events."))
.DefiningMessagesAs(t => t.Namespace != null && t.Namespace.Contains(".Messages."))
.StructureMapBuilder(new Container(new DependencyRegistry()));
Configure.Serialization.Json();
hubConnection = new HubConnection("http://localhost:58120");
hubProxy = hubConnection.CreateHubProxy("AmsHub");
hubProxy.On<string>("receiveServerPush", x => System.Diagnostics.Debug.WriteLine(x));
hubConnection.Start().Wait();
}
public class DependencyRegistry : Registry
{
public DependencyRegistry()
{
Scan(x =>
{
x.AssembliesFromApplicationBaseDirectory();
x.ExcludeNamespace("StructureMap");
x.WithDefaultConventions();
});
}
}
}
What I'm confused about, is how am I supposed to reference the hubConnection and hubProxy in a message handler? I seems like I'm jerry rigging NServicebus.
public class TestHandler : IHandleMessages<AMS.Infrastructure.Events.IEvent>
{
public void Handle(AMS.Infrastructure.Events.IEvent message)
{
EndpointConfig.hubProxy.Invoke("ServerFunction", "yodle");
}
}
PS: the reason I need the connection and proxy to be global is because spawning up a new hubConnection is expensive according to the signalr people. They highly discourage creating and destroying hubconnections over and over again. They found that making the hubconnection global/static(?) ok though.
In this case, your Hub Connection/Proxy really are unrelated to the EndPointConfiguration class. They don't use nor require any data from this type in order to function.
I would recommend placing them in their own lazy initialized singleton, and start them automatically upon first access. This would look like:
public class Hub
{
private static Lazy<Hub> instance = new Lazy<Hub>(() => new Hub());
public static Hub Instance { get { return instance.Value; } }
private Hub()
{
this.Connection = new HubConnection("http://localhost:58120");
this.Proxy = Connection.CreateHubProxy("AmsHub");
this.Proxy.On<string>("receiveServerPush", x => System.Diagnostics.Debug.WriteLine(x));
this.Connection.Start().Wait();
}
public HubConnection Connection { get; private set; }
public IHubProxy Proxy { get; private set; }
}
Your consumers then just use:
public class TestHandler : IHandleMessages<AMS.Infrastructure.Events.IEvent>
{
public void Handle(AMS.Infrastructure.Events.IEvent message)
{
Hub.Instance.Proxy.Invoke("ServerFunction", "yodle");
}
}
This has the benefit of not creating and starting until first use, and isolates this type into it's own class.
Given that you're also handling the subscription internally, you also could, optionally, encapsulate your methods to simplify usage:
public class Hub
{
private static Lazy<Hub> instance = new Lazy<Hub>(() => new Hub());
public static Hub Instance { get { return instance.Value; } }
private Hub()
{
this.Connection = new HubConnection("http://localhost:58120");
this.Proxy = Connection.CreateHubProxy("AmsHub");
this.Proxy.On<string>("receiveServerPush", x => System.Diagnostics.Debug.WriteLine(x));
this.Connection.Start().Wait();
}
private HubConnection Connection { get; set; }
private IHubProxy Proxy { get; set; }
public static Task Invoke(string method, params Object[] args)
{
return Instance.Proxy.Invoke(method, args);
}
public static Task<T> Invoke<T>(string method, params Object[] args)
{
return Instance.Proxy.Invoke<T>(method, args);
}
}
With the above, you could just use: Hub.Invoke("ServerFunction", "yodle");
#reed-copsey Old post, but thanks for your reply, it helped me a lot.
In my case I am creating an Azure Function, which will connect to an SignalR Hub which is part of an ASP.NET MVC site. I needed the connection to be secure / authenticated before sending a notification.
So my example included authenticating and getting a cookie.
public class Hub
{
private static readonly string HOMEPAGE = ConfigurationManager.AppSettings["Homepage"];
private static readonly string NOTIFICATION_USER = ConfigurationManager.AppSettings["NotificationUser"];
private static readonly string NOTIFICATION_PASSWORD = ConfigurationManager.AppSettings["NotificationPassword"];
private static Lazy<Hub> instance = new Lazy<Hub>(() => new Hub());
public static Hub Instance { get { return instance.Value; } }
private Hub()
{
ClientHandler = new HttpClientHandler();
ClientHandler.CookieContainer = new CookieContainer();
using (Client = new HttpClient(ClientHandler))
{
var content = string.Format("Email={0}&Password={1}", NOTIFICATION_USER, NOTIFICATION_PASSWORD);
var response = this.Client.PostAsync(HOMEPAGE + "/Account/Login", new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded")).Result;
}
Connection = new HubConnection($"{HOMEPAGE}/");
Connection.CookieContainer = ClientHandler.CookieContainer;
Proxy = Connection.CreateHubProxy("notificationsHub");
//this.Proxy.On<string>("receiveServerPush", x => System.Diagnostics.Debug.WriteLine(x));
Connection.Start().Wait();
}
public HttpClientHandler ClientHandler { get; private set; }
public HttpClient Client { get; private set; }
public HubConnection Connection { get; private set; }
public IHubProxy Proxy { get; private set; }
public static Task Invoke(string method, params Object[] args)
{
return Instance.Proxy.Invoke(method, args);
}
public static Task<T> Invoke<T>(string method, params Object[] args)
{
return Instance.Proxy.Invoke<T>(method, args);
}
}
Related
Description
I want to create an object of a class with dependency injection. If I set the parameter manually I got the exception Cannot access a disposed of the object..
This Application is a Blazor wasm with Dotnet core 3.1. I´ve created a Middleware that should connect to a query console. So I have a static list that contains all query clients. If a client is missing it will be created.
Invoke Async in the middleware:
public async Task InvokeAsync(HttpContext context,
IConfiguration configuration,
IInstanceControlRepository instanceControlRepository,
IServiceProvider serviceProvider)
{
_configuration = configuration;
_instanceControlRepository = instanceControlRepository;
long timestamp = new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds();
var instances = _instanceControlRepository.GetAllInstances();
if (_time + 3 <= timestamp)
{
_time = timestamp;
// Remove
foreach(var client in TeamspeakInstanceQueryClients.ToList())
{
var cl = instances.ToList().Find(el => el.Id == client.Instance.Id);
if(cl == null)
{
client.Dispose();
TeamspeakInstanceQueryClients.RemoveAll(el => el.Instance.Equals(client.Instance));
}
}
// Create & Update
foreach (var instance in instances)
{
var queryClient = TeamspeakInstanceQueryClients.Find(el => el.Instance.Id == instance.Id);
if(queryClient == null)
{
//var test = ActivatorUtilities.CreateInstance<ApplicationDbContext>(serviceProvider);
//var dbContext = serviceProvider.GetService<ApplicationDbContext>();
//queryClient = new TeamspeakInstanceQueryClient(new InstancesControlRepository(ActivatorUtilities.CreateInstance<ApplicationDbContext>(serviceProvider)));
queryClient = new TeamspeakInstanceQueryClient(serviceProvider);
_ = queryClient.Connect(instance);
TeamspeakInstanceQueryClients.Add(queryClient);
}
else
{
_ = queryClient.CheckInstanceData(instance);
}
}
}
await _next(context);
}
TeamspeakInstanceQueryClient.cs
public partial class TeamspeakInstanceQueryClient : ITeamspeakInstanceQueryClient
{
private IInstanceControlRepository _instanceControlRepository;
private const short MAX_RETRYS = 3;
private const short TIME_TO_RETRY = 10;
private EventHandler OnConnected;
public Instance Instance { get; internal set; }
public TeamSpeakClient Client { get; internal set; }
public bool IsSelected { get; internal set; }
private short _connectionTrys = 0;
public TeamspeakInstanceQueryClient(IServiceProvider serviceProvider)
{
_instanceControlRepository = new InstancesControlRepository(ActivatorUtilities.CreateInstance<ApplicationDbContext>(serviceProvider));
Init();
}
}
InstancesControlRepository.cs
public class InstancesControlRepository : IInstanceControlRepository
{
private readonly ApplicationDbContext _applicationDbContext;
public InstancesControlRepository(ApplicationDbContext applicationDbContext)
{
_applicationDbContext = applicationDbContext;
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(option =>
option.UseMySql(
Configuration.GetConnectionString("DefaultConnection"),
mySqlOptions => mySqlOptions.ServerVersion(new System.Version(10, 4, 13), ServerType.MariaDb)
)
);
services.AddScoped<IInstanceControlRepository, InstancesControlRepository>();
services.AddScoped<IServerQueryRepository, ServerQueryRepository>();
What I´ve tried
I´ve tried to create the class with the service provider but it comes to the same error
I´ve tried to create the missing parameters with the service provider in the created class. But I need to inject the service provider which also creates the exception Cannot access a disposed of the object. Object name: 'IServiceProvider'.
I´ve tried to make the service provider static so it can´t be disposed but it is disposed.
It seems that instance of IServiceProvider is a scoped one and it is disposed when the scope ends (in the end of request I assume). You can try define singleton factory for your TeamspeakInstanceQueryClient and use it:
class ClientFactory
{
private IServiceProvider _sp { get; set; }
private IServiceScope _scope { get; set; }
public MyClass(IServiceProvider sp)
{
_sp = sp;
_scope = sp.CreateScope();
}
public TeamspeakInstanceQueryClient Create() => new TeamspeakInstanceQueryClient(_scope.ServiceProvider);
}
// register it as singleton
services.AddSingleton<ClientFactory>();
and use it in InvokeAsync:
var factory = serviceProvider.GetRequiredService<ClientFactory>();
queryClient = factory.Create();
P.S. this code can be improved vastly and is used only for demonstration purposes.
I got stuck and need some advice or pointer to a solution.
A web API with ASP.NET Core 3.1
Startup.cs
services.AddSingleton<ITopicClient>(s => new TopicClient({connectionstring},{topic}));
TopicRepository.cs
public class TopicRepository : ITopicRepository
{
private readonly ITopicClient _topicClient1;
private readonly ITopicClient _topicClient2;
public TopicRepository (ITopicClient topicClient1, ITopicClient topicClient2)
{
_topicClient1 = topicClient1;
_topicClient2 = topicClient2;
}
public async Task<Response> SendToTopicAsync(string message, string topic)
{
if( topic == "topic1")
await _topicClient1.send(message);
else if (topic == "topic2")
await _topicClient2.send(message);
}
}
TopicClient.cs in a shared library
public TopicClient(string serviceBusConnectionString, string topicName)
{
_topicClient = new TopicClient(_serviceBusConnectionString,topicName);
}
I need to send message to different topics. I would like to register services with different topic names in startup.cs. I want to reuse topicClient connection.
services.AddSingleton(s => new TopicClient({connectionstring},{topic1}));
services.AddSingleton(s => new TopicClient({connectionstring},{topic2}));
How can I achieve this by registering singleton instances of same type using same interface ?
Thank you in advance!
You could use a client resolver that holds your registered clients with a wrapper around the client.
First create a wrapper around your client with a name or enum for how to resolve it. As I'm not a fan of magic strings I decided to go with an enum in the example.
// Wrapper for your TopicClients
public interface ICustomTopicClient
{
public ITopicClient TopicClient { get; }
public TopicName TopicName { get; }
}
// Implement the ICustomTopicClient interface
public class CustomTopicClient : ICustomTopicClient
{
public ITopicClient TopicClient { get; }
public TopicName TopicName { get; }
public CustomTopicClient(ITopicClient topicClient, TopicName topicName)
{
TopicClient = topicClient;
TopicName = topicName;
}
}
// Enum for how to resolve the requested TopicClient
public enum TopicName
{
Topic1 = 0,
Topic2 = 1
}
// Register all ICustomTopicClients in your container
services.AddSingleton<ICustomTopicClient>(s => new CustomTopicClient(new TopicClient({connectionstring},{topic}), TopicName.Topic1));
services.AddSingleton<ICustomTopicClient>(s => new CustomTopicClient(new TopicClient({connectionstring},{topic2}), TopicName.Topic2));
Then you create a resolver that holds all custom clients.
You inject the collection of clients from the container and create a dictionary with a public method to resolve the clients.
public interface IMessageClientResolver
{
ITopicClient ResolveClient(TopicName name);
}
public class MessageClientResolver : IMessageClientResolver
{
private readonly Dictionary<TopicName, ITopicClient> topicClients;
public MessageClientResolver(IEnumerable<ICustomTopicClient> clients)
{
topicClients = clients.ToDictionary(k => k.TopicName, v => v.TopicClient);
}
public ITopicClient ResolveClient(TopicName name)
{
topicClients.TryGetValue(name, out var client);
if (client is null)
throw new ArgumentException(nameof(client));
return client;
}
}
Register the resolver to the container.
services.AddSingleton<IMessageClientResolver, MessageClientResolver>();
And then use it like this:
public class Foo
{
private readonly ITopicClient topicClient;
private readonly ITopicClient topicClient2;
public Foo(IMessageClientResolver clientResolver)
{
topicClient = clientResolver.ResolveClient(TopicName.Topic1);
topicClient2 = clientResolver.ResolveClient(TopicName.Topic2);
}
}
You can use the same pattern and extend the resolver with IQueueClients. And add a resolve method to return the IQueueClient by a QueueName enum.
You can already register multiple instances as the same interface, so when you do:
services.AddSingleton<ITopicClient>(_ => new TopicClient("topic1"));
services.AddSingleton<ITopicClient>(_ => new TopicClient("topic2"));
you already added two instances to the container.
It is just when you resolve interface ITopicClient, you always get the last added instance. For example, if you resolve:
// instance = topic2
var instance = container.GetService<ITopicClient>();
If you need all instances, you should resolve / inject IEnumerable<ITopicClient>.
class TopicRepository
{
public TopicRepository(IEnumerable<ITopicClient> clients)
{
// clients contains topic1 and topic2
}
}
I have asp.net core application. Given S3 urls, the application needs to download file. These S3 urls may belongs to different AWS regions in the US.
public class Downloader
{
public void DownloadFile(string s3Url, string destFolder)
{
//download files
}
}
The DownloadFile() method gets called concurrently. Each url pass to this method may belong to different region.
AWS documentation shows how to Configure the AWS SDK for .NET with .NET Core. In my case AWS credentials are stored in profile file on server and the same credentials can be used across all US regions. So appsettings.json looks like
"AWS": {
"Profile": "default",
"ProfilesLocation": "C:\\aws\\awsprofile"
},
Issue
Since URLS can belong to different region, i cannot follow documentation code. I cannot register IAmazonS3 with DI framework and inject that instance into Downloader to download files from different regions. Because IAmazonS3 instance tried to a particular region.
Solution
So i created a factory which provides instance of IAmazonS3 given region name.
public interface IS3ClientFactory : IDisposable
{
IAmazonS3 GetS3Client(RegionEndpoint region);
}
public class S3ClientFactory : IS3ClientFactory
{
private bool _disposed = false;
private IDictionary<string, IAmazonS3> _container = null;
private S3ClientFactory()
{
_container = new Dictionary<string, IAmazonS3>();
}
public static IS3ClientFactory Configure(AWSOptions option, RegionEndpoint[] regions)
{
var factory = new S3ClientFactory();
foreach (RegionEndpoint region in regions)
{
option.Region = region;
factory._container.Add(region.SystemName, option.CreateServiceClient<IAmazonS3>());
}
return factory;
}
public IAmazonS3 GetS3Client(RegionEndpoint region)
{
return _container[region.SystemName];
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (_container != null && _container.Any())
{
foreach (var s3Client in _container)
{
if (s3Client.Value != null)
{
s3Client.Value.Dispose();
}
}
}
_disposed = true;
}
}
}
}
and in startup.cs register factory with DI
services.AddSingleton<IS3ClientFactory>(S3ClientFactory.Configure(Configuration.GetAWSOptions(),
new RegionEndpoint[]
{
RegionEndpoint.USWest1,
RegionEndpoint.USWest2,
RegionEndpoint.USEast1,
RegionEndpoint.USEast2
}));
and Downloader class would look like
public class Downloader : IDownloader
{
private readonly IS3ClientFactory _factory;
public Downloader(IS3ClientFactory factory)
{
_factory = factory;
}
public void DownloadFile(string s3Url, string destFolder)
{
var s3Uri = new AmazonS3Uri(s3Url);
var s3Client = _factory.GetS3Client(s3Uri.Region);
// use s3Client to download file
}
}
Questions
In S3ClientFactory's Configure method i am dynamically assigning RegionEndpoint to AWSOptions and then call option.CreateServiceClient<IAmazonS3>() is this a correct way of creating region specific instance of IAmazonS3? The code need to be unit testable so i could not use new AmazonS3Client(RegionEndpoint).
foreach (RegionEndpoint region in regions)
{
option.Region = region;
factory._container.Add(region.SystemName, option.CreateServiceClient<IAmazonS3>());
}
Is it okay to have singleton instance of IAmazonS3?
You can just inject IEnumerable of your service interface. And then find the instance that you want using LINQ.
Startup
foreach (string snsRegion in Configuration["SNSRegions"].Split(',', StringSplitOptions.RemoveEmptyEntries))
{
services.AddAWSService<IAmazonSimpleNotificationService>(
string.IsNullOrEmpty(snsRegion) ? null :
new AWSOptions()
{
Region = RegionEndpoint.GetBySystemName(snsRegion)
}
);
}
services.AddSingleton<ISNSFactory, SNSFactory>();
services.Configure<SNSConfig>(Configuration);
SNSConfig
public class SNSConfig
{
public string SNSDefaultRegion { get; set; }
public string SNSSMSRegion { get; set; }
}
appsettings.json
"SNSRegions": "ap-south-1,us-west-2",
"SNSDefaultRegion": "ap-south-1",
"SNSSMSRegion": "us-west-2",
SNS Factory
public class SNSFactory : ISNSFactory
{
private readonly SNSConfig _snsConfig;
private readonly IEnumerable<IAmazonSimpleNotificationService> _snsServices;
public SNSFactory(
IOptions<SNSConfig> snsConfig,
IEnumerable<IAmazonSimpleNotificationService> snsServices
)
{
_snsConfig = snsConfig.Value;
_snsServices = snsServices;
}
public IAmazonSimpleNotificationService ForDefault()
{
return GetSNS(_snsConfig.SNSDefaultRegion);
}
public IAmazonSimpleNotificationService ForSMS()
{
return GetSNS(_snsConfig.SNSSMSRegion);
}
private IAmazonSimpleNotificationService GetSNS(string region)
{
return GetSNS(RegionEndpoint.GetBySystemName(region));
}
private IAmazonSimpleNotificationService GetSNS(RegionEndpoint region)
{
IAmazonSimpleNotificationService service = _snsServices.FirstOrDefault(sns => sns.Config.RegionEndpoint == region);
if (service == null)
{
throw new Exception($"No SNS service registered for region: {region}");
}
return service;
}
}
public interface ISNSFactory
{
IAmazonSimpleNotificationService ForDefault();
IAmazonSimpleNotificationService ForSMS();
}
Now you can get the SNS service for the region that you want in your custom service or controller
public class SmsSender : ISmsSender
{
private readonly IAmazonSimpleNotificationService _sns;
public SmsSender(ISNSFactory snsFactory)
{
_sns = snsFactory.ForSMS();
}
.......
}
public class DeviceController : Controller
{
private readonly IAmazonSimpleNotificationService _sns;
public DeviceController(ISNSFactory snsFactory)
{
_sns = snsFactory.ForDefault();
}
.........
}
I have application in which I am showing data from sensors using SignalR. It uses ASP.net membership to authenticate the users. It all works fine if I only open one browser window(e.g. Firefox). If I open same website in another browser e.g. Chrome at the same time then signalR connection to firefox browser drops even if the user is different. This is what I am using to broadcast message:
Hub
[Authorize]
public class DataHub:Hub
{
private readonly RealTimeData _sensor;
public DataHub() : this(RealTimeData.Instance) { }
public DataHub(RealTimeData data)
{
_sensor = data;
}
public override Task OnConnected()
{
// _sensor.UserId = Context.ConnectionId; changed to
_sensor.UserId = Membership.GetUser().ProviderUserKey.ToString();
return base.OnConnected();
}
}
public class RealTimeData
{
//User Id
public String UserId { get; set; }
private readonly static Lazy<RealTimeData> _instance = new Lazy<RealTimeData>(() => new RealTimeData(GlobalHost.ConnectionManager.GetHubContext<DataHub>().Clients));// Singleton instance
private IHubConnectionContext Clients;
private void BroadcastDataOfAllSensors(List<SensorDetails> sensor)
{
//Clients.Client(UserId).updateDashboard(sensor);changed to
Clients.User(UserId).updateDashboard(sensor);
}
}
Application Startup
public class StartUp
{
public void Configuration(IAppBuilder app)
{
var idProvider = new UserIdProvider();
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);
app.MapSignalR();
}
}
UserId
public class UserIdProvider : IUserIdProvider
{
public string GetUserId(IRequest request)
{
var userId = Membership.GetUser().ProviderUserKey;
return userId.ToString();
}
}
I have a simple SignalR based timer on the server which updates my dashboard panel. Everything works fine on VS2012, however when I deploy to azure or IIS7.5 it can't stablish a connection. Here are the errors from console.
This is my hub:
public class BroadCastHub : Hub
{
// Is set via the constructor on each creation
//private readonly Broadcaster _broadcaster;
private readonly TimeSpan BroadcastInterval = TimeSpan.FromMilliseconds(AppConfig.Instance.Tracing.RefreshRate * 1000);
public BroadCastHub() {
if (AppConfig.Instance.Tracing.EnableServerAutoUpdates)
{
// Start the broadcast loop
var _broadcastLoop = new Timer(
UpdatePanel,
null,
BroadcastInterval,
BroadcastInterval);
}
}
public void UpdatePanel()
{
UpdatePanel(null);
}
public void UpdatePanel(object o)
{
var appService = DependencyResolver.Current.GetService<IApplicationService>();
var applications = appService.GetSummaryCollection();
var model = applications.Select(c => new ApplicationState
{
id = c.id,
lastRunTime = c.lastRunTime.GetValueOrDefault(),
totalTraces = c.totalTraces,
status = appService.GetStatus(c.lastRunTime, c.lastTraceType, c.traceInterval)
}.InjectFrom(c)).Cast<ApplicationState>().AsQueryable();
Clients.All.updatePanel(model);
}
}
This is my JS code (Angular):
function init() {
var broadCastHub = $.connection.broadCastHub;
broadCastHub.client.updatePanel = function(apps) {
console.log('Broadcasting');
};
$.connection.hub.start()
.done(function () {
console.log('Now connected, connection ID=' + $.connection.hub.id);
})
.fail(function () { console.log('Could not Connect!'); });
//listenBroadcast();
}
EDIT:
Curiously, I saw a similar article and implemented like this:
public class Broadcaster
{
private readonly IApplicationService _applicationService;
private readonly static Lazy<Broadcaster> _instance = new Lazy<Broadcaster>(() => new Broadcaster());
// We're going to broadcast to all clients a maximum of 25 times per second
private readonly TimeSpan BroadcastInterval = TimeSpan.FromMilliseconds(AppConfig.Instance.Tracing.RefreshRate * 1000);
private readonly IHubContext _hubContext;
private Timer _broadcastLoop;
public Broadcaster()
{
_applicationService = DependencyResolver.Current.GetService<IApplicationService>();
// Save our hub context so we can easily use it
// to send to its connected clients
_hubContext = GlobalHost.ConnectionManager.GetHubContext<BroadCastHub>();
if (AppConfig.Instance.Tracing.EnableServerAutoUpdates) {
// Start the broadcast loop
_broadcastLoop = new Timer(
UpdatePanel,
null,
BroadcastInterval,
BroadcastInterval);
}
}
public void UpdatePanel(object state)
{
var applications = _applicationService.GetSummaryCollection();
var model = applications.Select(c => new ApplicationState
{
id = c.id,
lastRunTime = c.lastRunTime.GetValueOrDefault(),
totalTraces = c.totalTraces,
status = _applicationService.GetStatus(c.lastRunTime, c.lastTraceType, c.traceInterval)
}.InjectFrom(c)).Cast<ApplicationState>().AsQueryable();
_hubContext.Clients.All.updatePanel(model);
}
public static Broadcaster Instance
{
get
{
return _instance.Value;
}
}
}
My hub:
public class BroadCastHub : Hub
{
// Is set via the constructor on each creation
private readonly Broadcaster _broadcaster;
public BroadCastHub()
: this(Broadcaster.Instance)
{
}
public BroadCastHub(Broadcaster broadcaster)
{
_broadcaster = broadcaster;
}
public void UpdatePanel()
{
_broadcaster.UpdatePanel(null);
}
}
Thanks for the article, I'll take a deeper look.