SignalR + Вопросы взыскания зависимостей
Я использую SignalR в своем приложении MVC3, и поскольку я реализовал Injection Dependency Injection StructureMap на моих контроллерах, я хотел бы сделать то же самое в моем хабе, но я не могу заставить его работать.
Скажите, пожалуйста, что случилось с моими кодами ниже:
SignalRSmDependencyResolver.cs
public class SignalRSmDependencyResolver : DefaultDependencyResolver
{
private IContainer _container;
public SignalRSmDependencyResolver(IContainer container)
{
_container = container;
}
public override object GetService(Type serviceType)
{
object service = null;
if (!serviceType.IsAbstract && !serviceType.IsInterface && serviceType.IsClass)
{
// Concrete type resolution
service = _container.GetInstance(serviceType);
}
else
{
// Other type resolution with base fallback
service = _container.TryGetInstance(serviceType) ?? base.GetService(serviceType);
}
return service;
}
public override IEnumerable<object> GetServices(Type serviceType)
{
var objects = _container.GetAllInstances(serviceType).Cast<object>();
objects.Concat(base.GetServices(serviceType));
return objects;
}
}
SignalRExtensionsRegistry.cs
public class SignalRExtensionsRegistry : Registry
{
public SignalRExtensionsRegistry()
{
For<IDependencyResolver>().Add<SignalRSmDependencyResolver>();
}
}
IoC.cs
public static class IoC {
public static IContainer Initialize() {
var container = BootStrapper.Initialize();
container.Configure(x =>
{
x.For<IControllerActivator>().Singleton().Use<StructureMapControllerActivator>();
});
return container;
}
}
public class StructureMapControllerActivator : IControllerActivator {
public StructureMapControllerActivator(IContainer container) {
_container = container;
}
private IContainer _container;
public IController Create(RequestContext requestContext, Type controllerType) {
IController controller = DependencyResolver.Current.GetService(controllerType) as IController;
return controller;
}
}
AppStart_Structuremap.cs
[assembly: WebActivator.PreApplicationStartMethod(typeof(StoreUI.AppStart_Structuremap), "Start")]
namespace MyNameSpace {
public static class AppStart_Structuremap {
public static void Start() {
var container = (IContainer) IoC.Initialize();
DependencyResolver.SetResolver(new StructureMapDependenceyResolver(container));
AspNetHost.SetResolver(new StructureMapDependencyResolver(container));
}
}
}
NotificationsHub.cs
[HubName("notificationsHub")]
public class NotificationsHub : Hub
{
#region Declarations
private readonly IUserService userService;
#endregion
#region Constructor
public NotificationsHub(IUserService userService)
{
this.userService = userService;
}
#endregion
public void updateServer(string message)
{
Clients.updateClient(message);
}
}
Спасибо
Ответы
Ответ 1
Получение Structuremap в SignalR на самом деле довольно просто. Сначала вы хотите создать свой собственный резольвер:
Резолюция StructureMap
Usings:
using SignalR.Infrastructure;
using StructureMap;
Класс:
public class StructureMapResolver : DefaultDependencyResolver
{
private IContainer _container;
public StructureMapResolver(IContainer container)
{
_container = container;
}
public override object GetService(Type serviceType)
{
object service = null;
if (!serviceType.IsAbstract && !serviceType.IsInterface && serviceType.IsClass)
{
// Concrete type resolution
service = _container.GetInstance(serviceType);
}
else
{
// Other type resolution with base fallback
service = _container.TryGetInstance(serviceType) ?? base.GetService(serviceType);
}
return service;
}
public override IEnumerable<object> GetServices(Type serviceType)
{
var objects = _container.GetAllInstances(serviceType).Cast<object>();
return objects.Concat(base.GetServices(serviceType));
}
}
Идея здесь состоит в том, чтобы попытаться использовать ваш контейнер для разрешения зависимостей, если у вас нет подключенной зависимости, передайте его по умолчанию. Таким образом, вам не нужно беспокоиться обо всех других зависимостях в SignalR и сосредоточиться только на том, что вы хотите ввести (Hubs, ConnectionIdFactory, MessageBus и т.д.).
Привязки для резольвера и концентратора
Затем вы захотите зарегистрировать это в своем контейнере (мне нравится использовать реестры):
Usings:
using SignalR.Infrastructure;
using StructureMap.Configuration.DSL;
Класс:
public class ExtensionsRegistry : Registry
{
public ExtensionsRegistry()
{
For<IDependencyResolver>().Add<StructureMapResolver>();
}
}
Замена резольвера
Наконец, вы захотите сказать SignalR использовать свой резольвер вместо стандартного:
Глобальный:: Application_Start или WebActivator:: Pre_Start
Usings:
using SignalR.Hosting.AspNet;
using SignalR.Infrastructure;
Application_Start:
// Make sure you build up the container first
AspNetHost.SetResolver(StructureMap.ObjectFactory.GetInstance<IDependencyResolver>());
Глупый концентратор с инъецированными зависимостями
Теперь вы можете просто вводить любые зависимости, которые ваш контейнер знает в самих концентраторах:
[HubName("defaultHub")]
public class DefaultHub : Hub, IDisconnect
{
private readonly IRepository _repo;
public DefaultHub(IRepository repo)
{
_repo = repo;
}
public void Connect()
{
Caller.setUser(Context.ConnectionId);
Clients.addMessage(string.Format("{0} has connected", Context.ConnectionId));
}
public void MessageSender(string message)
{
Caller.addMessage(_repo.RepositoryMessage());
Clients.addMessage(message);
}
public Task Disconnect()
{
var clientId = this.Context.ConnectionId;
return Task.Factory.StartNew(() => { Clients.addMessage(string.Format("{0} has disconnected", clientId)); });
}
}
Ответ 2
Вы следуете инструкциям здесь: - https://github.com/SignalR/SignalR/wiki/Extensibility?
Вам нужно использовать AspNetHost.SetResolver
.
Ответ 3
Я знаю, что это старый поток, но для тех, кто задается вопросом, где находится AspNetHost.SetResolver в более новой версии signalR, вы можете использовать это в App_Start StructuremapMvc.cs:
public static void Start() {
IContainer container = IoC.Initialize();
GlobalHost.DependencyResolver = new SignalRSmDependencyResolver(container); // for signalR
DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapDependencyResolver(container);
}
Ответ 4
Добавьте что-то подобное в файл в папке App_Start. Этот фрагмент кода предназначен для Ninject, поэтому просто замените AspNetHost.SetResolver()
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Ninject;
using SignalR.Hosting.AspNet;
using SignalR.Infrastructure;
using SignalR.Ninject;
using Web.Models;
[assembly: WebActivator.PreApplicationStartMethod(typeof(Web.App_Start.NinjectSignalR), "Start")]
namespace Web.App_Start
{
public static class NinjectSignalR
{
public static void Start()
{
IKernel kernel = CreateKernel();
// switch this line to the structuremap resolver
AspNetHost.SetResolver(new NinjectDependencyResolver(kernel));
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
RegisterServices(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
// add your services here
//kernel.Bind<IRepository>().To<Repository>();
}
}
}