2015-04-21 3 views
9

Взято из: http://docs.autofac.org/en/latest/integration/signalr.html:Owin + SignalR + Autofac

«Распространенная ошибка в интеграции Owin является использование GlobalHost В Owin создать конфигурацию с нуля Вы не должны ссылаться на GlobalHost в любом месте при использовании интеграции Owin.. «.

Звучит разумно. Однако как следует разрешать IHubContext от ApiController, как и обычный (не OWIN):

GlobalHost.ConnectionManager.GetHubContext<MyHub>()?

Я не могу найти ссылку на этот где-нибудь, и единственный метод, который я теперь должен зарегистрировать экземпляр HubConfiguration в том же контейнере, и сделать это:

public MyApiController : ApiController { 
    public HubConfiguration HubConfig { get; set; } // Dependency injected by 
                // PropertiesAutowired() 

    public IHubContext MyHubContext { 
    get { 
     return HubConfig 
     .Resolver 
     .Resolve<IConnectionManager>() 
     .GetHubContext<MyHub>(); 
    } 
    } 

    // ... 

} 

Однако, это кажется вполне подробный для меня. Каков правильный способ сделать это? Чтобы быть более конкретным, существует ли чистый способ регистрации IConnectionManager?

EDIT:

То, что я в конечном итоге делает что-то вроде:

var container = builder.Build(); 
hubConfig.Resolver = new AutofacDependencyResolver(container); 

app.MapSignalR("/signalr", hubConfig); 

var builder2 = new ContainerBuilder(); 
builder2 
    .Register(ctx => hubConfig.Resolver.Resolve<IConnectionManager>()) 
    .As<IConnectionManager>(); 

builder2.Update(container); 

, но у меня есть ощущение, что должно быть более простой способ, чтобы получить, что IConnectionManager вводят в контроллер.

+1

Похоже, у вас также есть API Web в миксе. Это так? –

+0

Могу ли я спросить, почему вы не выполняете инъекцию конструктора? Здесь у вас огромная зависимость от вашего контейнера. – Anders

+0

@TravisIllig: Да, извините, если я не был откровенен в этом вопросе. Когда я сказал ApiController, я имел в виду контроллер WebAPI. – itim

ответ

9

Этот ответ немного запоздал, но здесь идет.

  • Я рекомендую строго типизированные концентраторы.
  • Вам необходимо добавить определенные регистрации для строго типизированных концентраторов.
  • Я не использую GlobalHost
    • Вместо этого я использовать конфигурацию, созданную для Owin регистрации.

Декларация Hub

public interface IMyHub 
{ 
    // Any methods here for strongly-typed hubs 
} 

[HubName("myHub")] 
public class MyHub : Hub<IMyHub> 

Hub Регистрация

С вашей Autofac регистрации

// SignalR Configuration 
var signalRConfig = new HubConfiguration(); 

var builder = // Create your normal AutoFac container here 

builder.RegisterType<MyHub>().ExternallyOwned(); // SignalR hub registration 

// Register the Hub for DI (THIS IS THE MAGIC LINE) 
builder.Register(i => signalRConfig.Resolver.Resolve<IConnectionManager>().GetHubContext<MyHub, IMyHub>()).ExternallyOwned(); 

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

// SignalR Dependency Resolver 
signalRConfig.Resolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container); 

app.UseAutofacMiddleware(container); 
app.MapSignalR("/signalr", signalRConfig); 

разрешающего ступицу в фоновом коде

Используя метод расширения AutoFacs AutowiredProperties(), он может разрешить правильный контекст (также может быть в конструкторе, если хотите).

public IHubContext<IMyHub> InstanceHubContext { get; [UsedImplicitly] set; } 
+0

Спасибо. Brilliant. Я использую слегка измененное решение: 'builder.RegisterType (). (). SingleInstance();' 'builder.Register (context => context.Resolve (). Разрешить (). GetHubContext ()). ExternallyOwned(); 'и использовать autofac для решения решателей:' hubConfiguration.Resolver = container.Resolve (); 'То же самое для' httpConfiguration' для единообразия. –

+0

Это правильный ответ. Спасибо! – itim

6

Что вы можете сделать, это переместить часть этого повторяющегося кода (предположим, что IHubContext также используется в некоторых других классах, и он загружается таким же образом) в регистрацию контейнера.

