2014-01-15 3 views
27

Я пытаюсь использовать OWIN, SignalR и Autofac в одном проекте.SignalR + Autofac + OWIN: Почему не работает GlobalHost.ConnectionManager.GetHubContext?

Я устанавливаю вещи касаемо signalR следующим образом:

 // Create the AutoFac container builder: 
     var builder = new ContainerBuilder(); 

     // ...[Register various other things in here]... 

     // register signalR Hubs 
     builder.RegisterHubs(Assembly.GetExecutingAssembly()); 

     // Build the container: 
     var container = builder.Build(); 

     // Configure SignalR with the dependency resolver. 
     app.MapSignalR(new HubConfiguration 
     { 
      Resolver = new AutofacDependencyResolver(container) 
     }); 

Моя проблема заключается в том, что, когда я использую интеграции Autofac SignalR, я больше не может получить контекст signalR концентратора на сервере (в например, контроллер webapi) и поэтому не может отправлять сообщения со стороны сервера подключенным клиентам. Что-то вроде следующего, как я делаю это, когда я не использую интеграции Autofac signalR:

var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>(); 
hubContext.Clients.All.notification("Test Message"); 

Но это не работает, когда я добавить Autofac в микс - я не получаю сообщение об ошибке и Кажется, я получаю hubContext, но называть его на самом деле, похоже, не добираются до клиентов.

Если я прокомментировал использование преобразователя зависимостей для signalR в вызове MapSignalR, вызов GetHubContext снова работает, и сообщения успешно доходят до клиентов signalR, но, конечно, я больше не могу использовать IoC на своих концентраторах. например

 // Configure SignalR with the dependency resolver. 
     app.MapSignalR(new HubConfiguration 
     { 
      // Resolver = new AutofacDependencyResolver(container) 
     }); 

Может кто-нибудь сказать мне, почему использование AutofacDependencyResolver перестает GlobalHost.ConnectionManager.GetHubContext работать правильно ??

Примечание: Еще одна вещь, которую я попытался это вместо того, чтобы использовать GlobalHost.ConnectionManager.GetHubContext() Я попробовал нагнетание IConnectionManager в контроллер WebAPI, из которого я хочу, чтобы отправить сообщение для клиентов, то вызов GetHubContext на том, но Autofac не смог разрешить IConnectionManager.

Я нашел следующую статью Петра Szmyd, который, видимо, позволяет это:

http://www.szmyd.com.pl/blog/wiring-signalr-with-autofac

, но это, как представляется, на основе устаревших signalR строит, и в то время, как представляется, пакет NuGet для него здесь :

http://www.nuget.org/packages/SignalR.AutoFac/

также кажется хорошо устареть.

+0

[эти] (http://stackoverflow.com/questions/20990308/cannot-pass-a-dependencyresolver-to-mapsignalr-in-a-hubconfiguration) начинают чувствовать себя как [дубликаты] (http: // stackoverflow.com/a/20202040/2001735) –

ответ

31

Если вы используете распознаватель пользовательских зависимостей с SignalR, вы больше не можете использовать GlobalHost, если вы не измените ее:

GlobalHost.DependencyResolver = new AutofacDependencyResolver(container); 
IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>(); 

// A custom HubConfiguration is now unnecessary, since MapSignalR will 
// use the resolver from GlobalHost by default. 
app.MapSignalR(); 

Если вы не хотите, чтобы изменить GlobalHost, вам придется вручную решить IConnectionManager :

IDependencyResolver resolver = new AutofacDependencyResolver(container); 
IHubContext hubContext = resolver.Resolve<IConnectionManager>().GetHubContext<MyHub>(); 

app.MapSignalR(new HubConfiguration 
{ 
    Resolver = resolver 
}); 
+0

Aha! Спасибо, я думаю, что это приближает меня к ответу. Есть ли недостатки в модификации GlobalHost? (например, если я хочу переключиться на собственный хост в будущем и т. д.?) – mutex

+1

Единственный минус для модификации GlobalHost, о котором я могу думать, это то, что вы полагаетесь на глобальное состояние. Если вы хотите запускать несколько экземпляров SignalR в том же процессе, то GlobalHost, вероятно, не для вас. В противном случае это, наверное, хорошо. – halter73

+0

@ halter73 ты мой герой прямо сейчас – sfuqua

2

Для полного ответа, с SignalR, Autofac и Owin, я сделал следующее:

// register IPersistantConnectionContext for access to SignalR connection 
// and IDependencyResolver to enable inection of the container into its 
// construction for the config object. 
var builder = new ContainerBuilder(); 
builder.RegisterType<Autofac.Integration.SignalR.AutofacDependencyResolver>() 
    .As<IDependencyResolver>() 
    .SingleInstance(); 
builder.Register((context, p) => 
     context.Resolve<IDependencyResolver>() 
      .Resolve<Microsoft.AspNet.SignalR.Infrastructure.IConnectionManager>() 
      .GetConnectionContext<SignalRConnection>()); 

// ... other registrations 

var container = builder.Build(); 

var signalrConfiguration = new ConnectionConfiguration 
{ 
    Resolver = container.Resolve<IDependencyResolver>(), 
}; 

app.UseAutofacMiddleware(container); 

app.MapSignalR<SignalRConnection>("/signalr", signalrConfiguration); 

// ... other middleware 

В моих контроллерах я включил параметр типа IPersistentConnectionContext и ввел правильный экземпляр.

Я использовал PersistentConnection, но он должен быть похож на концентраторы.

+0

Спасибо, что действительно работает! Ниже приведен полный пример https://stackoverflow.com/a/49214891/1149328 с использованием концентраторов – Andrii

0

Чтобы расширить ответ Натана, я использую нечто подобное с ключом линии будучи

builder.RegisterHubs(Assembly.GetExecutingAssembly()).SingleInstance(); 

в Startup.cs.

Строка «SingleInstance()» гарантирует, что во всем приложении используется только один «экземпляр» концентратора.

Затем я просто использую прямолинейную инъекцию зависимостей в конструктор контроллера, чтобы получить указатель на концентратор.

Смежные вопросы