调用服务器方法是集线器类的从外面SignalR
客户考虑下面的类:调用服务器方法是集线器类的从外面SignalR
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
}
是否可以从客户端调用ChangeStreamBounds
方法,即使它是轮毂的外类?可以从服务器(以及Hub类以外的地方)调用客户端函数,但是否有可能以相反的方式进行操作?
不幸的是我已经把自己投入了一个角落,代码必须从我写的类中执行(而不是从Hub本身执行 - 除非你可以将SignalR Hub作为任务工厂运行)
您的问题可能有一个答案,涉及HubConnection
s和IHubProxy
s(允许您绑定到hub方法调用)或较低级别的API,但我认为您可能会以错误的方式解决这个问题。
从概念上讲,您希望GeoFeedHub
可以处理客户端请求,TwitterStream
类可以处理与Twitter API的交互。因此,你的GeoFeedHub
类对TwitterStream
有依赖。
这很好,您的TwitterStream
类有async
方法,这是fully supported in SignalR。您可以使用调用TwitterStream
的异步Hub方法,该方法不需要在Global.asax
中使用TaskFactory
。
而不是在应用程序启动时创建TwitterStream
,并试图找到一种方法将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);
}
}
谢谢!很好的答案 – adaam
为什么你不能把一个方法'是被客户端调用GeoFeedHub',然后调用'ChangeStreamBounds'你的'TwitterStream'的实例,从那里? –
@RyanErdmann我使用Task.Factory.StartNew(()=> new TwitterStream());'Global.asax' /'Application_Start'中创建'TwitterStream'类的实例。 – adaam
有趣。 'TwitterStream'的目的是什么?它看起来像'TwitterStream'本质上是你的应用程序的单例实例吗? –