You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Azure SignalR Service实现控制台应用日志传输失败排查

问题描述

开发一个通过Azure SignalR Service在控制台应用间传递日志的项目,包含发送端控制台应用、接收端控制台应用和连接SignalR的Azure Function。发送端已成功连接SignalR,但接收端无法接收日志,Azure SignalR门户显示消息数和出站流量均为0,调试时连接状态显示“已连接”。

相关代码

发送端控制台应用

class Program
{
    static async Task Main(string[] args)
    {
        var connection = new HubConnectionBuilder()
            .WithUrl("<Functionapp Url>")
            .Build();

        await connection.StartAsync();

        Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .CreateLogger();

        var sender = new LogSender(connection);
        string logMessage = $"Log from Sender at {DateTime.Now}";

        while (true)
        {
            sender.SendLog(logMessage);
        }
    }
}

class LogSender
{
    private readonly HubConnection _connection;

    public LogSender(HubConnection connection)
    {
        _connection = connection;
    }

    public async void SendLog(string message)
    {
        Log.Information(message);
        await _connection.InvokeAsync("SendLog", message);
    }
}

接收端控制台应用

class Program
{
    static async Task Main(string[] args)
    {
        var connection = new HubConnectionBuilder()
            .WithUrl("<FunctionUrl>")
            .Build();

        connection.On<string>("ReceiveLog", log =>
        {
            Console.WriteLine($"Received log: {log}");
        });

        connection.Closed += async (exception) =>
        {
            Console.WriteLine($"Connection closed: {exception?.Message}");       
        };

        try
        {
            await connection.StartAsync();
            Console.WriteLine("Connected to SignalR hub.");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error connecting to SignalR hub: {ex.Message}");            
        }

        Console.WriteLine("Listening for logs. Press any key to exit.");
        Console.ReadKey();
    }
}

Azure Function

public static class Function1
{
    [FunctionName("negotiate")]
    public static SignalRConnectionInfo Negotiate(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
        [SignalRConnectionInfo(HubName = "loghub")] SignalRConnectionInfo connectionInfo)
    {
        return connectionInfo;
    }
}

public class loghub : ServerlessHub
{
    public async Task SendLog(string message)
    {
        await Clients.All.SendAsync("ReceiveLog", message);
    }
}

发送端项目文件

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.10" />
    <PackageReference Include="Microsoft.Azure.SignalR" Version="1.25.2" />
    <PackageReference Include="Serilog" Version="3.1.1" />
    <PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
    <PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
  </ItemGroup>

</Project>

接收端项目文件

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.10" />
    <PackageReference Include="Microsoft.Azure.SignalR" Version="1.25.2" />
  </ItemGroup>

</Project>

Azure Function项目文件

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <UserSecretsId>88e61c2f-e8c0-47d9-a0ce-c401e2e6296a</UserSecretsId>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.SignalRService" Version="1.10.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.4.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

问题排查与解决方案

1. 修复异步方法调用问题

发送端SendLog方法使用async void,会导致异常无法捕获、异步操作无法等待,进而引发消息发送失败。修改为async Task并在调用时添加等待:

// LogSender类修改
public async Task SendLog(string message)
{
    Log.Information(message);
    try
    {
        await _connection.InvokeAsync("SendLog", message);
        Log.Information("消息发送成功");
    }
    catch (Exception ex)
    {
        Log.Error(ex, "发送日志消息失败");
    }
}

// Main方法循环修改
while (true)
{
    string logMessage = $"Log from Sender at {DateTime.Now}";
    await sender.SendLog(logMessage);
    await Task.Delay(1000); // 添加延迟避免高频发送压垮连接
}

2. 修正客户端连接URL

SignalR客户端需要连接到Function的Hub端点,而非Function根URL。正确格式为"<FunctionUrl>/hubs/loghub",其中loghub是Function中定义的HubName。修改发送端和接收端的连接代码:

var connection = new HubConnectionBuilder()
    .WithUrl("<FunctionUrl>/hubs/loghub")
    .Build();

3. 检查Azure Function配置

  • 确保local.settings.json(本地运行)或Azure应用配置中,已添加AzureSignalRConnectionString,值为Azure SignalR Service的连接字符串。
  • 可在host.json中添加SignalR路由配置(默认配置通常足够,可选):
{
  "version": "2.0",
  "extensions": {
    "signalR": {
      "hubRoute": "/hubs/{hubName}"
    }
  }
}

4. 确保ServerlessHub被正确识别

确认Azure Function项目引用的Microsoft.Azure.WebJobs.Extensions.SignalRService版本与v4 Function兼容,运行时会自动扫描继承ServerlessHub的类,无需额外配置。

5. 优化日志消息内容

原代码中日志消息在循环外定义,时间不会更新,修改为循环内生成,确保每条日志的时间都是最新的。

内容的提问来源于stack exchange,提问作者ish1104

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:02:06