未使用 SignalR 找到名称为 'x' 的客户端方法
No client method with the name 'x' found with SignalR
我有一个 ASP.NET Boilerplate v3.6.2 项目 (.NET Core / Angular),我需要在其中从后端方法调用客户端函数,所以我使用 ASP.NET Core SignalR implementation.
我按照官方文档做了,所以:
在后端
在我的模块中,我将依赖添加到 AbpAspNetCoreSignalRModule
:
[DependsOn(typeof(AbpAspNetCoreSignalRModule))]
public class MyModule : AbpModule
并将 this NuGet 包添加到模块的项目中。
然后我扩展了 AbpCommonHub
class 以利用 SignalR Hub 的内置实现,添加了一个 SendMessage()
方法用于发送留言:
public interface IMySignalRHub : ITransientDependency
{
Task SendMessage(string message);
}
public class MySignalRHub: AbpCommonHub, IMySignalRHub {
protected IHubContext<MySignalRHub> _context;
protected IOnlineClientManager onlineClientManager;
protected IClientInfoProvider clientInfoProvider;
public MySignalRHub(
IHubContext<MySignalRHub> context,
IOnlineClientManager onlineClientManager,
IClientInfoProvider clientInfoProvider)
: base(onlineClientManager, clientInfoProvider) {
AbpSession = NullAbpSession.Instance;
_context = context;
}
public async Task SendMessage(string message) {
await _context.Clients.All.SendAsync("getMessage", string.Format("User {0}: {1}", AbpSession.UserId, message));
}
}
我将 '/signalr' url 的映射更改为 MySignalRHub
:
public class Startup {
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
[...]
# if FEATURE_SIGNALR
app.UseAppBuilder(ConfigureOwinServices);
# elif FEATURE_SIGNALR_ASPNETCORE
app.UseSignalR(routes => {
routes.MapHub<MySignalRHub>("/signalr");
});
# endif
[...]
}
}
然后我在服务实现中使用集线器发送消息:
public class MyAppService: AsyncCrudAppService<MyEntity, MyDto, int, PagedAndSortedResultRequestDto, MyCreateDto, MyDto>, IMyAppService {
private readonly IMySignalRHub _hub;
public MyAppService(IRepository<MyEntity> repository, IMySignalRHub hub) : base(repository) {
_hub = hub;
}
public override Task<MyDto> Create(MyCreateDto input) {
_hub.SendMessage("test string").Wait();
[...]
}
}
在客户端
原始模板中的所有配置和内含物都已到位。当我打开 Angular 应用程序时,我可以看到此控制台日志:
DEBUG: Connected to SignalR server!
DEBUG: Registered to the SignalR server!
当我尝试调用向客户端发送消息的后端服务时,我在控制台中收到此警告:
Warning: No client method with the name 'getMessage' found.
我尝试了在 official documentation 和互联网上找到的许多解决方案,但其中 none 有效。我无法在客户端代码中定义 'getMessage' 处理程序。
一些 无效的 我试过的例子:
实施 1:
// This point is reached
abp.event.on('getMessage', userNotification => {
debugger; // Never reaches this point
});
实施 2:
// This point is reached
abp.event.on('abp.notifications.received', userNotification => {
debugger; // Never reaches this point
});
实施 3:
// This is taken from the official documentation and triggers the error:
// ERROR TypeError: abp.signalr.startConnection is not a function
abp.signalr.startConnection('/signalr', function (connection) {
connection.on('getMessage', function (message) {
console.log('received message: ' + message);
});
});
你遇到过这种情况吗? Angular 客户端中是否有处理程序定义的简单工作示例?
更新
我尝试了这个替代解决方案,更改了 SignalRAspNetCoreHelper
class(基本模板附带的共享 class)的实现:
export class SignalRAspNetCoreHelper {
static initSignalR(): void {
var encryptedAuthToken = new UtilsService().getCookieValue(AppConsts.authorization.encrptedAuthTokenName);
abp.signalr = {
autoConnect: true,
connect: undefined,
hubs: undefined,
qs: AppConsts.authorization.encrptedAuthTokenName + "=" + encodeURIComponent(encryptedAuthToken),
remoteServiceBaseUrl: AppConsts.remoteServiceBaseUrl,
startConnection: undefined,
url: '/signalr'
};
jQuery.getScript(AppConsts.appBaseUrl + '/assets/abp/abp.signalr-client.js', () => {
// ADDED THIS
abp.signalr.startConnection(abp.signalr.url, function (connection) {
connection.on('getMessage', function (message) { // Register for incoming messages
console.log('received message: ' + message);
});
});
});
}
}
现在在控制台中我可以看到两条消息:
Warning: No client method with the name 'getMessage' found.
SignalRAspNetCoreHelper.ts:22 received message: User 2: asd
所以它正在工作,但不完全。 'getMessage' 处理程序在某处不可见。
使用 ASP.NET 样板在 Angular 中实现消息处理程序的正确方法是什么?
设置autoConnect: false
开始你自己的连接:
abp.signalr = {
autoConnect: false,
// ...
};
更好...
不要扩展 AbpCommonHub
。你会发现实时通知停止工作,你需要替换 IRealTimeNotifier
因为 SignalRRealTimeNotifier
使用 AbpCommonHub
.
Do you have a simple working example of the handler definition in the Angular client?
What is the proper way to implement the messages handler in Angular with ASPNet Boilerplate?
按照文档创建一个单独的中心。
您应该使用 Clients.Others.SendAsync
或 Client.AllExcept.SendAsync
而不是 Clients.All.SendAsync
。
Clients.All.SendAsync
专为客户端想要发送和接收消息的场景(如聊天室)而设计。因此,所有连接的客户端都应该实现 connection.on('getMessage',
以接收通知。如果他们不这样做,他们会发出警告 在收到他们刚刚推送的通知时找不到名称为 'x' 的客户端方法。
在您的场景中,我了解到您有一种客户端推送通知,另一种客户端接收通知(例如 GPS 设备将位置发送到跟踪应用程序)。在这种情况下,使用 Clients.Others.SendAsync
或 Client.AllExcept.SendAsync
将确保推送客户端不会广播回他们(或他们的同类)刚刚推送的通知。
我在使用包 "@aspnet/signalr": "1.1.4"
的 Angular 应用程序中遇到了同样的错误。
出现这个问题的原因是我加入频道后没有调用订阅方法
public async getWorkSheetById(worksheetId: string): Promise < Worksheet > {
const worksheet: Worksheet = await this._worksheetService.getWorksheet(worksheetId);
this.displayWorksheet(worksheet);
await this._worksheetEventsService.joinWorksheetChannel(this._loadedWorksheet.id);
return worksheet;
}
所以,为了解决这个问题,我在加入后调用了订阅方法 await this.subscribeToSendMethod(this._loadedWorksheet)
)
public subscribeToSendMethod(loadedWorksheet: Worksheet): Worksheet {
let newWorksheet: Worksheet;
this._hubConnection.on('Send', (groupId: string, payloadType: string, payload: string, senderUserId: string)=> {
newWorksheet=this._worksheetHandler.handlePayload(payloadType, payload, loadedWorksheet);
this.displayWorksheet(newWorksheet);
}
);
return newWorksheet;
}
我有一个 ASP.NET Boilerplate v3.6.2 项目 (.NET Core / Angular),我需要在其中从后端方法调用客户端函数,所以我使用 ASP.NET Core SignalR implementation.
我按照官方文档做了,所以:
在后端
在我的模块中,我将依赖添加到
AbpAspNetCoreSignalRModule
:[DependsOn(typeof(AbpAspNetCoreSignalRModule))] public class MyModule : AbpModule
并将 this NuGet 包添加到模块的项目中。
然后我扩展了
AbpCommonHub
class 以利用 SignalR Hub 的内置实现,添加了一个SendMessage()
方法用于发送留言:public interface IMySignalRHub : ITransientDependency { Task SendMessage(string message); } public class MySignalRHub: AbpCommonHub, IMySignalRHub { protected IHubContext<MySignalRHub> _context; protected IOnlineClientManager onlineClientManager; protected IClientInfoProvider clientInfoProvider; public MySignalRHub( IHubContext<MySignalRHub> context, IOnlineClientManager onlineClientManager, IClientInfoProvider clientInfoProvider) : base(onlineClientManager, clientInfoProvider) { AbpSession = NullAbpSession.Instance; _context = context; } public async Task SendMessage(string message) { await _context.Clients.All.SendAsync("getMessage", string.Format("User {0}: {1}", AbpSession.UserId, message)); } }
我将 '/signalr' url 的映射更改为
MySignalRHub
:public class Startup { public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { [...] # if FEATURE_SIGNALR app.UseAppBuilder(ConfigureOwinServices); # elif FEATURE_SIGNALR_ASPNETCORE app.UseSignalR(routes => { routes.MapHub<MySignalRHub>("/signalr"); }); # endif [...] } }
然后我在服务实现中使用集线器发送消息:
public class MyAppService: AsyncCrudAppService<MyEntity, MyDto, int, PagedAndSortedResultRequestDto, MyCreateDto, MyDto>, IMyAppService { private readonly IMySignalRHub _hub; public MyAppService(IRepository<MyEntity> repository, IMySignalRHub hub) : base(repository) { _hub = hub; } public override Task<MyDto> Create(MyCreateDto input) { _hub.SendMessage("test string").Wait(); [...] } }
在客户端
原始模板中的所有配置和内含物都已到位。当我打开 Angular 应用程序时,我可以看到此控制台日志:
DEBUG: Connected to SignalR server!
DEBUG: Registered to the SignalR server!
当我尝试调用向客户端发送消息的后端服务时,我在控制台中收到此警告:
Warning: No client method with the name 'getMessage' found.
我尝试了在 official documentation 和互联网上找到的许多解决方案,但其中 none 有效。我无法在客户端代码中定义 'getMessage' 处理程序。
一些 无效的 我试过的例子:
实施 1:
// This point is reached
abp.event.on('getMessage', userNotification => {
debugger; // Never reaches this point
});
实施 2:
// This point is reached
abp.event.on('abp.notifications.received', userNotification => {
debugger; // Never reaches this point
});
实施 3:
// This is taken from the official documentation and triggers the error:
// ERROR TypeError: abp.signalr.startConnection is not a function
abp.signalr.startConnection('/signalr', function (connection) {
connection.on('getMessage', function (message) {
console.log('received message: ' + message);
});
});
你遇到过这种情况吗? Angular 客户端中是否有处理程序定义的简单工作示例?
更新
我尝试了这个替代解决方案,更改了 SignalRAspNetCoreHelper
class(基本模板附带的共享 class)的实现:
export class SignalRAspNetCoreHelper {
static initSignalR(): void {
var encryptedAuthToken = new UtilsService().getCookieValue(AppConsts.authorization.encrptedAuthTokenName);
abp.signalr = {
autoConnect: true,
connect: undefined,
hubs: undefined,
qs: AppConsts.authorization.encrptedAuthTokenName + "=" + encodeURIComponent(encryptedAuthToken),
remoteServiceBaseUrl: AppConsts.remoteServiceBaseUrl,
startConnection: undefined,
url: '/signalr'
};
jQuery.getScript(AppConsts.appBaseUrl + '/assets/abp/abp.signalr-client.js', () => {
// ADDED THIS
abp.signalr.startConnection(abp.signalr.url, function (connection) {
connection.on('getMessage', function (message) { // Register for incoming messages
console.log('received message: ' + message);
});
});
});
}
}
现在在控制台中我可以看到两条消息:
Warning: No client method with the name 'getMessage' found.
SignalRAspNetCoreHelper.ts:22 received message: User 2: asd
所以它正在工作,但不完全。 'getMessage' 处理程序在某处不可见。 使用 ASP.NET 样板在 Angular 中实现消息处理程序的正确方法是什么?
设置autoConnect: false
开始你自己的连接:
abp.signalr = {
autoConnect: false,
// ...
};
更好...
不要扩展 AbpCommonHub
。你会发现实时通知停止工作,你需要替换 IRealTimeNotifier
因为 SignalRRealTimeNotifier
使用 AbpCommonHub
.
Do you have a simple working example of the handler definition in the Angular client?
What is the proper way to implement the messages handler in Angular with ASPNet Boilerplate?
按照文档创建一个单独的中心。
您应该使用 Clients.Others.SendAsync
或 Client.AllExcept.SendAsync
而不是 Clients.All.SendAsync
。
Clients.All.SendAsync
专为客户端想要发送和接收消息的场景(如聊天室)而设计。因此,所有连接的客户端都应该实现 connection.on('getMessage',
以接收通知。如果他们不这样做,他们会发出警告 在收到他们刚刚推送的通知时找不到名称为 'x' 的客户端方法。
在您的场景中,我了解到您有一种客户端推送通知,另一种客户端接收通知(例如 GPS 设备将位置发送到跟踪应用程序)。在这种情况下,使用 Clients.Others.SendAsync
或 Client.AllExcept.SendAsync
将确保推送客户端不会广播回他们(或他们的同类)刚刚推送的通知。
我在使用包 "@aspnet/signalr": "1.1.4"
的 Angular 应用程序中遇到了同样的错误。
出现这个问题的原因是我加入频道后没有调用订阅方法
public async getWorkSheetById(worksheetId: string): Promise < Worksheet > {
const worksheet: Worksheet = await this._worksheetService.getWorksheet(worksheetId);
this.displayWorksheet(worksheet);
await this._worksheetEventsService.joinWorksheetChannel(this._loadedWorksheet.id);
return worksheet;
}
所以,为了解决这个问题,我在加入后调用了订阅方法 await this.subscribeToSendMethod(this._loadedWorksheet)
)
public subscribeToSendMethod(loadedWorksheet: Worksheet): Worksheet {
let newWorksheet: Worksheet;
this._hubConnection.on('Send', (groupId: string, payloadType: string, payload: string, senderUserId: string)=> {
newWorksheet=this._worksheetHandler.handlePayload(payloadType, payload, loadedWorksheet);
this.displayWorksheet(newWorksheet);
}
);
return newWorksheet;
}