我最近以AspBoilerplate(Abp)开始了一个新项目,并使用SignalR作为某种广播机制来告诉连接的客户端数据库中的某些记录是否已更改或添加或删除.
如果我将SignalR Hub用作AppService的代理,则一切正常,并通知客户端
public class TestHub : Hub
{
IMyAppService = _service
public TestHub(IMyAppService service)
{
_service = service;
}
public void CreateEntry(EntryDto entry)
{
_service.Create(entry);
Clients.All.entryCreated(entry);
}
}
但是,如果我尝试利用Abp的EventBus的优势,那么我实现了我的AppSevice将事件发送到EventBus:
class MyAppService : ApplicationService, IMyAppService
{
public IEventBus EventBus { get; set; }
private readonly IMyRepository _myRepository;
public LicenseAppService(ILicenseRepository myRepository)
{
EventBus = NullEventBus.Instance;
_myRepository = myRepository;
}
public virtual EntryDto CreateLicense(EntryDto input)
{
var newEntry = Mapper.Map<EntryDto >(_myRepository.Insert(input));
EventBus.Trigger(new EntryCreatedEventData { Entry = newEntry});
return newEntry;
}
}
然后,我尝试将集线器直接用作EventHandler,但这失败了,因为abp每当需要处理事件时都会创建自己的EventHandler类实例.但是这里的代码只是为了完整性:
public class TestHub : Hub,
IEventHandler<EntryCreatedEventData>
{
public void Handle(EntryCreatedEventData data)
{
Clients.All.entryCreated(data.Entry);
}
}
此后,我创建了一个单独的Listener类,并尝试使用像这样的集线器上下文并使用一个非常空的集线器:
public class TestHub : Hub
{
}
public class EntryChangeEventHandler : IEventHandler<EntryCreatedEventData>
{
private IHubContext _hubContext;
public EntryChangeEventHandler()
{
_hubContext = GlobalHost.ConnectionManager.GetHubContext<TestHub>();
public void Handle(EntryCreatedEventData data)
{
_hubContext.Clients.All.entryCreated(eventData.Entry);
}
}
在最后一个解决方案中,一切都顺利进行
_hubContext.Clients.All.entryCreated(eventData.Entry);
但在我的javascript实现的客户端上,从未调用过该方法.客户端(基于DurandalJs)在使用集线器作为代理与我想使用的新方法之间没有变化.
用于Signalr的客户端插件
define(["jquery", "signalr.hubs"],
function ($) {
var myHubProxy
function connect(onStarted, onCreated, onEdited, onDeleted) {
var connection = $.hubConnection();
myHubProxy = connection.createHubProxy('TestHub');
connection.connectionSlow(function () {
console.log('We are currently experiencing difficulties with the connection.')
});
connection.stateChanged(function (data) {
console.log('connectionStateChanged from ' + data.oldState + ' to ' + data.newState);
});
connection.error(function (error) {
console.log('SignalR error: ' + error)
});
myHubProxy .on('entryCreated', onCreated);
myHubProxy .on('updated', onEdited);
myHubProxy .on('deleted', onDeleted);
connection.logging = true;
//start the connection and bind functions to send messages to the hub
connection.start()
.done(function () { onStarted(); })
.fail(function (error) { console.log('Could not Connect! ' + error); });
}
return signalr =
{
connect: connect
};
});
使用插件查看:
define(['jquery', 'signalr/myHub],
function ($, myHubSR) {
return function () {
var that = this;
var _$view = null;
that.attached = function (view, parent) {
_$view = $(view);
}
that.activate = function () {
myHubSR.connect(that.onStarted, that.onCreated, that.onEdited, that.onDeleted);
}
that.onStarted= function () {
//do something
}
that.onCreated= function (data) {
//do something
}
that.onEdited = function (data) {
//do something
}
that.onDeleted= function (data) {
//do something
}
}
});
所以有人知道为什么我打电话时永远不会调用onCreated
_hubContext.Clients.All.entryCreated(eventData.Entry);
?
为了测试signalR通信是否完全有效,我添加了一个直接调用客户端方法的方法.调用此方法会将更新成功推送到客户端.所以我认为问题出在使用IHubContext远程调用所有客户端的任何线索中,在使用IHubContext时可能出什么毛病?
public class TestHub : Hub
{
public TestHub ()
:base()
{ }
public void Test()
{
this.Clients.All.entryCreated(new EntryDto());
}
}
解决方法:
首先,您是否已将EntryChangeEventHandler注册到DI?如果没有,请为EntryChangeEventHandler实现ITransientDependency接口.
您的问题可能与序列化有关.它可能不会序列化eventData.Entry.您可以尝试发送另一个DTO对象.
另外,您可以实施
IEventHandler<EntityChangedEventData<Project>>
为了侦听Project实体中的所有更改(包括插入,更新和删除).这里的项目只是一个示例实体.
对于第一种情况,如果TestHub没有注册到DI,它将无法工作.您也可以为TestHub类实现ITransientDependency.并且您应该使SignalR从DI容器中获取它.您可以使用这样的类:
public class WindsorDependencyResolver : DefaultDependencyResolver
{
public override object GetService(Type serviceType)
{
return IocManager.Instance.IocContainer.Kernel.HasComponent(serviceType) ? IocManager.Instance.IocContainer.Resolve(serviceType) : base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return IocManager.Instance.IocContainer.Kernel.HasComponent(serviceType) ? IocManager.Instance.IocContainer.ResolveAll(serviceType).Cast<object>() : base.GetServices(serviceType);
}
}
然后在启动时进行设置:
GlobalHost.DependencyResolver =新的WindsorDependencyResolver();
也许我的回答有点令人困惑:)我希望你能理解.