Base solution for your next web application
Open Closed

Entity notifications issue #12502


User avatar
0
Loizos created

Version 13.4.0, Angular 18, .NET 8

Hi Support,

We are experiencing an issue when trying to use entity notifications. Basically when an entity notification is published, we get the below JavaScript error at the angular side with result the notifications bar and also the notifications page not fetching any data at all.

After some investigation I see that the record that is added to AbpTenantNotifications is responsible to produce this error and if I make the Entity fields (EntityId, EntityTypeAssemblyQualifiedName, EntityTypeName) NULL then all works and the new notification as well as all previous are shown properly.

ERROR SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data handleErrorResponse zero-template-http-interceptor.ts:20 RxJS 3 onload abp-ng2-module.mjs:454 Angular 5 core.mjs:7404:23

Please advise!

Thanks, Loizos

Markdown is supported
Copy & paste or drag & drop images (max 30 MB per image)

5 Answer(s)
  • User Avatar
    0
    Loizos created

    Hi support,

    Is there any update on this?

    Thanks Loizos

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi @Loizos

    Sorry for the late response. In order to reproduce this issue in your case, could you please send your project to [email protected]? This way, we can provide you with a faster and more specific response.

    Thank you

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    Loizos created

    Hi @oguzhanagir

    I am afraid I cannot send entire project. Is there any other option?

    Did you attempt to replicate it at your side at all? We haven't changed anything from core/out of the box code. We just try to use entity notifications. Subscribe works fine as we want it. When publish though to any notifier it produces above problem.

    Loizos

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi @Loizos

    Thank you for the follow up. We have analyzed the issue and can confirm the problem is related to how entity notification data is serialized. You can resolve this without sending us the entire project by implementing the following changes. We also created an issue for this, you can follow the developments here.

    The root cause is the EntityType property (which is a System.Type object) within the TenantNotification class. The .NET JSON serializer converts this property into a complex object that the Angular client cannot parse, leading to the JSON.parse error. The [Obsolete] attribute on this property in ABP's source code already warns that this is a known bad practice.

    The solution is to use Data Transfer Objects (DTOs) to send a "clean" version of the notification data to the client, without the problematic EntityType property.

    Here is a step by step guide to fix this:

    Define Your Safe Notification DTOs

    First, ensure you have your own set of DTOs for notifications. Based on your code, you have already done this correctly by creating classes in the MyCompanyName.AbpZeroTemplate.Notifications.Dto namespace and removing the EntityType property. This is the correct approach.

    For clarity, these are the DTOs you should have:

    // In a file like /Notifications/Dto/UserNotificationDto.cs
    
    namespace MyCompanyName.AbpZeroTemplate.Notifications.Dto
    {
        [Serializable]
        public class UserNotification : EntityDto<Guid>, IUserIdentifier
        {
            public int? TenantId { get; set; }
            public long UserId { get; set; }
            public UserNotificationState State { get; set; }
            public TenantNotification Notification { get; set; }
            // Other properties...
        }
    
        [Serializable]
        public class TenantNotification : EntityDto<Guid>, IHasCreationTime
        {
            public string NotificationName { get; set; }
            public NotificationData Data { get; set; }
            public string EntityTypeName { get; set; } // This string version is safe
            public object EntityId { get; set; }
            public NotificationSeverity Severity { get; set; }
            public DateTime CreationTime { get; set; }
            
            // The problematic 'public Type EntityType { get; set; }' is correctly removed.
        }
    }
    

    Update the NotificationAppService

    Next, modify the GetUserNotifications method in your NotificationAppService.cs to map the original notification objects to your new safe DTOs before returning them.

    // In NotificationAppService.cs
    
    public async Task<GetNotificationsOutput> GetUserNotifications(GetNotificationsInput input)
    { 
        var totalCount = await _userNotificationManager.GetUserNotificationCountAsync(
          AbpSession.ToUserIdentifier(), input.State, input.StartDate, input.EndDate
        );
        
        var unreadCount = await _userNotificationManager.GetUserNotificationCountAsync(
          AbpSession.ToUserIdentifier(), UserNotificationState.Unread, input.StartDate, input.EndDate
        );
        var notifications = await _userNotificationManager.GetUserNotificationsAsync(
          AbpSession.ToUserIdentifier(), input.State, input.SkipCount, input.MaxResultCount, input.StartDate,
          input.EndDate
        );
    
        // Map the framework objects to your safe DTOs
        var notificationDtos = ObjectMapper.Map<List<Dto.UserNotification>>(notifications);
    
        // Return the GetNotificationsOutput with your DTO list
        return new GetNotificationsOutput(totalCount, unreadCount, notificationDtos);
    }
    

    Configure AutoMapper

    The ObjectMapper.Map call requires mapping rules. You must tell AutoMapper how to convert the framework's notification types to your DTOs. Add the following configuration to CustomDtoMapper.cs in your .Application project.

    // In CustomDtoMapper.cs
    
    using MyCompanyName.AbpZeroTemplate.Notifications.Dto;
    //...
    
    internal static class CustomDtoMapper
    {
        public static void CreateMappings(IMapperConfigurationExpression configuration)
        {
            // ... other existing mappings
    
            // Add these two lines to define the mapping rules
            configuration.CreateMap<Abp.Notifications.UserNotification, UserNotification>();
            configuration.CreateMap<Abp.Notifications.TenantNotification, TenantNotification>();
        }
    }
    

    Ensure GetNotificationsOutput Uses Your DTO

    Finally, confirm that your GetNotificationsOutput class uses your custom UserNotification DTO. Your provided code is already correct.

    // In /Notifications/Dto/GetNotificationsOutput.cs
    
    // The generic type PagedResultDto<UserNotification> correctly refers to your DTO
    // in the MyCompanyName.AbpZeroTemplate.Notifications.Dto namespace.
    public class GetNotificationsOutput : PagedResultDto<UserNotification>
    {
        public int UnreadCount { get; set; }
    
        public GetNotificationsOutput(int totalCount, int unreadCount, List<UserNotification> notifications)
            : base(totalCount, notifications)
        {
            UnreadCount = unreadCount;
        }
    }
    

    By following these steps, you are intercepting the problematic data from the framework and transforming it into a clean, safe format before it is sent to the Angular client. This will resolve the JSON.parse error.

    Please let us know if this solves the issue.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    Loizos created

    Hi @oguzhanagir,

    Thanks for your answer. So basically we've solved it by adding below line of code in NotificationAppService/GetUserNotifications, as a temporary solution. Once you fix it in your next release we will remove it.

    notifications.ForEach(notification => notification.Notification.EntityType = null);

    Thanks, Loizos

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)