8

私はSignalRを使い始めていますが、すべてが構成されるとうまく機能します。しかし、私が取り組んでいるほとんどすべてのアプリケーションはCastle Windsorを使用しているので、それらを一緒に使用できるのは素晴らしいことです。これを実行したい理由は、永続的な接続内でCastleの依存関係/サービスを使用できるようにするためです。

ソースコードを調べたところ、DependencyResolverをCastleベースのもの(つまり、CastleがIDependencyResolverを実装しているもの)に置き換えるか、DependencyResolverの使用法をCastleに変更できるようです。

これらのどれがより良い考えですか?CastleとSignalRを組み合わせるために使用できる別のアプローチはありますか?

ありがとう、エリック

4

3 に答える 3

6

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年からの古い答え

独自のDependencyResolverを設定する最初のオプションを選択しました

AspNetHost.SetResolver(new SignalResolver(_container));

必要に応じてSignalResolverを提供できますが、今のところ読みやすくするために省略しています。

もう1つの重要な注意点は、ハブには空のコンストラクターが必要であるため、城のコンテナーがプロパティを介して注入することです。

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;
            }
        }
    }
于 2012-05-11T10:31:24.577 に答える
3

これが私がやったことです。まず、Windsor wikiをフォローして、ASP.NETMVC3のセットアップを取得しました。私の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が同じプロジェクトからWTFを実行しようとしているのかどうかはわかりませんでしたが、うまく機能しているように見える独自のプロジェクトを作成しました(もちろん、これがうまくいかない理由については、どんな提案も受け付けています)。

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

また、これは新しいSignalRバージョン0.5以降用です

于 2012-07-13T21:34:56.533 に答える
1

鳩の答えは問題ありませんが、少し混乱し、別のより具体的な答えを追加します。私の主な目標はこれが機能することです:

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

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

もちろん、必要なのはハブを作成することです。通常、ハブはSignalRによって作成されますが、いくつかの依存関係があるため、SignalRでは作成できません。SignalR自体には、独自の依存関係を取得するために使用する依存関係リゾルバー(SignalR名前空間内)があり、それに何かを追加できますが、Windsorに覚えてもらいたいですか?したがって、IHubActivatorハブの作成方法を変更します。SignalRではなく、次のハブを使用します。

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;
    }
}

SignalRコンテナでこれを置き換えるには、次のような操作を行う必要があります。

// 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 });

これで、すべてのハブをWindsorに登録する必要があります。

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

注: SignalRHubActivatorもコンポーネントとして登録しました。これは、Startup使用するクラスがアクティベーターを依存関係として受け取るためです。

container.Register(Component.For<SignalRHubActivator>().
    DependsOn(Dependency.OnValue("container", container)));
于 2017-09-29T16:34:42.807 に答える