Search code examples
c#asp.net-coresignalr-hubaspnetboilerplateasp.net-core-signalr

Class MessageAppService cannot have multiple base classes 'Hub' and 'AsyncCrudAppService'


I'm using ASP.NET Boilerplate with .NET Core 3.1.

I'm trying to save SignalR chat history to the database. The problem is when I want to create a subclass of AsyncCrudAppService and Hub, an error occurred with below text:

Class MessageAppService cannot have multiple base classes 'Hub' and 'AsyncCrudAppService'

Here is my code:

namespace MyProject.ChatAppService
{
    public class MessageAppService : Hub, AsyncCrudAppService<Message, MessageDto, int, PagedAndSortedResultRequestDto, CreateMessageDto, UpdateMessageDto, ReadMessageDto>
    {
        private readonly IRepository<Message> _repository;

        private readonly IDbContextProvider<MyProjectDbContext> _dbContextProvider;
        private MyProjectPanelDbContext db => _dbContextProvider.GetDbContext();

        public MessageAppService(
            IDbContextProvider<MyProjectDbContext> dbContextProvider,
            IRepository<Message> repository)
            : base(repository)
        {
            _repository = repository;
            _dbContextProvider = dbContextProvider;
        }

        public  List<Dictionary<long, Tuple<string, string>>> InboxChat()
        {
            // The result will be List<userid, Tuple<username, latest message>>();
            List<Dictionary<long, Tuple<string, string>>> result = new List<Dictionary<long, Tuple<string, string>>>();

            List<User> listOfAllUsers = db.Set<User>().ToList();

            listOfAllUsers.ForEach((user) =>
            {
                try
                {
                    var dict = new Dictionary<long, Tuple<string, string>>();

                    var latestMessage = (from msg in db.Set<Message>() select msg)
                        .Where(msg => msg.CreatorUserId == user.Id && msg.receiverID == AbpSession.UserId)
                        .OrderByDescending(x => x.CreationTime)
                        .FirstOrDefault()
                        .Text.ToString();

                    dict.Add(user.Id, Tuple.Create(user.UserName, latestMessage));
                    result.Add(dict);
                }
                catch (Exception ex)
                {
                    new UserFriendlyException(ex.Message.ToString());
                }
            });

            return result;
        }

        public List<Message> getMessageHistory(int senderId)
        {
            return _repository.GetAll()
                .Where(x => x.CreatorUserId == senderId && x.receiverID == AbpSession.UserId )
                .ToList();
        }
    }
}

How could I avoid this error?

Update

Here is MyChatHub code that I wanted to combine with the AsyncCrudAppService subclass to become one class (I don't know if this way is correct but this was what came to my mind!).

public class MyChatHub : Hub, ITransientDependency
{
    public IAbpSession AbpSession { get; set; }

    public ILogger Logger { get; set; }

    public MyChatHub()
    {
        AbpSession = NullAbpSession.Instance;
        Logger = NullLogger.Instance;
    }

    public async Task SendMessage(string message)
    {
        await Clients.All.SendAsync("getMessage", string.Format("User {0}: {1}", AbpSession.UserId, "the message that has been sent from client is "+message));
    }

    public async Task ReceiveMessage(string msg, long userId)
    {
        if (this.Clients != null)
        {
            await Clients.User(userId.ToString())
                .SendAsync("ReceiveMessage", msg, "From Server by userID ", Context.ConnectionId, Clock.Now);
        }
        else
        {
            throw new UserFriendlyException("something wrong");
        }
    }

    public override async Task OnConnectedAsync()
    {
        await base.OnConnectedAsync();
        Logger.Debug("A client connected to MyChatHub: " + Context.ConnectionId);
    }

    public override async Task OnDisconnectedAsync(Exception exception)
    {
        await base.OnDisconnectedAsync(exception);
        Logger.Debug("A client disconnected from MyChatHub: " + Context.ConnectionId);
    }
}    

Solution

  • Your AsyncCrudAppService subclass can't and shouldn't inherit Hub.

    Instead, inject and use IHubContext<MyChatHub> similar to ABP's SignalRRealTimeNotifier.

    public MessageAppService(
        IHubContext<MyChatHub> hubContext,
        IDbContextProvider<MyProjectDbContext> dbContextProvider,
        IRepository<Message> repository)
        : base(repository)
    {
        _dbContextProvider = dbContextProvider;
        _hubContext = hubContext;
        _repository = repository;
    }
    

    To send a message to all clients, call _hubContext.Clients.All.SendAsync(...).

    References: