I have an ASP.NET Boilerplate v3.6.2 project (.NET Core / Angular) in which I need to call a client function from a backend method, so I'm using the ASP.NET Core SignalR implementation.
I followed the official documentation, so:
In the backend
In my module, I added the dependency to
AbpAspNetCoreSignalRModule
:[DependsOn(typeof(AbpAspNetCoreSignalRModule))] public class MyModule : AbpModule
And added this NuGet package to the module's project.
Then I extended the
AbpCommonHub
class to take advantage of the built-in implementation of the SignalR Hub, adding aSendMessage()
method used to send the message: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)); } }
I changed the mapping of the '/signalr' url to
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 [...] } }
Then I use the hub to send a message in a service implementation:
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(); [...] } }
In the client
All the configurations and inclusions are already in place from the original template. When I open the Angular app I can see this console logs:
DEBUG: Connected to SignalR server!
DEBUG: Registered to the SignalR server!
When I try to call the backend service which sends the message to the client, I get this warning in console:
Warning: No client method with the name 'getMessage' found.
I tried many solutions found in the official documentation and on the Internet but none of them worked. I'm not able to define the 'getMessage' handler in the client code.
Some non-working examples I tried:
Implementation 1:
// This point is reached
abp.event.on('getMessage', userNotification => {
debugger; // Never reaches this point
});
Implementation 2:
// This point is reached
abp.event.on('abp.notifications.received', userNotification => {
debugger; // Never reaches this point
});
Implementation 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);
});
});
Have you ever found yourself in this situation? Do you have a simple working example of the handler definition in the Angular client?
UPDATE
I tried this alternative solution, changing the implementation of the SignalRAspNetCoreHelper
class (a shared class which is shipped with the base template):
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);
});
});
});
}
}
Now in the console I can see both the messages:
Warning: No client method with the name 'getMessage' found.
SignalRAspNetCoreHelper.ts:22 received message: User 2: asd
So it is working, but not fully. Somewhere the 'getMessage' handler is not visible. What is the proper way to implement the messages handler in Angular with ASP.NET Boilerplate?