I am creating an application where SignalR is used to broadcast real-time tweets to a map. I am using the C# Tweetinvi library (tweetinvi.codeplex.com) to handle all of the logic associated with connecting to the Twitter Streaming API.
The Twitter API specifies that only one streaming connection can be open to Twitter at any time. As I am using SignalR, there is a dependency between the Streaming connection and the Hub class. I know that the Hub class is transient, meaning that it is created each time a client requests it, so I need to ensure that the instance of my Twitter Stream class injected into the Hub class is a singleton, or at least IFilteredStream
is only created once in the lifetime of the application. Here is the boilerplate code to connect to the API:
public class TweetStream
{
private IFilteredStream _stream;
public TweetStream()
{
var consumerKey = ConfigurationManager.AppSettings.Get("twitter:ConsumerKey");
var consumerSecret = ConfigurationManager.AppSettings.Get("twitter:ConsumerSecret");
var accessKey = ConfigurationManager.AppSettings.Get("twitter:AccessKey");
var accessToken = ConfigurationManager.AppSettings.Get("twitter:AccessToken");
TwitterCredentials.SetCredentials(accessKey, accessToken, consumerKey, consumerSecret);
_stream = Stream.CreateFilteredStream();
}
// Return singular instance of _stream to Hub class for usage.
public IFilteredStream Instance
{
get { return _stream; }
}
}
The IFilteredStream interface exposes a lambda method as below which allows for receiving Tweets in real-time, which I would like to be able to access from within my SignalR Hub class:
_stream.MatchingTweetReceived += (sender, args) => {
Clients.All.broadcast(args.Tweet);
};
The source for this method can be found here
I've tried to implement Autofac, and it seems that the connection to the Twitter API happens, however nothing more happens. I've tried to debug this, but am unsure how to debug such a scenario using dependency injection. My Hub class currently looks like this:
public class TwitterHub : Hub
{
private readonly ILifetimeScope _scope;
private readonly TweetStream _stream;
// Inject lifetime scope and resolve reference to TweetStream
public TwitterHub(ILifetimeScope scope)
{
_scope = scope.BeginLifetimeScope();
_stream = scope.Resolve<TweetStream>();
var i = _stream.Instance;
_stream.MatchingTweetReceived += (sender, args) => {
Clients.All.broadcast(args.Tweet);
};
i.StartStreamMatchingAllConditions();
}
}
And finally, my OWIN Startup class, where I register my dependencies and Hub with Autofac:
[assembly: OwinStartup(typeof(TwitterMap2015.App_Start.OwinStartup))]
namespace TwitterMap2015.App_Start
{
public class OwinStartup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// use hubconfig, not globalhost
var hubConfig = new HubConfiguration {EnableDetailedErrors = true};
builder.RegisterHubs(Assembly.GetExecutingAssembly()); // register all SignalR hubs
builder.Register(i => new TweetStream()).SingleInstance(); // is this the correct way of injecting a singleton instance of TweetStream?
var container = builder.Build();
hubConfig.Resolver = new AutofacDependencyResolver(container);
app.MapSignalR("/signalr", hubConfig);
}
}
}
Sorry if this question is a bit of a mess, I'm having a hard time of understand what kind of architecture I need to implement to get this working! Open to advice / recommendations on how this could be improved, or how it should be done!