Добавление функций в реальном времени в мой чат приложения Xamarin вызывает System.InvalidOperationException

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

Я решил использовать SignalR, как было предложено в комментариях:

-Добавил его в мой CongifureService, как показано:

public void ConfigureServices(IServiceCollection services)
    {           
        services.AddDbContext<HostelContext>(opt =>
           opt.UseSqlServer(Configuration.GetConnectionString("HostelContext")));

        services.AddCors();
        services.AddControllers();

        services.AddAuthentication("BasicAuthentication")
            .AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);

        services.AddScoped<IUsersService, UsersService>();
        services.AddScoped<IConversationsService, ConversationsService>();
        services.AddScoped<IMessagesService, MessagesService>();

        // Register the Swagger generator, defining 1 or more Swagger documents
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "HostelApi", Version = "v1" });             
        });

        services.AddSignalR();
    }

-Добавлена ​​конечная точка для настройки, как показано на рисунке:

app.UseEndpoints(endpoints =>
        {                
            endpoints.MapControllers();
            endpoints.MapHub<ChatHub>("/chatHub");
        });

-Добавлен класс в мой проект API в новой папке под названием Hub.

-Это класс концентратора:

//[Authorize]    
public class ChatHub : Hub
{                
    public async Task SendMessage(Message message)
    {
        //await Clients.All.SendAsync("ReceiveMessage", message);
        await Clients.All.SendAsync("ReceiveMessage" + message.ConversationId, message);
        //await Clients.Users(destinationUserIdList).SendAsync("ReceiveMessage" + message.ConversationId, message);
    }
}

В моем приложении Xamarin:

-Добавлен сервис-концентратор:

-Это класс обслуживания концентратора:

class HubService : IHubService
{
    public HubConnection HubConnection { get; }
    public HubService()
    {
        HubConnection = new HubConnectionBuilder()
            .WithUrl($"https://10.0.2.2:5001/chatHub")
            .Build();
    }

    public async Task Connect()
    {
        await HubConnection.StartAsync().ConfigureAwait(false);
    }

    public async Task Disconnect()
    {
        await HubConnection.StopAsync().ConfigureAwait(false);
    }

    public async Task SendMessage(Message message)
    {            
        await HubConnection.InvokeAsync("SendMessage", message).ConfigureAwait(false);
    }
}

-Подключиться к концентратору, когда приложение запускается после входа в систему:

public MainPage()
    {
        InitializeComponent();                   

        MasterBehavior = MasterBehavior.Popover;

        //should be home page
        MenuPages.Add((int)MenuItemType.Home, (NavigationPage)Detail);

        HubService.Connect().ConfigureAwait(true);            
    }

-Закрыть соединение при выходе

-При отправке сообщения я вызываю метод SendMessage:

await HubService.SendMessage(message).ConfigureAwait(true);
            OutGoingText = string.Empty;
            Messages.Add(message);

Проблема сейчас в том, когда я отправляю сообщение и получаю:

public async Task SendMessage(Message message)
    {            
        await HubConnection.InvokeAsync("SendMessage", message).ConfigureAwait(false);
    }

бросает это:

System.InvalidOperationException: 'The 'InvokeCoreAsync' method cannot be called if the connection is not active'

Уже пробовал с HubService.Connect().Wait(), но приложение остается в цикле

Кто-нибудь может мне с этим помочь?? @Ник Ковальский...

С уважением


person MarchalPT    schedule 13.03.2020    source источник
comment
Вы уверены, что клиент устанавливает соединение до того, как вы вызовете Send?   -  person Jason    schedule 13.03.2020
comment
Когда я вызываю соединение, если я использую ожидание, приложение зависает, и мне приходится его перезапускать. Я предполагаю, что это означает, что соединение не происходит, и я не знаю, почему: S Конечная точка API для концентратора существует, если я использую URL-адрес в браузере, я получаю требуемый идентификатор соединения, поэтому это означает, что проблема не в API. . Почему не происходит подключение??? понятия не имею :С   -  person MarchalPT    schedule 13.03.2020
comment
не выполняйте сетевые операции в потоке пользовательского интерфейса. Вы тестировали URL-адрес концентратора в браузере устройства/эмулятора, а не в браузере настольного компьютера? Вы используете самоподписанный сертификат?   -  person Jason    schedule 13.03.2020
comment
Я только что проверил это и предупреждает меня, что соединение не является безопасным, я все равно продолжаю, и появляется требуемый идентификатор соединения, как в браузере моего ПК. У меня есть другие конечные точки API, к которым я могу подключиться с помощью этого приложения Xamarin, это просто концентратор, к которому я не могу подключиться. Что касается сертификата, я добавил его, когда создавал API. Не знаю, какой сертификат был, я полагаю, что он был самоподписанным, потому что мне нужно, чтобы мой браузер мог получить доступ к API.   -  person MarchalPT    schedule 13.03.2020
comment
Я понятия не имею, будет ли SignalR работать с самозаверяющим сертификатом.   -  person Jason    schedule 13.03.2020
comment
Спасибо @Jason. Я нашел этот пост: stackoverflow.com/questions/18150758/ Я думаю, это может работать, но я не очень хорошо это понимаю.   -  person MarchalPT    schedule 14.03.2020


Ответы (1)


Я узнаю проблему!

Проблема заключалась в вызове «HubService.Connect().ConfigureAwait(true);» который является асинхронным методом внутри конструктора, поэтому у него не может быть ожидания.

public MainPage()
{
    InitializeComponent();                   

    MasterBehavior = MasterBehavior.Popover;

    //should be home page
    MenuPages.Add((int)MenuItemType.Home, (NavigationPage)Detail);

    HubService.Connect().ConfigureAwait(true);            
}

Решено перенести вызов "HubService.Connect().ConfigureAwait(true);" в App.xaml.cs и поместите его в метод OnStart():

protected override async void OnStart()
    {
        await HubService.Connect().ConfigureAwait(true);
    }

Спасибо всем, ребята!

person MarchalPT    schedule 22.03.2020