Blazor Server SignalR聊天可以在本地运行,而不能在Azure上运行

s4n0splo  于 2023-01-21  发布在  其他
关注(0)|答案(2)|浏览(107)

我有一个工作的Blazor服务器应用程序,其中的聊天组件在本地正确运行,使用信号R集线器连接。
部署到Azure时,我收到错误“收到无效的协商响应"。---〉System.Text.Json.JsonReaderException:“0x 1F”是无效的值开头。
下面是一张类似的关联罚单,但从未得到回复:Blazor Server SignalR hub fails on StartAsync due to Azure ADB2C
目标:为Blazor服务器应用程序创建一个私人聊天功能。我不能使用单例服务,因为所有用户不能共享同一个服务示例。
我还没有找到blazor server中用户/用户组之间有消息传递功能的示例。
由于我使用的是带有OIDC默认身份验证方案的Azure B2C身份验证,因此我必须手动传递cookie和头。
就像我提到的,这个示例在localhost上运行得很好,当我打开两个浏览器(一个是匿名的)时,我可以在登录的用户之间发送消息。但是,当我发布到Azure应用服务时,我无法连接到集线器。
代码:

private HubConnection _hubConnection;
private User user;
ObservableCollection<Message> messages = new ObservableCollection<Message>();
SfTextBox MessageBox;
SfTextBox SendTo;

public class Message
{
    public string Id { get; set; }
    public string UserName { get; set; }
    public string MessageText { get; set; }
    public string Chat { get; set; }
}

protected override async Task OnInitializedAsync()
{
    var state = await authenticationStateProvider.GetAuthenticationStateAsync();
    user = state.ToUser();
    _hubConnection = new HubConnectionBuilder()
        .WithUrl(navigationManager.ToAbsoluteUri("/chatHub"), options =>
        {
            options.UseDefaultCredentials = true;
            var httpContext = HttpContextAccessor.HttpContext;
            var cookieCount = httpContext.Request.Cookies.Count();
            var cookieContainer = new System.Net.CookieContainer(cookieCount);
            foreach (var cookie in httpContext.Request.Cookies)
                cookieContainer.Add(new System.Net.Cookie(
                cookie.Key,
                WebUtility.UrlEncode(cookie.Value),
                path: httpContext.Request.Path,
                domain: httpContext.Request.Host.Host));
            options.Cookies = cookieContainer;

            NameValueHeaderValue headers = null;
            foreach (var header in httpContext.Request.Headers)
            {
                if (header.Key != ":method")
                    options.Headers.Add(header.Key, header.Value);
            }
            options.HttpMessageHandlerFactory = (input) =>
            {
                var clientHandler = new HttpClientHandler
                    {
                        PreAuthenticate = true,
                        CookieContainer = cookieContainer,
                        UseCookies = true,
                        UseDefaultCredentials = true,
                    };

                return clientHandler;
            };
        })
 .WithAutomaticReconnect()
 .Build();

    _hubConnection.On<string, string, string, string>("ReceiveMessage", (userName, from, to, message) =>
    {
        if (user.Email == to || user.Id == from)
        {
            messages.Add(new Message()
                {
                    Id = Guid.NewGuid().ToString(),
                    MessageText = message,
                    Chat = user.Id == from ? "sender" : "receive",
                    UserName = user.Id == from ? "You" : userName
                });
            StateHasChanged();
        }
    });

    await _hubConnection.StartAsync();
}

public async void Send()
{
    if (MessageBox.Value != "" && SendTo.Value != "")
    {
        var userName = user.DisplayName;
        var to = SendTo.Value;
        var message = MessageBox.Value;
        var from = user.Id;
        _hubConnection.SendAsync("SendMessage", userName, from, to, message);
    }
}

public bool IsConnected => _hubConnection.State == HubConnectionState.Connected;

}

gmxoilav

gmxoilav1#

问题是Azure平台上的身份验证。由于您使用手动提供Cookie,因此它在本地运行良好,而在Azure平台上,我们需要提供身份验证。
点击以下链接获取支持。
https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-invalid-json?pivots=dotnet-6-0
https://learn.microsoft.com/en-us/azure/azure-signalr/signalr-tutorial-build-blazor-server-chat-app

j8yoct9x

j8yoct9x2#

    • HttpContextAccessor.HttpContext**是问题所在。它在本地(IIS Express)上工作,但在应用程序部署到Azure(或IIS)时不工作。

我在这里发布了一个解决方案:Solution: Custom SignalR Endpoints (Hubs) in a Blazor Server Application using Azure B2C When Deployed to Azure
基本上:
此时抓取所有Cookie,并将其放入Cookie集合中,以便将其传递给app. razor控件。

<body>
@{
    var CookieCollection = HttpContext.Request.Cookies;
    Dictionary<string, string> Cookies = new Dictionary<string, string>();
    foreach (var cookie in CookieCollection)
    {
        Cookies.Add(cookie.Key, cookie.Value);
    }        
}
<component type="typeof(App)" render-mode="ServerPrerendered" param-Cookies="Cookies" />

将它们设置为将传递给所有其他Blazor控件的CascadingValue。检索Cookie集合作为CascadingParameter,并在创建SignalR客户端时使用这些Cookie手动设置Header和Cookie。

hubConnection = new HubConnectionBuilder()
             .WithUrl(Navigation.ToAbsoluteUri("/chathub"), options =>
             {
                 options.UseDefaultCredentials = true;
                 var cookieCount = Cookies.Count();
                 var cookieContainer = new CookieContainer(cookieCount);
                 foreach (var cookie in Cookies)
                     cookieContainer.Add(new Cookie(
                         cookie.Key,
                         WebUtility.UrlEncode(cookie.Value),
                         path: "/",
                         domain: Navigation.ToAbsoluteUri("/").Host));
                 options.Cookies = cookieContainer;

                 foreach (var header in Cookies)
                     options.Headers.Add(header.Key, header.Value);

                 options.HttpMessageHandlerFactory = (input) =>
                 {
                     var clientHandler = new HttpClientHandler
                         {
                             PreAuthenticate = true,
                             CookieContainer = cookieContainer,
                             UseCookies = true,
                             UseDefaultCredentials = true,
                         };
                     return clientHandler;
                 };
             })
             .WithAutomaticReconnect()
             .Build();

            hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
            {
                var encodedMsg = $"{user}: {message}";
                messages.Add(encodedMsg);
                InvokeAsync(StateHasChanged);
            });

            await hubConnection.StartAsync();

相关问题