本地正常的C# .NET Core应用部署Azure WebApp后ServiceBus/SQL失效排查
看起来你遇到的问题核心是控制台应用的运行模式不匹配Azure WebApp的环境,再加上配置管理、资源生命周期的小问题。下面是具体的调整方案,一步步来解决:
1. 把控制台应用改成ASP.NET Core Worker Service
Azure WebApp默认会终止没有HTTP端点的后台进程,你的控制台应用靠Console.ReadKey()维持运行,但在WebApp环境中这个方法不会生效,进程会很快被系统回收。改成Worker Service(专门的后台服务模板)就能让应用在WebApp中长期稳定运行。
操作步骤:
- 新建一个ASP.NET Core Worker Service项目(或者把现有控制台项目改造为Worker Service)
- 把ServiceBus和SQL的业务逻辑移到
Worker.cs的对应方法中
示例核心代码(Worker.cs):
using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.ServiceBus; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace ServiceBusReaderWorker { public class Worker : BackgroundService { private readonly ILogger<Worker> _logger; private readonly string _serviceBusConnStr; private readonly string _queueName; private readonly string _sqlConnStr; private IQueueClient _queueClient; // 依赖注入获取配置和日志 public Worker(ILogger<Worker> logger, IConfiguration configuration) { _logger = logger; _serviceBusConnStr = configuration["ServiceBusConnectionString"]; _queueName = configuration["QueueName"]; _sqlConnStr = configuration.GetConnectionString("SqlDatabase"); } // 启动时初始化ServiceBus客户端 public override async Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation("ServiceBus reader starting..."); _queueClient = new QueueClient(_serviceBusConnStr, _queueName); RegisterMessageHandler(); await base.StartAsync(cancellationToken); } // 后台服务保持运行的核心逻辑 protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); // 用无限延迟让服务持续运行,直到收到停止信号 await Task.Delay(Timeout.Infinite, stoppingToken); } // 注册ServiceBus消息处理器 private void RegisterMessageHandler() { var handlerOptions = new MessageHandlerOptions(ExceptionHandler) { MaxConcurrentCalls = 1, AutoComplete = false }; _queueClient.RegisterMessageHandler(ProcessMessageAsync, handlerOptions); } // 处理ServiceBus消息并写入SQL private async Task ProcessMessageAsync(Message message, CancellationToken token) { var messageBody = Encoding.UTF8.GetString(message.Body); _logger.LogInformation("Received message: {seq} - {body}", message.SystemProperties.SequenceNumber, messageBody); // 用using管理SQL连接,自动释放资源,避免连接池耗尽 using (var connection = new SqlConnection(_sqlConnStr)) { await connection.OpenAsync(token); string query = "INSERT INTO [SalesLT].[messages] (message) VALUES(@Message)"; using (var cmd = new SqlCommand(query, connection)) { cmd.Parameters.AddWithValue("@Message", messageBody); await cmd.ExecuteNonQueryAsync(token); _logger.LogInformation("Message saved to SQL successfully"); } } // 标记消息已处理,避免重复接收 await _queueClient.CompleteAsync(message.SystemProperties.LockToken); } // 处理ServiceBus异常 private Task ExceptionHandler(ExceptionReceivedEventArgs args) { _logger.LogError(args.Exception, "ServiceBus message handler failed"); var context = args.ExceptionReceivedContext; _logger.LogError("Exception context: Endpoint={ep}, Path={path}, Action={act}", context.Endpoint, context.EntityPath, context.Action); return Task.CompletedTask; } // 停止时清理ServiceBus客户端 public override async Task StopAsync(CancellationToken cancellationToken) { _logger.LogInformation("ServiceBus reader stopping..."); await _queueClient.CloseAsync(cancellationToken); await base.StopAsync(cancellationToken); } } }
2. 用Azure App Settings管理敏感配置,禁止硬编码
你代码里直接写死了ServiceBus连接字符串、SQL账号密码,这既不安全,也不便于在Azure环境中修改。应该把这些配置移到WebApp的应用设置和连接字符串中:
操作步骤:
- 打开Azure门户,找到你的WebApp
- 进入配置 > 应用设置,添加两个键值对:
ServiceBusConnectionString:值填你的ServiceBus完整连接字符串QueueName:值填BasicQueue
- 进入配置 > 连接字符串,添加SQL连接:
- 名称:
SqlDatabase - 值:你的Azure SQL连接字符串(示例:
Server=tcp:xxxx.database.windows.net,1433;Initial Catalog=mySampleDatabase;User ID=USERID;Password=PASSWORD;Encrypt=True;Connection Timeout=30;) - 类型选择
SQLAzure
- 名称:
本地开发时,可以在appsettings.json中写占位符,Azure配置会自动覆盖本地值:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning" } }, "ServiceBusConnectionString": "", "QueueName": "BasicQueue", "ConnectionStrings": { "SqlDatabase": "" } }
3. 修复SQL连接的生命周期问题
之前用静态SqlConnection长期保持打开状态,容易导致连接池耗尽、连接失效。正确的做法是每次操作数据库时创建新连接,用using语句自动释放,这样能利用ADO.NET的连接池机制,避免资源泄漏。
上面的Worker示例中已经用了using (var connection = new SqlConnection(_sqlConnStr)),这就是标准的正确写法。
4. 启用WebApp日志,方便排查问题
WebApp环境中Console.WriteLine的输出不会直接显示,需要启用应用日志来查看运行状态和错误:
操作步骤:
- 进入WebApp的监控 > 日志流
- 点击开启,选择日志级别(比如
Information) - 之后你的
ILogger日志会在这里实时展示,能快速定位ServiceBus或SQL的错误
5. 检查网络权限配置
如果你的Azure SQL或ServiceBus设置了网络防火墙,需要确保WebApp能访问它们:
- Azure SQL:进入SQL服务器的防火墙和虚拟网络,勾选「允许Azure服务和资源访问此服务器」
- ServiceBus:如果启用了VNet隔离,需要将WebApp的VNet加入ServiceBus的允许列表,或者开启「允许受信任的Microsoft服务绕过此防火墙」
完成这些调整后,重新部署应用到Azure WebApp,应该就能正常读取ServiceBus消息并写入SQL数据库了。
内容的提问来源于stack exchange,提问作者Eugene Goldberg

