集成温莎城堡与SignalR - 我应该如何处理呢?(Integrating Castle Win

2019-06-24 06:49发布

我开始使用SignalR,一旦一切都配置它的伟大工程。 然而,几乎所有我在使用温莎城堡工作,所以这将是伟大的应用程序能够一起使用。 我想这样做的原因是,我可以用一个持续连接的内城相依/服务。

我在源代码周围挖,它看起来像我既可以使用基于一个城堡(即城堡实现的IDependencyResolver)取代DependencyResolver,我也可以DependencyResolver的使用改变城堡。

其中哪一个是一个更好的主意吗? 有没有我可以用它来城堡和SignalR结合的另一种方法?

谢谢,埃里克

Answer 1:

2016年8月更新

从下面的评论我不再使用下面的方法,但现在使用的GlobalHost.DependencyResolver

所以在Global.asax.cs中我初始化的东西

public static void Init(IWindsorContainer container)
{
    var conn = configurationManager.ConnectionStrings["SRSQL"].ConnectionString;
    GlobalHost.DependencyResolver.Register(typeof(IHubActivator), 
                                      () => new SignalHubActivator(container));
    GlobalHost.DependencyResolver.Register(typeof(ILoggingService), 
                                      container.Resolve<ILoggingService>);
    //etc or you could just pass your existing container to the resolver
    GlobalHost.DependencyResolver.UseSqlServer(conn);    
}

然后在轮毂

private ILoggingService LoggingService{ get; set; }

    public NotificationHub()
    {
        LoggingService = GlobalHost.DependencyResolver.Resolve<ILoggingService>();
    }

和完整性

public class SignalHubActivator: IHubActivator
{
    private readonly IWindsorContainer _container;

    public SignalHubActivator(IWindsorContainer container)
    {
        _container = container;
    }


    public IHub Create(HubDescriptor descriptor)
    {
                var result=  _container.Resolve(descriptor.HubType) as IHub;

        if (result is Hub)
        {
            _container.Release(result);
        }

    return result;
    }

}

从2012年OLD ANSWER

我设定自己的第一个选项去DependencyResolver

AspNetHost.SetResolver(new SignalResolver(_container));

如果需要的话,但留出了可读性,现在我可以提供SignalResolver。

另外要注意的是,所以我们的城堡容器注入通过属性,如集线器必须有一个空的构造

public class NotificationHub : Hub, INotificationHub
    { 

public INotificationService NotificationService { get; set; }

和解析请求

public class SignalResolver : DefaultDependencyResolver
    {
        private readonly IWindsorContainer _container;

        public SignalResolver(IWindsorContainer container) 
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            _container = container;
        }

        public override object GetService(Type serviceType) 
        {
            return TryGet(serviceType) ?? base.GetService(serviceType);
        }

        public override IEnumerable<object> GetServices(Type serviceType)
        {
            return TryGetAll(serviceType).Concat(base.GetServices(serviceType));
        }

        private object TryGet(Type serviceType)
        {
            try
            {
                return _container.Resolve(serviceType);
            }
            catch (Exception)
            {
                return null;
            }
        }

        private IEnumerable<object> TryGetAll(Type serviceType)
        {
            try
            {
                var array = _container.ResolveAll(serviceType);
                return array.Cast<object>().ToList();
            }
            catch (Exception)
            {
                return null;
            }
        }
    }


Answer 2:

下面是我落得这样做。 首先,我跟着一起温莎维基让我的ASP.NET MVC3设置一起。 我的Global.asax.cs:

private static IWindsorContainer _container;

    protected void Application_Start()
    {
        BootstrapContainer();
        RegisterRoutes(RouteTable.Routes);
        AreaRegistration.RegisterAllAreas();
        RegisterGlobalFilters(GlobalFilters.Filters);
    }

    protected void Application_End()
    {
        _container.Dispose();
    }

    private static void BootstrapContainer()
    {
        _container = new WindsorContainer().Install(FromAssembly.This());
        RouteTable.Routes.MapHubs(new CastleWindsorDependencyResolver(_container));
        var controllerFactory = new WindsorControllerFactory(_container.Kernel);
        ControllerBuilder.Current.SetControllerFactory(controllerFactory);
    }
    ...

CastleWindsorDependencyResolver从来到这里

复制:

public class CastleWindsorDependencyResolver : DefaultDependencyResolver
{
    private readonly IWindsorContainer _container;

    public CastleWindsorDependencyResolver(IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        _container = container;

        // perform the lazy registrations
        foreach (var c in _lazyRegistrations)
            _container.Register(c);

        _lazyRegistrations.Clear();
    }

    public override object GetService(Type serviceType)
    {
        if (_container.Kernel.HasComponent(serviceType))
            return _container.Resolve(serviceType);
        return base.GetService(serviceType);
    }

    public override IEnumerable<object> GetServices(Type serviceType)
    {
        IEnumerable<object> objects;
        if (_container.Kernel.HasComponent(serviceType))
            objects = _container.ResolveAll(serviceType).Cast<object>();
        else
            objects = new object[] { };

        var originalContainerServices = base.GetServices(serviceType);
        if (originalContainerServices != null)
            return objects.Concat(originalContainerServices);

        return objects;
    }

    public override void Register(Type serviceType, Func<object> activator)
    {
        if (_container != null)
            // cannot unregister components in windsor, so we use a trick
            _container.Register(Component.For(serviceType).UsingFactoryMethod<object>(activator, true).OverridesExistingRegistration());
        else
            // lazy registration for when the container is up
            _lazyRegistrations.Add(Component.For(serviceType).UsingFactoryMethod<object>(activator));

        // register the factory method in the default container too
        //base.Register(serviceType, activator);
    }

    // a form of laxy initialization is actually needed because the DefaultDependencyResolver starts initializing itself immediately
    // while we now want to store everything inside CastleWindsor, so the actual registration step have to be postponed until the
    // container is available
    private List<ComponentRegistration<object>> _lazyRegistrations = new List<ComponentRegistration<object>>();
}

public static class WindsorTrickyExtensions
{
    /// <summary>
    /// Overrideses the existing registration:
    /// to overide an existiong component registration you need to do two things:
    /// 1- give it a name.
    /// 2- set it as default.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="componentRegistration">The component registration.</param>
    /// <returns></returns>
    public static ComponentRegistration<T> OverridesExistingRegistration<T>(this ComponentRegistration<T> componentRegistration) where T : class
    {
        return componentRegistration
        .Named(Guid.NewGuid().ToString())
        .IsDefault();
    }
}

我不知道跆拳道的HubsInstaller试图从同一个项目要做,但我做我自己,这似乎做工精细(我当然愿意接受任何建议,为什么这可能吸):

public class HubsInstallers : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly()
                            .BasedOn<IHub>()
                            .LifestyleTransient());
    }
}

