Open Closed

Chat Module Unable to cast object of type 'Volo.Chat.Users.ChatUser' to type 'Volo.Abp.Users.IUserData #5226


User avatar
0
abpnewtonvisionco created

Hey guys, we are trying to implement the Chat Module for a Microservice based template. We added a new microservice and added the Chat module on this new microservice, however we are having the following issue:

  • ABP Framework version: v7.2.2

  • UI type: Angular

  • DB provider: EF Core

  • ** Identity Server Separated (Angular): yes

  • Exception message and stack trace:

  • System.InvalidCastException: 'Unable to cast object of type 'Volo.Chat.Users.ChatUser' to type 'Volo.Abp.Users.IUserData'.'

  • System.InvalidCastException HResult=0x80004002 Message=Unable to cast object of type 'Volo.Chat.Users.ChatUser' to type 'Volo.Abp.Users.IUserData'. Source=System.Linq StackTrace: at System.Linq.Enumerable.<CastIterator>d__671.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at Volo.Abp.Users.UserLookupService`2.

    This exception was originally thrown at this call stack: [External Code] Volo.Chat.Users.ContactAppService.GetContactsAsync(Volo.Chat.Users.GetContactsInput) in ContactAppService.cs

  • Steps to reproduce the issue:"

We followed the guide https://docs.abp.io/en/commercial/latest/modules/chat

We are able to see the Chat module on the Angular, however when we click on the "start conversation" we get a 503 error. When debugging this method:

public virtual async Task<List

    if (input.IncludeOtherContacts)
    {
        var lookupUsers = await _chatUserLookupService.SearchAsync(
            nameof(ChatUser.UserName),
            input.Filter,
            maxResultCount: ChatConsts.OtherContactLimitPerRequest);



        var lookupContacts = lookupUsers
            .Where(x => !(conversationContacts.Any(c => c.Username == x.UserName) || x.Id == CurrentUser.GetId()))
            .Select(x => new ChatContactDto
            {
                UserId = x.Id,
                Name = x.Name,
                Surname = x.Surname,
                Username = x.UserName
            });



        conversationContacts.AddRange(lookupContacts);
    }



    return conversationContacts;
}

7 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    You can try this.

    Update Chat Service project:

    • Update the appsettings.json
      "RemoteServices": {
        "AbpIdentity": {
          "BaseUrl": "https://localhost:44388/", Identity service URL
          "UseCurrentAccessToken": "false"
        }
      },
      "IdentityClients": {
        "Default": {
          "GrantType": "client_credentials",
          "ClientId": "AdministrationService",
          "ClientSecret": "1q2w3e*",
          "Authority": "https://localhost:44322", AuthServer URL
          "Scope": "IdentityService",
          "RequireHttps": "true",
          "ValidateIssuerName": "true",
          "ValidateEndpoints ": "true"
        }
      },
    
    • Grant user lookup permission to AdministrationService

    You can create an application named ChatService instead of using AdministrationService

    • Add package references

    <PackageReference Include="Volo.Abp.Identity.Pro.HttpApi.Client" Version="7.2.2" /> <PackageReference Include="Volo.Abp.Http.Client.IdentityModel.Web" Version="7.2.2" />

    [DependsOn(typeof(AbpHttpClientIdentityModelWebModule))]
    [DependsOn(typeof(AbpIdentityHttpApiClientModule))]
    public class ...HttpApiHostModule : AbpModule
    
  • User Avatar
    0
    abpnewtonvisionco created

    Hey, thanks for the answer.

    I added what you mentioned to our Chat Service, however I have some questions:

    1- When starting the websocket for the chat service we are having issue here:

    We enabled the websocket for Ocelot too as we were having an issue connecting to the websocket and this was not mention on the tutorial of the page.

    Is there something we need to specify or something for the web sockets on this module?

    2- Even though we added the module and the previous steps you mention, I don't see the contacts loading on the left side. Debugging it also fails when bringing the Users from the Administration mode, I created another use just to check if in any of the methods on the GetContactsAsync to get contacts/users work but they return object reference or a 0.

    _conversationRepository.GetListByUserIdAsync always returns 0,

    _chatUserLookupService.SearchAsync throws an error.

    "System.NullReferenceException HResult=0x80004003 Message=Object reference not set to an instance of an object. Source=Volo.Abp.IdentityModel StackTrace: at Volo.Abp.IdentityModel.IdentityModelAuthenticationService.<GetAccessTokenAsync>d__32.MoveNext() at Volo.Abp.IdentityModel.IdentityModelAuthenticationService.<GetAccessTokenOrNullAsync>d__31.MoveNext() at Volo.Abp.IdentityModel.IdentityModelAuthenticationService.<TryAuthenticateAsync>d__30.MoveNext() at Volo.Abp.Http.Client.IdentityModel.IdentityModelRemoteServiceHttpClientAuthenticator.<Authenticate>d__4.MoveNext() at Volo.Abp.Http.Client.IdentityModel.Web.HttpContextIdentityModelRemoteServiceHttpClientAuthenticator.<Authenticate>d__5.MoveNext() at Volo.Abp.Http.Client.ClientProxying.ClientProxyBase1.<RequestAsync>d__34.MoveNext() at Volo.Abp.Http.Client.ClientProxying.ClientProxyBase1.<RequestAsync>d__331.MoveNext() at Volo.Abp.Http.Client.ClientProxying.ClientProxyBase1.<RequestAsync>d__311.MoveNext() at Volo.Abp.Identity.IdentityUserLookupClientProxy.<SearchAsync>d__2.MoveNext() at Volo.Abp.Identity.HttpClientExternalUserLookupServiceProvider.<SearchAsync>d__6.MoveNext() at Volo.Abp.Users.UserLookupService2.<SearchAsync>d__17.MoveNext() at Volo.Chat.Users.ContactAppService.<GetContactsAsync>d__3.MoveNext() in C:\Juvenal\NVC\code\testChat\services\FGChat\modules\Volo.Chat\src\Volo.Chat.Application\Volo\Chat\Users\ContactAppService.cs:line 44

    This exception was originally thrown at this call stack: [External Code] Volo.Chat.Users.ContactAppService.GetContactsAsync(Volo.Chat.Users.GetContactsInput) in ContactAppService.cs"

    Is it possible for you guys to send me a working example of a chat service for a microservice solution? Just so I can compare and modify what ever I find as difference with my project.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    Could you share the project with me? I will check it. shiwei.liang@volosoft.com

  • User Avatar
    0
    abpnewtonvisionco created

    Hi Liang, I was able to fix the issue, it was related with the Ocelot configuration.

    I have another small quesiton here, I send a chat to another user but I don't see the icon changing to notify that he has unread messages, is this a known issue?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    It looks like a problem, we will check and fix it.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    You can try this:

    [ExposeServices(typeof(IConversationAppService))]
    public class MyConversationAppService : ConversationAppService
    {
        private readonly MyMessagingManager _myMessagingManager;
        private readonly IChatUserLookupService _chatUserLookupService;
        public MyConversationAppService(
            MessagingManager messagingManager,
            IChatUserLookupService chatUserLookupService,
            IConversationRepository conversationRepository,
            IRealTimeChatMessageSender realTimeChatMessageSender,
            IAuthorizationService authorizationService,
            MyMessagingManager myMessagingManager) : base(messagingManager, chatUserLookupService, conversationRepository, realTimeChatMessageSender, authorizationService)
        {
            _chatUserLookupService = chatUserLookupService;
            _myMessagingManager = myMessagingManager;
        }
    
        public override async Task<ChatConversationDto> GetConversationAsync(GetConversationInput input)
        {
    
            var targetUser = await _chatUserLookupService.FindByIdAsync(input.TargetUserId);
            if (targetUser == null)
            {
                throw new BusinessException("Volo.Chat:010003");
            }
    
            var chatConversation = new ChatConversationDto
            {
                TargetUserInfo = new ChatTargetUserInfo
                {
                    UserId = targetUser.Id,
                    Name = targetUser.Name,
                    Surname = targetUser.Surname,
                    Username = targetUser.UserName,
                },
                Messages = new List<ChatMessageDto>()
            };
    
            var messages = await _myMessagingManager.ReadMessagesAsync(targetUser.Id, input.SkipCount, input.MaxResultCount);
    
            chatConversation.Messages.AddRange(
                messages.Select(x => new ChatMessageDto
                {
                    Message = x.Message.Text,
                    MessageDate = x.Message.CreationTime,
                    ReadDate = x.Message.ReadTime ?? DateTime.MaxValue,
                    IsRead = x.Message.IsAllRead,
                    Side = x.UserMessage.Side
                })
            );
    
    
            return chatConversation;
        }
    }
    
    [ExposeServices(typeof(MessagingManager), typeof(MyMessagingManager))]
    public class MyMessagingManager : MessagingManager
    {
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IUserMessageRepository _userMessageRepository;
        private readonly IConversationRepository _conversationRepository;
        private readonly IMessageRepository _messageRepository;
    
        public MyMessagingManager(
            IMessageRepository messageRepository,
            IUserMessageRepository userMessageRepository,
            IChatUserLookupService chatUserLookupService,
            IConversationRepository conversationRepository,
            ICurrentUser currentUser,
            IUnitOfWorkManager unitOfWorkManager)
            : base(messageRepository, userMessageRepository, chatUserLookupService, conversationRepository, currentUser)
        {
            _messageRepository = messageRepository;
            _userMessageRepository = userMessageRepository;
            _conversationRepository = conversationRepository;
            _unitOfWorkManager = unitOfWorkManager;
        }
    
    
        public new async Task<List<MessageWithDetails>> ReadMessagesAsync(Guid targetUserId, int skipCount, int maxResultCount)
        {
            var messages = await _userMessageRepository.GetMessagesAsync(CurrentUser.GetId(), targetUserId, skipCount, maxResultCount);
    
            //TODO: Optimize
            var readMessages = new List<Message>();
            foreach (var message in messages.Where(m => !m.UserMessage.IsRead).ToArray())
            {
                message.UserMessage.MarkAsRead(Clock.Now);
                await _userMessageRepository.UpdateAsync(message.UserMessage);
    
                message.Message.MarkAsAllRead(Clock.Now);
                readMessages.Add(message.Message);
            }
    
            var conversationPair = await _conversationRepository.FindPairAsync(CurrentUser.GetId(), targetUserId);
            if (conversationPair != null)
            {
                conversationPair.SenderConversation.ResetUnreadMessageCount();
    
                await _conversationRepository.UpdateAsync(conversationPair.SenderConversation);
                await _conversationRepository.UpdateAsync(conversationPair.TargetConversation);
            }
    
            try
            {
                using (var uow = _unitOfWorkManager.Begin(requiresNew: true, isTransactional: _unitOfWorkManager.Current?.Options.IsTransactional ?? false))
                {
                    foreach (var message in readMessages)
                    {
                        await _messageRepository.UpdateAsync(message);
                    }
                    await uow.CompleteAsync();
                }
            }
            catch (AbpDbConcurrencyException e)
            {
                // The messages are change by another request. So, we can ignore this exception.
            }
    
            return messages;
        }
    }
    
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Sorry for the wrong place in my previous answer.

    We created an internal issue and it will fixed in the next patch version.

Made with ❤️ on ABP v9.1.0-preview. Updated on December 05, 2024, 12:19