Ошибка подключения WebSocket в ASP.NET Core SignalR с Blazor

Вопрос или проблема

Я реализую систему уведомлений в своем API на ASP.NET Core с использованием SignalR и клиента Blazor. Я настроил NotificationHub и пользовательский провайдер идентификаторов, чтобы управлять подключениями пользователей. Однако каждый раз, когда я запускаю свое приложение, я сталкиваюсь с следующей ошибкой:
Не удалось установить соединение WebSocket с 'wss://localhost:63225/notificationHub?id=LDfet**&access_token=ey**':
Фрагменты кода:
NotificationHub:

[Authorize]
public class NotificationHub : Hub
{
    public override Task OnConnectedAsync()
    {
        Debug.WriteLine(Context.UserIdentifier);
        return base.OnConnectedAsync();
    }
}

CustomUserIdProvider:

public class CustomUserIdProvider : IUserIdProvider
{
    public string? GetUserId(HubConnectionContext connection)
    {
        return connection.User?.Identity?.Name;
    }
}

Добавление запроса с уведомлением:

    public async Task<int> AddEvolutionDemand(EvolutionDto evolutionToAddDto)
    {
        var EvolutionDemand = new Evolution();
        try
        {
            EvolutionDemand = new()
            {
                Service_ID = evolutionToAddDto.Service_ID,
                User_ID = evolutionToAddDto.User_ID,
                User_Name = evolutionToAddDto.User_Name,
                Doc_ID = evolutionToAddDto.Doc_ID,
                Demande_Creation_Date = evolutionToAddDto.Demande_Creation_Date,
                Demand_Type = evolutionToAddDto.Demand_Type,
                Demand_Title = evolutionToAddDto.Demand_Title,
                Demande_Comment = evolutionToAddDto.Demande_Comment,
                STATUS = evolutionToAddDto.STATUS,
                Demand_Assigned_ID = evolutionToAddDto.Demand_Assigned_ID,
                Demand_update_date = evolutionToAddDto.Demand_update_date,
                Demand_Update_Comment = evolutionToAddDto.Demand_Update_Comment,
            };
            await _kmDbContext.Evolution.AddAsync(EvolutionDemand);
            await _kmDbContext.SaveChangesAsync();
            var UserToNotify = await UserRepository.GetUser(evolutionToAddDto.Demand_Assigned_ID);
            await HubConntextion.Clients.User(UserToNotify.User_Login).SendAsync("notification", $"{DateTime.Now}");
        }
        catch (Exception ex)
        {
            _logger.Error(ex, ErrorMessage, ex.Message);
        }
        return EvolutionDemand.Demand_ID;
    }

Клиент Blazor:

@code {
    private HubConnection? hubConnection;
    public int pendingDemandCount { get; set; } = 0;
    List<string> notifications = [];
    [Inject] IAccessTokenProvider AccessTokenProvider { get; set; } = default!;

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        var authState = await AuthenticationStateTask;

        if (authState.User.Identity != null && authState.User.Identity.IsAuthenticated)
        {
            await connectToNotificationHub();
            await RefreshPendingDemands();
        }
    }

    public async Task connectToNotificationHub()
    {
        try
        {
            if (hubConnection is not null)
                return;
            var notificationUrl = "notificationHub";
            hubConnection = new HubConnectionBuilder()
                                .WithUrl($"https://localhost:63225/{notificationUrl}", options =>
                                {
                                    options.AccessTokenProvider = () => GetAccessTokenAsync();
                                })
                                .Build();

            hubConnection.On<string>("notification", async (message) =>
            {
                notifications.Add(message);
                await RefreshPendingDemands();
                await InvokeAsync(StateHasChanged);
            });

            await hubConnection.StartAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Ошибка при подключении к SignalR хабу: {ex.Message}");
            Console.WriteLine($"Стек вызовов: {ex.StackTrace}");
        }
    }

    private async Task<string?> GetAccessTokenAsync()
    {
        var tokenResult = await AccessTokenProvider.RequestAccessToken();
        if (tokenResult != null && tokenResult.TryGetToken(out AccessToken accessToken))
        {
            return accessToken.Value;
        }
        return null;
    }

    private async Task RefreshPendingDemands()
    {
        var pendingDemands = await DocumentService.GetPendingDemandsForUser();
        pendingDemandCount = pendingDemands?.Count ?? 0;
    }

    public async ValueTask DisposeAsync()
    {
        if (hubConnection is not null)
        {
            await hubConnection.DisposeAsync();
            hubConnection = null;
        }
    }
}

