SignalR + Autofac + OWIN: Почему не работает GlobalHost.ConnectionManager.GetHubContext?
Я пытаюсь использовать OWIN, SignalR и Autofac в одном проекте.
Я настраиваю вещи в отношении 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.
Я нашел следующую статью Piotr Szmyd, которая, по-видимому, позволяет это:
http://www.szmyd.com.pl/blog/wiring-signalr-with-autofac
но это, по-видимому, основано на устаревших строках signalR, и, хотя, похоже, для него существует пакет nuget:
http://www.nuget.org/packages/SignalR.AutoFac/
он также кажется устаревшим.
Ответы
Ответ 1
Если вы используете настраиваемый зависимый преобразователь с 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
});
Ответ 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, но он должен быть похож на Hubs.
Ответ 3
Чтобы расширить ответ Nathan, я использую что-то похожее с ключевой строкой
builder.RegisterHubs(Assembly.GetExecutingAssembly()).SingleInstance();
в Startup.cs.
Строка "SingleInstance()" гарантирует, что во всем приложении используется только один "экземпляр" концентратора.
Затем я просто использую простое вложение зависимостей в конструктор контроллера, чтобы получить указатель на концентратор.