Прежде всего, зарегистрировать IHubContext экземпляров, предположим, у вас есть несколько концентраторов в проекте. В этом случае услуги должны быть зарегистрированы как named services.

builder 
    .Register<IHubContext>(c => c.Resolve<IConnectionManager>().GetHubContext<MyHub>()) 
    .Named<IHubContext>("MyHub"); 

Классы, которые хотят использовать IHubContext теперь могут получить его в качестве параметра конструктора или в собственность. Но мы должны указать контейнер, который он должен ввести. Это может быть сделано в конфигурации контейнера несколькими способами

Конструктор может использовать ResolvedParameter правильно выбрать IHubContext реализация

// example class 
public class SampleClass { 
    public SampleClass(IHubContext context) { } 
} 

// and registration for this class 
builder.RegisterType<SampleClass>() 
    .WithParameter(new ResolvedParameter((pi, ctx) => 
    { 
     // only apply this to parameters of IHubContext type 
     return pi.ParameterType == typeof(IHubContext); 
    }, (pi, ctx) => 
    { 
     // resolve context 
     return ctx.ResolveNamed<IHubContext>("MyHub"); 
    })); 

инъекции собственности, также немного сложнее.Это необходимо, чтобы разрешить правильный экземпляр в OnActivated обратного вызова, например, так:

// example class 
public class SampleClass2 
{ 
    public IHubContext Context { get; set; } 
} 

// registration for this case 
builder.RegisterType<SampleClass2>() 
    .PropertiesAutowired() 
    .OnActivated(e => e.Instance.Context = e.Context.ResolveNamed<IHubContext>("MyHub")); 
+0

Это выглядит чище, но все же немного слишком многословно, и у меня есть ощущение, что может быть проще. Мой пример несколько упрощен, но я бы действительно хотел, чтобы экземпляр IConnectionManager был инъецирован в контроллеры, если это возможно (сейчас я не могу этого сделать, не обновляя контейнер Autofac после его создания, например: «var connManager = hubConfig.Resolver.Resolve (); builder.Register (ctx => connManager); builder.Update (container) '. Попытка:' builder.Register (ctx => ctx.Resolve ()) 'не работает для меня. – itim

+0

Ah , Я ошибочно предположил, что все внутренние элементы SignalR зарегистрированы в контейнере Autofac. Фактически, 'AutofacDependencyResolver' делегирует построение внутренних компонентов SignalR на« DefaultDependencyResolver », который поступает из самого SignalR. Таким образом, ваш подход выглядит действительным и соответствует примерам Microsoft (это для Ninject, но похоже на то, что вы делаете http://www.asp.net/signalr/overview/advanced/dependency-injection). Еще один вариант - зарегистрировать также внутренние службы SignalR в co ntainer, но это может привести к проблемам обслуживания во время обновлений SignalR. – drax

2

Я похож на себя, который получил это работает в Owin для меня

builder.RegisterInstance(config.Resolver).As<IDependencyResolver>(); 
builder.Update(container); 

Затем используйте это, чтобы получить мой концентратор

Resolve<IDependencyResolver>().Resolve<IConnectionManager>().GetHubContext<MyHub>(); 

Надеется, что это помогает другим там

1

Easi что я мог бы найти как-то сочетание ответов здесь, но мне кажется, что это лучший способ справиться с этим и поддерживать лучшие практики как для SignalR, так и для Autofac SignalR Integration:

В классах, в которых я хочу контекст концентратора I имеют свойство

public IConnectionManager ConnectionManager { get; set; } 

, который я зарегистрировать следующим образом:

newBuilder.RegisterInstance(resolver.Resolve<IConnectionManager>()); 

, где resolver является new AutofacDependencyResolver(container);

Тогда, я в основном использовать ConnectionManager очень похожи на GlobalHost:

var context = ConnectionManager.GetHubContext<WorkshopsHub>(); 

тогда я называю context.Clients.All.clientMethod();

Таким образом, я легко могу обновлять клиент из-за пределы ступицы, имею легко ремонтопригоден код и следовать лучшему практики (я думаю и надеюсь: D).

Я также думал о регистрации и разрешении их при запуске, но это кажется очень сложной задачей, с очень небольшим преимуществом (отличным от того, чтобы чувствовать себя хорошо, когда это удается).

Надеюсь, это поможет! Удачи!

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