Что может вызывать сбой соединения WebSocket и как я могу устранить эту проблему? Я проверил, что access_token сгенерирован правильно и что пользователь аутентифицирован. Буду признателен за любые советы по решению этой проблемы!

Я реализовал метод OnConnectedAsync в NotificationHub, чтобы записать идентификатор пользователя и проверить, правильно ли устанавливается соединение. Я убедился, что токен доступа сгенерирован корректно, используя IAccessTokenProvider в своем клиенте Blazor. Я фиксирую все проблемы с процессом получения токена.

Ответ или решение

Ошибка подключения WebSocket в ASP.NET Core SignalR с Blazor: Подробный анализ и рекомендации

Введение

При использовании SignalR для реализации системы уведомлений в приложении ASP.NET Core на основе Blazor, вы можете столкнуться с ошибкой подключения WebSocket. В данном ответе мы рассмотрим возможные причины возникновения данной ошибки и предложим методы её диагностики и устранения.

Описание Проблемы

Ваша система сталкивается с ошибкой при попытке установить соединение WebSocket с хабом уведомлений (NotificationHub). Ошибка, которая генерируется, может выглядеть следующим образом:

WebSocket connection to 'wss://localhost:63225/notificationHub?id=LDfet**&access_token=ey**' failed:

Возможные Причины Ошибки

  1. SSL-сертификат:

    • Если вы разрабатываете локально и используете HTTPS (как в вашем случае), возможно, SSL-сертификат не распознается на вашем устройстве. Убедитесь, что ваш сертификат действителен и доверен.
  2. Несоответствие настройкам CORS:

    • Настройки CORS могут блокировать запросы к вашему API. Убедитесь, что у вас правильно настроены CORS, позволяющие запросы от клиента Blazor.
  3. Ошибки аутентификации:

    • Ваша ошибка может быть связана с неправильной аутентификацией пользователя. Несмотря на то что вы упомянули, что токен доступа корректно сгенерирован и пользователь аутентифицирован, стоит еще раз проверить, что токен действительно соответствует ожидаемому формату и действителен на момент запроса.
  4. Приватное подключение к Hub:

    • Убедитесь, что в NotificationHub имеется правильный механизм аутентификации и авторизации. Ваш хаб имеет атрибут [Authorize], что означает, что все пользователи должны быть авторизованы для подключения.
  5. Настройки хаба:

    • Проверьте, что URL для подключения к хабу сформирован правильно и что метод подключения к HubConnectionBuilder с указанным URL, настроенным относительно вашего окружения, действительно доступен.

Шаги по Диагностике и Устранению Ошибки

  1. Проверка Соединения:

    • Попробуйте подключиться к хабу из другого клиента, например, отладочного инструмента или Postman, чтобы определить, доступен ли хаб.
  2. Логи:

    • В вашем методе OnConnectedAsync добавьте дополнительные логи, например, записывайте состояние токена и идентификатора пользователя для дальнейшего анализа.
  3. Проверка на стороне клиента:

    • Убедитесь, что метод GetAccessTokenAsync возвращает действительный токен. Это можно сделать, добавив логи перед тем, как возвращать токен, чтобы убедиться, что он не является null.
  4. Проверка настройки CORS:

    • Убедитесь, что в Startup.cs добавлены настройки CORS, разрешающие хост Blazor приложения. Пример:
      services.AddCors(options =>
      {
      options.AddPolicy("AllowSpecificOrigin", builder =>
      {
         builder.WithOrigins("https://localhost:5001")
                .AllowAnyHeader()
                .AllowAnyMethod()
                .AllowCredentials();
      });
      });
  5. Fallback на другие транспортные протоколы:

    • Если WebSocket продолжает выходить из строя, попробуйте использовать другие транспорты (Long Polling или Server-Sent Events) для проверки, работает ли всё в целом. Это можно сделать, добавив .WithUrl() с параметрами .Transport(TransportType.LongPolling).

Заключение

Ошибки соединения с WebSocket в ASP.NET Core SignalR могут быть вызваны рядом факторов, включая неправильные настройки безопасности или аутентификации, проблемы с CORS и конфликты в настройках хаба. С помощью предложенных шагов по диагностике вы сможете выявить источники проблемы и устранить её, обеспечив стабильную работу вашей системы уведомлений.

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

Оцените материал
Добавить комментарий

Капча загружается...