所以我尝试将 Signalr 与 Twitter Streaming API 结合使用,具体来说,为此我使用了 Tweetinvi C# API ( http://tweetinvi.codeplex.com/ )。
该应用程序的目的是将推文实时流式传输到使用特定关键字过滤的页面。
TweetInvi 库非常有用,我有一个命令行应用程序成功打印出带有特定关键字的推文。
我的用法基本概述如下:
我有一个 MVC 网络应用程序,它只有一个页面,有一个文本输入和一个按钮(用于更新过滤器),然后它调用 Signalr Hub 中的 Hub 方法,以启动流(如果还没有流的话)在第二次单击按钮时停止它。
除了信号器部分,所有这些都工作正常。
public class TweetHub : Hub
{
private IStreamManager _streamManager;
public void AddTweet(String tweet, double lat, double lon)
{
Clients.All.addTweet(tweet, lat, lon);
}
public void StartStream(String[] filters)
{
string accessToken = ConfigurationManager.AppSettings["AccessToken"];
string accessTokenSecret = ConfigurationManager.AppSettings["AccessTokenSecret"];
string consumerKey = ConfigurationManager.AppSettings["ConsumerKey"];
string consumerSecret = ConfigurationManager.AppSettings["ConsumerSecret"];
IToken token = new Token(accessToken, accessTokenSecret, consumerKey, consumerSecret);
if (_streamManager != null && _streamManager.StreamIsOpen())
{
_streamManager.StopStream();
_streamManager.StartStream(token, filters, tweet => AddTweet(tweet.Text, tweet.LocationCoordinates.Lattitude, tweet.LocationCoordinates.Longitude));
}
else if (_streamManager != null && !_streamManager.StreamIsOpen())
{
_streamManager.StartStream(token, filters, tweet => AddTweet(tweet.Text, tweet.LocationCoordinates.Lattitude, tweet.LocationCoordinates.Longitude));
}
else
{
_streamManager = new StreamManager();
_streamManager.StartStream(token, filters, tweet => AddTweet(tweet.Text, tweet.LocationCoordinates.Lattitude, tweet.LocationCoordinates.Longitude));
}
}
public void StopStream()
{
if (_streamManager != null && _streamManager.StreamIsOpen())
{
_streamManager.StopStream();
}
}
}
那是我的 Signalr Hub 的代码。正如我所说,使用 js 我可以很好地触发开始和停止流方法。
这是我的 StreamManager 类的代码:
public class StreamManager : IStreamManager
{
private StreamClient _streamClient;
private bool _streamOpen = false;
public void StartStream(IToken token, String[] filters, Action<ITweet> action)
{
if (_streamClient == null)
_streamClient = new StreamClient(token, filters, new FilteredStream());
_streamClient.StartStream(action);
_streamOpen = true;
}
public void StopStream()
{
if (_streamClient != null)
{
_streamClient.StopStream();
_streamOpen = false;
}
}
public bool StreamIsOpen()
{
return _streamOpen;
}
public void Dispose()
{
if (_streamOpen)
{
StopStream();
}
_streamClient.Dispose();
_streamClient = null;
}
}
我的 StreamClient 类的代码:
public class StreamClient : IStreamClient
{
private IFilteredStream _filteredStream;
private IToken _token;
private bool _streamOpen = false;
public StreamClient(IToken token, String[] filters, IFilteredStream filteredStream)
{
_token = token;
_filteredStream = filteredStream;
AddFilters(filters);
}
private void AddFilters(String[] filters)
{
for (int i = 0; i < filters.Length; ++i)
{
_filteredStream.AddTrack(filters[i]);
}
}
public void StartStream(Action<ITweet> action)
{
_filteredStream.StartStream(_token, action);
_streamOpen = true;
}
public void StartStream(Func<ITweet, bool> predicateFunc)
{
_filteredStream.StartStream(_token, predicateFunc);
_streamOpen = true;
}
public void StopStream()
{
_filteredStream.StopStream();
_streamOpen = false;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
if (_streamOpen)
{
_filteredStream.StopStream();
_filteredStream = null;
_token = null;
}
}
}
上面的代码是直接调用 Tweetinvi 库的地方。
我的问题是,当我将 Hub 方法作为 Action 参数传递给 StreamManager 的 StartStream 方法时,AddTweet 方法永远不会被命中。
正如我所说,当使用命令提示符应用程序作为客户端并使用以下代码时,一切正常:
static void Main(string[] args)
{
string accessToken = ConfigurationManager.AppSettings["AccessToken"];
string accessTokenSecret = ConfigurationManager.AppSettings["AccessTokenSecret"];
string consumerKey = ConfigurationManager.AppSettings["ConsumerKey"];
string consumerSecret = ConfigurationManager.AppSettings["ConsumerSecret"];
IToken token = new Token(accessToken, accessTokenSecret, consumerKey, consumerSecret);
String[] filters = new string[2]
{
"test",
"twitter"
};
StreamClient streamClient = new StreamClient(token, filters, new FilteredStream());
streamClient.StartStream(tweet => TestMethod());
}
public static void TestMethod()
{
Console.WriteLine("test");
}
这非常有效,并在收到这些关键字时打印出推文。
这让我相信我使用 Signalr 的方式存在问题,signalr 方法永远不会被命中,因为流肯定会打开,我只是偷偷怀疑它与集线器的使用生命周期以及我使用它的方式。
我怀疑这是因为,虽然我的集线器中的 StartStream 方法被调用得很好,并更新了被点击的按钮,但当我想再次点击以调用 StopStream 时,StopStream 方法被点击了,但我的“_streamManager”成员变量为空,如果集线器在其生命周期内保持状态,则不应如此,我猜它不会。
要么那个,要么它被处理掉,然后流就不会再存在了。
我真的没有足够的 Signalr 经验来正确调试。
在此先感谢您的帮助。
最佳答案
集线器类的实例是 transient 的。这意味着每次调用集线器类中的方法或发生连接事件(例如 onConnected、onDisconnected)时,SignalR 都会创建一个集线器类的实例。当被调用的方法完成其工作时,该集线器实例将被释放。 读这个:http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-server#transience
因此,您不应尝试在集线器类中维护有关连接的状态信息。在您的情况下,这将是“_streamManager”。 所以我认为你应该将你所有的业务逻辑移动到另一个类(不是从 Hub 派生的)。将它们封装在方法中并从你的 signalR 方法中调用它们。
如果您需要从您的服务器代码调用集线器中的方法,您应该首先获得一个集线器上下文。 在这里查看如何操作:http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-server#callfromoutsidehub
希望这对您有所帮助!
关于c# - Signalr 中心和 Twitter 流媒体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19727771/