我正在创建一个应用程序,其中SignalR用于向地图广播实时推文。我正在使用C#Tweetinvi库(tweetinvi.codeplex.com)来处理与连接到Twitter Streaming API相关的所有逻辑。
Twitter API指定任何时候只能向Twitter打开一个流连接。当我使用SignalR时,Streaming连接和Hub类之间存在依赖关系。我知道Hub类是瞬态的,这意味着每次客户端请求它时都会创建它,因此我需要确保注入Hub类的我的Twitter Stream类的实例是单例,或者至少{{1} }仅在应用程序的生命周期中创建一次。以下是连接到API的样板代码:
IFilteredStream
IFilteredStream接口公开了一个lambda方法,允许实时接收推文,我希望能够从我的SignalR Hub类中访问:
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; }
}
}
可以找到此方法的来源here
我试图实现Autofac,似乎与Twitter API的连接发生了,但是没有更多的事情发生。我试图调试这个,但不确定如何使用依赖注入调试这样的场景。我的Hub类目前看起来像这样:
_stream.MatchingTweetReceived += (sender, args) => {
Clients.All.broadcast(args.Tweet);
};
最后,我的OWIN Startup类,我用Autofac注册我的依赖项和Hub:
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();
}
}
很抱歉,如果这个问题有点乱,我很难理解我需要实现什么样的架构来实现这个功能!欢迎提出有关如何改进或如何改进的建议/建议!
答案 0 :(得分:1)
IMO这不起作用,因为您将事件连接到特定集线器实例的上下文,无论与Autofac相关的任何代码(可能还有问题,但我不是它的专家)。 每次发生新连接或从客户端调用方法时,都会调用hub的构造函数,因此:
i.StartStreamMatchingAllConditions()
这一事实对我来说似乎不对。Clients
成员上创建一个闭包,当集线器被销毁时它应该消失(所以你可能正在泄漏内存) )你需要做什么,因为你正在呼叫Client.All
,因此这是一个独立于任何特定呼叫者的纯广播,是:
TwitterStream
服务TwitterHub
这样的构造函数可能如下所示:
public service TwitterStream : ??? <- an interface here?
{
...
public TwitterStream (ILifetimeScope scope ??? <- IMO you don't need this...)
{
//Autofac/Twitter stuff
...
var context = GlobalHost.DependencyResolver.GetHubContext<TwitterHub>();
_stream.MatchingTweetReceived += (sender, args) => {
context.Clients.All.broadcast(args.Tweet);
};
//maybe more Autofac/Twitter stuff
...
}
...
}
TwitterHub
必须存在,但是如果您只是需要它来执行 all 的这种广播,而不需要监视连接或处理客户端生成的调用所需的特殊代码,它很可能是空的,你的实际的集线器相关代码就在它之外并使用IHubContext
来广播消息。这样的代码将在每次推文到达时处理所有现有的连接客户端,因此无需跟踪它们。
当然,如果您对实际处理客户有更多要求,那么事情可能需要有所不同,但您的代码并没有让我想到其他。