[英]Injecting Singleton Instance of class into SignalR Hub using Autofac
我正在創建一個使用SignalR將實時推文廣播到地圖的應用程序。 我正在使用C#Tweetinvi庫( tweetinvi.codeplex.com )處理與連接到Twitter Streaming 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方法,該方法允許實時接收Tweets,我希望能夠從我的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注冊依賴項和Hub:
[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);
}
}
}
抱歉,如果這個問題有點混亂,我很難理解要實現此功能需要實現哪種架構! 可以就如何改進或應該如何改進提出建議/建議!
IMO不能正常工作,因為您正在連接事件以在特定的集線器實例的上下文上進行調用,而不管與Autofac有關的任何代碼(可能也有問題,但我不是這方面的專家)。 每當發生新連接或從客戶端調用方法時,都會調用集線器的構造函數。
i.StartStreamMatchingAllConditions()
的事實對我來說似乎是錯誤的 Clients
成員創建一個關閉時,該關閉都應該在集線器被銷毀后消失(所以很可能您正在泄漏內存) 考慮到您正在通過Client.All
進行呼叫,因此您需要做的是,這是獨立於任何特定呼叫者的純廣播,它是:
TwitterStream
服務的構造函數中初始化您的Twitter連接 TwitterHub
的中心上下文的實例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
必須存在,但是如果您只需要它對所有人進行這種廣播,而無需監視連接或處理客戶端生成的呼叫的特殊代碼,則它可以為空,並且與您的實際集線器相關也可以代碼位於其外部,並使用IHubContext
廣播消息。 這樣的代碼將在每次發推文時處理所有現有的已連接客戶端,因此無需跟蹤它們。
當然,如果您對分別處理客戶有更多要求,那么情況可能會有所不同,但是您的代碼並沒有使我反感。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.