.NET通过进程启动Web API(真实TCP套接字)无法连接问题排查
排查步骤及解决方案
1. 端口不匹配(最直接的问题)
你的错误信息显示连接被拒绝的是localhost:5000,但测试代码里请求的是http://localhost:5083/WeatherForecast——说明API实际启动在5000端口,和你预期请求的端口完全不一致。
解决方法二选一:
- 修改测试代码,请求API实际使用的5000端口;
- 强制API启动在指定端口,修改
dotnet run的参数:
这样可以绕过launchSettings.json的默认配置,确保API固定启动在你需要的端口。Arguments = "run --urls=http://localhost:5083",
2. 硬编码延迟不可靠
Task.Delay(5000)是盲等逻辑,API可能还没完成启动初始化就被请求,导致连接失败。建议换成两种可靠的等待方式:
方案A:监听API启动日志
捕获API的输出,直到看到类似Now listening on: http://localhost:xxxx的启动完成日志,再发起请求:
private async Task<Process> StartProcessAndWaitForReady() { var tcs = new TaskCompletionSource<bool>(); var testProjectDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var apiProjectDir = Path.GetFullPath(Path.Combine(testProjectDir, "../../../../ProcessAPI")); var processStartInfo = new ProcessStartInfo { FileName = "dotnet", Arguments = "run --urls=http://localhost:5083", WorkingDirectory = apiProjectDir, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; var process = new Process { StartInfo = processStartInfo }; process.OutputDataReceived += (sender, args) => { if (args.Data != null) { Console.WriteLine(args.Data); if (args.Data.Contains("Now listening on:")) { tcs.TrySetResult(true); } } }; process.ErrorDataReceived += (sender, args) => { if (args.Data != null) Console.WriteLine($"Error: {args.Data}"); }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); // 设置30秒超时,避免无限等待 await Task.WhenAny(tcs.Task, Task.Delay(TimeSpan.FromSeconds(30))); if (!tcs.Task.IsCompletedSuccessfully) { process.Kill(); throw new InvalidOperationException("API启动超时"); } return process; }
方案B:重试请求
如果不想监听日志,可以给请求加重试逻辑,直到成功或超时:
// 在测试方法里替换请求逻辑 var response = await RetryAsync(() => client.GetAsync("http://localhost:5083/WeatherForecast"), maxRetries: 10, delayMs: 500); // 重试方法实现 private async Task<HttpResponseMessage> RetryAsync(Func<Task<HttpResponseMessage>> action, int maxRetries, int delayMs) { var retryCount = 0; while (true) { try { var response = await action(); if (response.IsSuccessStatusCode) return response; } catch (HttpRequestException) when (retryCount < maxRetries) { retryCount++; await Task.Delay(delayMs); } } }
3. 验证工作目录是否正确
相对路径../../../../ProcessAPI在不同环境(比如测试输出目录、CI流水线)可能无法正确定位到API项目。建议改为绝对路径:
var testProjectDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var apiProjectDir = Path.Combine(testProjectDir, "../../../../ProcessAPI"); // 转为绝对路径消除相对路径歧义 apiProjectDir = Path.GetFullPath(apiProjectDir);
把这个路径赋值给WorkingDirectory,确保Process能找到API项目文件。
4. 确认API是否真的启动
检查API的启动日志,看是否有启动失败的错误(比如依赖缺失、项目文件不存在)。如果用xUnit,可以注入ITestOutputHelper来记录日志,方便排查:
private readonly ITestOutputHelper _output; public GetWeatherForecastTest(ITestOutputHelper output) { _output = output; } // 在OutputDataReceived事件里替换输出逻辑 _output.WriteLine(args.Data);
这样就能在测试报告里看到API的完整启动日志,确认是否真的启动成功,以及实际监听的端口。
内容的提问来源于stack exchange,提问作者Isaac Richardson
相关产品推荐
相关产品推荐

