简体   繁体   中英

how SignalR works in Web API

I'm working in SignalR chat project like this example

It works well however, I want to make chat hub.cs in a Web API project and call it from other client projects.

I have searched for solutions but haven't found any. How do I achieve this.

My chatHub

public class ChatHub : Hub
{
        dbcontext db = new dbcontext();
        ChatManager chatManager = new ChatManager();
    public static string ConnectionId = null;

    public void Send(string name, string message)
    {
        ConnectedUsers cu = chatManager.getCurrentUserRow(Context.ConnectionId);

        if (cu != null)
        {
            string L_ConnectionId = cu.Other_ConnectionId;

            Clients.Client(L_ConnectionId)
                .addNewMessageToPage(name, message);
        }
    }
    public override Task OnConnected()
    {
        Console.WriteLine("Connected user: " + Context.User.Identity.Name);
        ConnectionId = Context.ConnectionId;
        chatManager.AddAndRemoveUser(true, Context.ConnectionId); // to add user in connectedUser Table
        chatManager.OpenRandomChat(Context.ConnectionId);

        return base.OnConnected();
    }
    public override Task OnDisconnected(bool stopCalled)
    {
        chatManager.RemoveLeftUser(Context.ConnectionId);
        chatManager.AddAndRemoveUser(false, Context.ConnectionId);
        return base.OnDisconnected(stopCalled);
    }
    public override Task OnReconnected()
    {
        Console.WriteLine("ReConnected user: " + Context.User.Identity.Name);
        return base.OnReconnected();
    }
    public void NewConnection()
    {
        int retVal = -1;
        chatManager.RemoveLeftUser(Context.ConnectionId); // to remove left user from 2 users
        chatManager.OpenRandomChat(Context.ConnectionId); // to chosse random user for me 

        // to get me and my if i have partner ..
        ConnectedUsers cu = chatManager.getCurrentUserRow(Context.ConnectionId);

        if (cu != null)
        {
            retVal = 0;
            //string groupId = cu.ConnectionId + cu.Other_ConnectionId;
            //string R_ConnectionId = cu.ConnectionId;
            string L_ConnectionId = cu.Other_ConnectionId;
        }
        Clients.Client(Context.ConnectionId)
              .sendGroupData(retVal);
    }

    public void SendQuestion(string question)
    {
        ConnectedUsers cu = chatManager.getCurrentUserRow(Context.ConnectionId);
        if (cu != null)
        {
            string L_ConnectionId = cu.Other_ConnectionId;
            Clients.Client(L_ConnectionId)
                .sendQuestion(question);
        }
    }
    public void AnswerQuestion(string answer)
    {
        ConnectedUsers cu = chatManager.getCurrentUserRow(Context.ConnectionId);
        if (cu != null)
        {
            string L_ConnectionId = cu.Other_ConnectionId;

            Clients.Client(L_ConnectionId)
                .answerQuestion(answer);
        }
    }
}

I created a separate class library that I include and use in any of my other projects, works great and gives access to a single reusable Hub. I use mine for order notifications.

 namespace MyProjects.SignalR.Hubs
{
    public class OrdersHub : Hub
    {


        public void OrderDeleted(int manufacturerId, int orderId)
        {
            Clients.Group(OrdersGroup(manufacturerId)).BroadcastOrder(orderId);
        }


        public Task JoinOrders(int manufacturerId)
        {
            return Groups.Add(Context.ConnectionId, OrdersGroup(manufacturerId));
        }

        private string OrdersGroup(int manufacturerId)
        {
            return "orders" + manufacturerId;
        }

    }
}

Then in any of my other projects that use this I simply call:

var ordersHubContext = GlobalHost.ConnectionManager.GetHubContext<OrdersHub>();
ordersHubContext.Clients.All.OrderDeleted(order.ManufacturerID, order.OrderID);

ChatManager chatManager = new ChatManager();

You can´t do that within a Hub. Hubs instances are not persistent, they are re-created on every single request, and so does your ChatManager .

To make that work, convert your ChatManager to a Lazy Singleton. The aim of using Lazy in this case is to make it thread safe (pretty neat for SignalR):

public sealed class ChatManager
{
    private static readonly Lazy< ChatManager > lazy =
        new Lazy< ChatManager >(() => new ChatManager());

    public static ChatManager Instance { get { return lazy.Value; } }

    private ChatManager()
    {
    }

    // TODO add your methods here
}

Then, from your hub:

ChatManager.Instance.AddAndRemoveUser(true, Context.ConnectionId);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM