2013-11-01 35 views
3

所以我试图用Twitter Streaming API使用Signalr,特别是为此,我使用Tweetinvi C#API(http://tweetinvi.codeplex.com/)。Signalr Hubs&Twitter Streaming

该应用程序的目的是流式传输到一个页面实时过滤与某些关键字。

的TweetInvi库工作一种享受,我有一个命令行应用程序成功打印出带有某些关键字的鸣叫在

我使用的基本轮廓如下:。

我有一个MVC的Web应用程序带有单个页面,带有文本输入和按钮(用于更新过滤器),然后调用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”成员变量是null,如果集线器在其生命周期中维持状态,它不应该是这种情况,我猜测它没有。

无论是它或它正在处理,然后流不会再存在了。

我真的没有足够的经验来正确调试Signalr。

在此先感谢您的帮助。

回答

1

集线器类的实例是暂时的。这意味着每次调用该集线器类中的某个方法或发生连接事件时(例如,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

希望这会有所帮助!

+0

非常感谢。这或多或少是我想的:) – JustinMoser