1

我正在创建一个应用程序,其中 SignalR 用于将实时推文广播到地图。我正在使用 C# Tweetinvi 库 ( tweetinvi.codeplex.com ) 来处理与连接到 Twitter 流 API 相关的所有逻辑。

Twitter API 指定任何时候只能向 Twitter 打开一个流连接。当我使用 SignalR 时,流连接和 Hub 类之间存在依赖关系。我知道 Hub 类是瞬态的,这意味着每次客户端请求时都会创建它,因此我需要确保注入 Hub 类的 Twitter Stream 类的实例是单例的,或者至少IFilteredStream只创建一次在应用程序的生命周期中。这是连接到 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; }
        }

    }

IFilteredStream 接口公开了一个 lambda 方法,如下所示,它允许实时接收推文,我希望能够从我的 SignalR Hub 类中访问它:

_stream.MatchingTweetReceived += (sender, args) => {
        Clients.All.broadcast(args.Tweet);
};

此方法的来源可以在这里找到

我尝试实现 Autofac,似乎与 Twitter API 的连接发生了,但没有发生任何其他事情。我试图调试这个,但我不确定如何使用依赖注入来调试这样的场景。我的 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();
    }
}

最后,我的 OWIN Startup 类,我在其中使用 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);
        }
    }
}

抱歉,如果这个问题有点乱,我很难理解我需要实现什么样的架构才能让它工作!对如何改进或应该如何做的建议/建议持开放态度!

4

1 回答 1

1

IMO 这不起作用,因为您正在连接您的事件以调用特定集线器实例的上下文,而不管与 Autofac 相关的任何代码(这也可能有问题,但我不是这方面的专家)。每次发生新连接或从客户端调用方法时都会调用集线器的构造函数,因此:

  • 您可能会为每个客户多次订阅该事件。我不知道你正在使用的 Twitter API,但在这张纸条上,你一直打电话的事实i.StartStreamMatchingAllConditions()对我来说似乎是错误的
  • 每次您在事件处理程序中对该Clients实例的成员创建一个闭包时,该闭包应该在集线器被销毁时消失(因此您可能正在泄漏内存)

鉴于您正在呼叫,您需要做的是Client.All,因此这是一个独立于任何特定呼叫者的纯广播,是:

  • TwitterStream在服务的构造函数中初始化您的 Twitter 连接
  • 在同一个地方(可能有一些间接,但可能没有必要)获取您的中心上下文的实例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必须存在,但如果您只需要它对所有人进行这种广播,而无需特殊代码来监视连接或处理客户端生成的调用,它很可能是空的,您的实际集线器相关代码就可以了生活在它之外并使用 aIHubContext来广播消息。每次推文到达时,这样的代码将负责处理所有现有的连接客户端,因此无需跟踪它们。

当然,如果您对实际单独处理客户有更多要求,那么事情可能需要有所不同,但您的代码不会让我有其他想法。

于 2015-04-15T14:34:35.927 回答