Отправьте сообщение в центр SignalR с любой активности Xamarin (Visual Studio 2017) для Android - PullRequest
2 голосов
/ 21 апреля 2019

Мне удалось создать и получить сообщения от концентратора SignalR со страницы html, aspx и клиента Xamarin - приложения, которое мне действительно нужно для использования Microsoft.AspNet.SignalR.Client v2.4.1 с использованием Xamarin в Visual Studio 2017. Как только мое приложение Xamarin аутентифицирует пользователя, я запускаю соединение с концентратором, затем подключаю событие для получения сообщений. Все это прекрасно работает, и я могу получать сообщения в приложении для Android независимо от того, какое действие является текущим, благодаря событию, которое подключено. Теперь, когда у меня есть эта работа, я хочу иметь возможность отправлять сообщения от клиента на концентратор без создания другого соединения с концентратором. Я посмотрел на статические классы, но не могу заставить это работать. Мой код:

Это код, который выполняется после аутентификации пользователя:

// Start SignalR connection
Client client = new Client(MyUser.Firstname + " " + MyUser.Lastname, MyUser.Username);

await client.Connect();

// Wire up the message received event
client.OnMessageReceived += (sender2, message) => RunOnUiThread(() => showMessage(message));

Отсюда пользователь может переходить от просмотра к просмотру и получать сообщения от концентратора через событие и метод showMessage. Это все работает без нареканий.

Код моего клиента: Этот код был скопирован из рабочего примера переполнения стека, я изменил его в соответствии с моими требованиями.

namespace ChatClient.Shared
{
    class Client
    {
        private readonly string _platform;
        private readonly HubConnection _connection;
        private readonly IHubProxy _proxy;

        public event EventHandler<string> OnMessageReceived;

        public Client(string platform, string username)
        {
            string _username = "username=" + username;
            _platform = platform;
            _connection = new HubConnection("https://Example.com/SignalRhub", _username);
            _proxy = _connection.CreateHubProxy("chathub");
        }

        public async Task Connect()
        {

            await _connection.Start();                 _proxy.On("broadcastMessage", (string platform, string message) =>
            {
                if (OnMessageReceived != null)
                    OnMessageReceived(this, string.Format("{0}: {1}", platform, message));
            });

            Send("Connected");
        }

        public async Task<List<string>> ConnectedUsers()
        {

            List<string> Users = await _proxy.Invoke<List<string>>("getConnectedUsers");

            return Users;
        }

        public Task Send(string message)
        {
            return _proxy.Invoke("Send", _platform, message);
        }
    }
}

Теперь мне нужно отправить сообщение на концентратор, используя соединение, созданное сразу после входа в систему, для распространения среди всех подключенных пользователей. Я не могу понять, как это сделать, я пытался использовать статический класс и пытался использовать методы, которые я нашел в Интернете, но, похоже, ничего не работает.

Код моего концентратора:

public class ChatHub : Hub
{

    private static readonly List<User> Users = new List<User>();

    public override Task OnConnected()
    {

        string userName = Context.QueryString["username"];
        string firstname = Context.QueryString["firstname"];
        string lastname = Context.QueryString["lastname"];
        string connectionId = this.Context.ConnectionId;

        var user = new User();
        user.Name = userName;
        user.ConnectionIds = connectionId;


        try
        {
            Users.Add(user);
        }
        catch (Exception ex)
        {
            var msg = ex.Message;
        }

        // send list of connected users to client as a test
        Send("Welcome " + userName, "Connected users are:");

        foreach (var display in Users)
        {
            Send("",display.Name.ToString());

        }

        // test sending to a specific user
        SendOne(connectionId, userName, "This is to a specific user.");

        return base.OnConnected();
    }

    public override Task OnDisconnected(bool stopped)
    {

        string userName = Context.User.Identity.Name;
        string connectionId = Context.ConnectionId;

        var item = Users.Find(x => x.ConnectionIds == connectionId);

        Send(item.Name , " disconnected.");

        Users.Remove(item);


        return base.OnDisconnected(true);
    }

    public void SendOne(string connectionId, string userName, string message)
    {

        Clients.Client(connectionId).broadcastMessage(userName, message);

    }

    public void Send(string name, string message)
    {
        // Call the broadcastMessage method to update clients.
        Clients.All.broadcastMessage(name, message);
    }

    public List<string> getConnectedUsers()
    {
        List<string> UserNames = new List<string>();

        foreach (var ConnectedUser in Users)
        {
            UserNames.Add(ConnectedUser.Name );
        }
       return UserNames;
    }
}

Есть много других вещей, которые я буду делать в хабе, но сейчас мне нужно, чтобы клиент отправлял сообщения без создания другого соединения

Есть ли способ получить доступ к соединению, созданному после аутентификации пользователя в других представлениях / действиях?

* Обновление *

Я изменил свой код в соответствии с ответом Лео Чжу ниже, однако я получаю сообщение об ошибке при попытке создать экземпляр класса в строке:

Client client = new Client.GetInstance(MyUser.Firstname + " " + MyUser.Lastname, MyUser.Username);

GetInstance does not exist когда это действительно так. Понятия не имею, почему он не "найден".

* Обновление *

Удалено ключевое слово new из строки:

Client client = new Client.GetInstance(MyUser.Firstname + " " + MyUser.Lastname, MyUser.Username);

Теперь оно гласит:

Client client = Client.GetInstance(MyUser.Firstname + " " + MyUser.Lastname, MyUser.Username);

Работает как шарм.

1 Ответ

0 голосов
/ 22 апреля 2019

Или вы можете попробовать шаблон синглтона, например (просто для того, чтобы предоставить идеи, вам нужно кодировать для собственных нужд):

public sealed class Client
  {
    // A private constructor to restrict the object creation from outside
    private Client()
     {
      ...
     }
    // A private static instance of the same class
    private static Client instance = null;
    public static Client GetInstance()
      {
       // create the instance only if the instance is null
       if (instance == null)
         {
           instance = new Client();
         }
       // Otherwise return the already existing instance
      return instance;
      }

  }

тогда вы можете позвонить по Client.GetInstance();

...