Base solution for your next web application
Open Closed

How to do Entity updates to the angular GUI. Tried SignalR and NotificationSystem - does nothing. Why? #8639


User avatar
0
ips-rk created

Hi, I am riddling for some days now about how to relaize a simple matter: Some user updates an entity whilst another user is just viewing this entity in some way (eg. list view). The backend should now notify in that special case (not all places) ping the GUI so it can requery the backend and show an updated list.

I have tried at first to do my very own SignalR Hub for that. Somehow works but was not satisfying. And seems to look untidy with existing SignalR hubs. The topic about extending the AbpCommonHup by the way is badly documented and it is not clear, whether this is a feasable or even recommended way.

Then I came across the notification system and thought, this could just give me one notification as a by product. However my TS-code never gets called. What am I doing wrong?

What am I trying?

I created this transiend class that some code calls to notify the GUI (works until it calls the Publish (tried both Async and non-Async):

public class EntityUpdateNotifyer: ITransientDependency
{
private readonly INotificationPublisher \_notificationPublisher;


    public EntityUpdateNotifyer(INotificationPublisher notificationPublisher) 
        : base()
    {
        _notificationPublisher = notificationPublisher;
        AbpSession = NullAbpSession.Instance;
    }

    public IAbpSession AbpSession { get; set; }

    public async Task NotifyClients(Type entiType, object id)
    {
        UserIdentifier uid = AbpSession.ToUserIdentifier();
        var data = new NotificationData();
        this._notificationPublisher.Publish("test.note.foobar", data, new EntityIdentifier(entiType, id), NotificationSeverity.Info, 
            null, null, null);
        return;
    }
}

For the client side (angular+TS) I extended a classical list view like that. I am not seeing the event caused alert. The others yes. So ngOnInit gets called.

  ...
   constructor(
        injector: Injector,
        private _appSessService: AppSessionService,
        private _objekteServiceProxy: ObjekteServiceProxy,
        private _notifyService: NotifyService,
        private _tokenAuth: TokenAuthServiceProxy,
        private _activatedRoute: ActivatedRoute,
        private _fileDownloadService: FileDownloadService
    ) {
        super(injector);
        this._blaServiceProxy.getDistinctBla()
            .subscribe(result => { this.distinctBlaList = result.concat(""); });
    }

    ngOnInit(): void {
        alert("nginit");    
        abp.event.on('abp.notifications.received', function (userNotification) {
            alert("event  a" + userNotification); 
        });
        abp.event.on('test.note.foobar', function (userNotification) {
            alert("event foobar" + userNotification); 
        });
      }
      
      ...

I tried to subscribe to the somehow mentioned abp.notifications.received event ID plus my own ID (this does not quite read out of the documentation). But my event alerts never appear.

It must be just a detail that I am missing. Please show me the detail.


5 Answer(s)
  • User Avatar
    -1
    aaron created
    Support Team
  • User Avatar
    0
    ips-rk created

    Well, I came across that thread and the description, too. But honestly this is massively confusing. It kind of has/lacks the 'missing link' to the UI.... It did not resolve my problem and I still do not receive the client side callback.

    What I understood: So the notification system expects the GUI to call into some AppService or Controller where the code then cann call a SubscribeAsync() with the current user from that session. Is it that????

    So after working this all trough, I added this line in my AppService, where the listing calls across:

    class MyObjekteAppService
    {
    ...
           public async Task<PagedResultDto<GetObjekteForViewDto>> GetAll(GetAllObjekteInput input)
            {
                try
                {
                    // Subscribe for entity updates
                    await _notificationSubscriptionManager.SubscribeAsync(AbpSession.ToUserIdentifier(), "test.note.foobar", new EntityIdentifier(typeof(OBJEKTE), 0));
    

    a directly following call to var subs = await _notificationSubscriptionManager.GetSubscribedNotificationsAsync(AbpSession.ToUserIdentifier()); asserts, that this subscription has been added.

    I use 0 here, and everywhere else, because I am rather interested in any update to OBJEKTE.

    But still nothing happens on the client side.

    Still the client side listens(?) to both events names, while just the first one would be right....

     ngOnInit(): void {
            alert("nginit");    
            abp.event.on('abp.notifications.received', function (userNotification) {
                alert("event  a" + userNotification); 
            });
            abp.event.on('test.note.foobar', function (userNotification) {
                alert("event foobar" + userNotification); 
            });
          }
    

    But perhaps this is not the right tool anyways? Because those entity updates I want to have do not really have to be persisted in any way.

    I whish some clarification about that

    Or maybe using SingalR instead would be wise?!?!

  • User Avatar
    0
    aaron created
    Support Team

    What I understood: So the notification system expects the GUI to call into some AppService or Controller where the code then can call a SubscribeAsync() with the current user from that session. Is it that?

    No, the user should only subscribe once (e.g. when the user is created) rather than in MyObjekteAppService.GetAll.

    Still the client side listens(?) to both events names, while just the first one would be right.

    I don't understand what you mean by "just the first one would be right".

    But perhaps this is not the right tool anyways? Because those entity updates I want to have do not really have to be persisted in any way. ... Or maybe using SingalR instead would be wise?

    Yes. Documentation: https://aspnetboilerplate.com/Pages/Documents/SignalR-AspNetCore-Integration

  • User Avatar
    0
    ips-rk created

    So rather take a chance in SignalR, instead? Just to do GUI updates on entity changes...

    Then, would it rather make sense to extent the AbpCommonHub?

    From what the sparse documentation tels you should inherit it and extend it plus use yours it in the Startup.cs instead of AbpCommonHub.

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub&lt;AbpCommonHub&gt;("/signalr");
                endpoints.MapHub&lt;ChatHub&gt;("/signalr-chat");
    

    to

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub&lt;MyCommonHub&gt;("/signalr");
                endpoints.MapHub&lt;ChatHub&gt;("/signalr-chat");
    

    but from discussions I remember this caused problems somehow. Probably because strong references were made in other opaque code places.

  • User Avatar
    0
    aaron created
    Support Team

    So rather take a chance in SignalR, instead? Just to do GUI updates on entity changes...

    That's as simple as it gets, other than direct long-polling.

    Then, would it rather make sense to extent the AbpCommonHub?

    From what the sparse documentation tels you should inherit it and extend it plus use yours it in the Startup.cs instead of AbpCommonHub.

    ...

    but from discussions I remember this caused problems somehow. Probably because strong references were made in other opaque code places.

    No, the documentation does not tell you to inherit AbpCommonHub. It says "we can inherit AbpHubBase".