另外这是较新的版本SignalR 0.5+



Answer 3:

dove answer is fine but it is a bit confusing, adding another more specific answer. My main goal is this to work:

[HubName("MyHub")]
public class MyHub : Hub
{
    public IJobRepository JobRepository { get; }

    public MyHub(IJobRepository jobRepository)
    {
        JobRepository = jobRepository ?? throw new ArgumentNullException(nameof(jobRepository));
    }
...
}

Of course what you want is your Hubs to be created for you, they are usually created by SignalR but now that they have some dependencies SignalR cannot create them. SignalR itself has a Dependency Resolver (in SignalR namespace) which uses to get its own dependencies, you can add stuff to it, but we want Windsor remember? So we are going to change just how the IHubActivator creates hubs, we are not going to use SignalR's but this one:

public class SignalRHubActivator : IHubActivator
{
    private readonly IWindsorContainer _container;

    public SignalRHubActivator(IWindsorContainer container)
    {
        _container = container;
    }

    public IHub Create(HubDescriptor descriptor)
    {
        var result = _container.Resolve(descriptor.HubType) as IHub;
        if (result is Hub)
        {
            _container.Release(result);
        }
        return result;
    }
}

To replace this in SignalR container you have to do something like:

// Get an instance of the hub creator (see note below)
var _hubActivator = new SignalRHubActivator(container);

// Get the SignalR's Default Dependency Resolver
var signalRResolver = new Microsoft.AspNet.SignalR.DefaultDependencyResolver();
// Override the IHubActivator service
signalRResolver.Register(typeof(IHubActivator), () => _hubActivator);
// now map SignalR with this configuration
appBuilder.MapSignalR(new HubConfiguration { Resolver = signalRResolver });

And that's it, you should also register all your Hubs with Windsor

container.Register(Classes.FromThisAssembly()
    .BasedOn(typeof(Microsoft.AspNet.SignalR.Hub)));
...
container.Register(Component.For<IJobRepository>()).ImplementedBy<JobRepository>());

Note: I registered the SignalRHubActivator as a component too, this is because the Startup class I use receives the activator as a dependency:

container.Register(Component.For<SignalRHubActivator>().
    DependsOn(Dependency.OnValue("container", container)));


文章来源: Integrating Castle Windsor with SignalR - how should I approach this?