0

以下のクラスを検討してください。

using Microsoft.AspNet.SignalR;
public class TwitterStream
    {
        // Hub Context
        IHubContext context = GlobalHost.ConnectionManager.GetHubContext<GeoFeedHub>();

        public void ChangeStreamBounds(double latitude, double longitude)
        {
            Debug.WriteLine(latitude + "-" + longitude);
        }

        // Lots of other interesting code redacted
   }

ChangeStreamBoundsHub クラス外でもクライアントからメソッドを呼び出すことはできますか? サーバーから (および Hub クラスの外部から) クライアント関数を呼び出すことは可能ですが、その逆は可能ですか?

残念ながら、私は少し窮地に立たされており、コードは私が作成したクラスから実行する必要があります (ハブ自体からではなく、もちろん SignalR ハブをタスク ファクトリとして実行できる場合を除きます)。

4

1 に答える 1

2

HubConnections およびs (ハブ メソッド呼び出しにバインドできるようにする) または下位レベルの APIに関する質問への回答があるかもしれませんが、IHubProxyこれについて間違った方法で行っている可能性があると思います。

概念的には、 でGeoFeedHubクライアント リクエストを処理し、TwitterStreamクラスで Twitter API との対話を処理する必要があります。したがって、GeoFeedHubクラスは に依存していTwitterStreamます。

TwitterStreamクラスにasyncメソッドがあるのは良いことであり、これはSignalR で完全にサポートされています。を呼び出す非同期ハブ メソッドを使用できるため、で使用TwitterStreamする必要がなくなります。 TaskFactoryGlobal.asax

アプリケーションの開始時に作成してTwitterStreamHub 呼び出しをそれにバインドする方法を見つけようとする (後方依存性と単一責任原則の違反) 代わりに、リアルタイム クライアント間の接点として Hub を立てる方がクリーンです。のインスタンスを にTwitterStream挿入しGeoFeedHubて、Hub が Twitter API にアクセスできるようにします。


このアイデアを説明するためのサンプル コードを次に示します。

public class GeoFeedHub : Hub
{
    // Declare dependency on TwitterStream class
    private readonly TwitterStream _twitterStream;

    // Use constructor injection to get an instance of TwitterStream
    public GeoFeedHub(TwitterStream _twitterStream)
    {
        _twitterStream = _twitterStream;
    }

    // Clients can call this method, which uses the instance of TwitterStream
    public async Task SetStreamBounds(double latitude, double longitude)
    {
        await _twitterStream.SetStreamBoundsAsync(latitude, longitude);
    }
}


public class TwitterStream
{
    public TwitterStream() 
    {
    }

    public async Task SetStreamBoundsAsync(double latitude, double longitude)
    {
        // Do something with Twitter here maybe?
        await SomeComponent.SetStreamBoundsAsync(latitude, longitude);
    }

    // More awesome code here
}

この例では DI を使用しているので、これを接続するために必要なグルー コードの一部を次に示します。このコードはあなたのApp_Startフォルダに入ります:

// Configure Unity as our DI container
public class UnityConfig
{

    private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    public static IUnityContainer GetConfiguredContainer()
    {
        return Container.Value;
    }


    private static void RegisterTypes(IUnityContainer container)
    {
        var twitterService = new TwitterService();
        container.RegisterInstance(twitterService);

        /*
         * Using RegisterInstance effectively makes a Singleton instance of 
         * the object accessible throughout the application.  If you don't need 
         * (or want) the class to be shared among all clients, then use 
         * container.RegisterType<TwitterService, TwitterService>();
         * which will create a new instance for each client (i.e. each time a Hub
         * is created, you'll get a brand new TwitterService object)
         */
    }
}


// If you're using ASP.NET, this can be used to set the DependencyResolver for SignalR 
// so it uses your configured container

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(UnitySignalRActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(UnitySignalRActivator), "Shutdown")]

public static class UnitySignalRActivator
{
    public static void Start() 
    {
        var container = UnityConfig.GetConfiguredContainer();
        GlobalHost.DependencyResolver = new SignalRUnityDependencyResolver(container);
    }

    public static void Shutdown()
    {
        var container = UnityConfig.GetConfiguredContainer();
        container.Dispose();
    }
}

public class SignalRUnityDependencyResolver : DefaultDependencyResolver
{
    private readonly IUnityContainer _container;

    public SignalRUnityDependencyResolver(IUnityContainer container)
    {
        _container = container;
    }

    public override object GetService(Type serviceType)
    {
        return _container.IsRegistered(serviceType) 
            ? _container.Resolve(serviceType) 
            : base.GetService(serviceType);
    }

    public override IEnumerable<object> GetServices(Type serviceType)
    {
        return _container.IsRegistered(serviceType) 
            ? _container.ResolveAll(serviceType) 
            : base.GetServices(serviceType);
    }
}
于 2014-07-21T21:02:33.020 に答える