编写控制台程序上传PDF至D365时遇FileStream读取异常求助
问题分析与解决方案
问题根源
你遇到的ReadTimeout异常,核心原因是同步阻塞调用异步方法导致FileStream状态异常。代码中用Wait()强制等待异步任务完成,会阻塞主线程,导致FileStream在等待过程中被错误触发超时检查;另外手动设置Content-Length也可能引发流长度不匹配的问题。
修复步骤与代码
关键修改点
- 全程使用
async/await替代同步阻塞的Wait(),避免流状态被干扰 - 移除手动添加的
Content-Length头,StreamContent会自动根据流长度生成正确的头信息 - 规范HttpClient的使用(控制台程序建议复用单例,或者在using块内正确异步调用)
- 简化异步获取Token的逻辑,去掉冗余的
Task.Run包裹
修复后的完整代码
using System.Net.Http.Headers; using Microsoft.Identity.Client; class Program { static async Task Main(string[] args) { // 替换为你的实际参数 string appid = "你的AppId"; string clientsecret = "你的ClientSecret"; string aadid = "你的AAD租户ID"; string url = "Dynamics 365的上传API地址"; string nameCleared = "清理后的文件名"; // 推荐复用HttpClient,避免频繁创建导致Socket资源耗尽 using var httpClient = new HttpClient(); using (var filestream = File.OpenRead(@"C:\test\test.pdf")) { var streamContent = new StreamContent(filestream); streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); // 获取认证Token var _application = ConfidentialClientApplicationBuilder .Create(appid) .WithClientSecret(clientsecret) .WithAuthority(new Uri($"https://login.microsoftonline.com/{aadid}")) .Build(); var authResult = await _application.AcquireTokenForClient(new[] { $"orgname.crm4.dynamics.com/.default" }) .ExecuteAsync(); // 构造上传请求并发送 using (var req = new HttpRequestMessage(HttpMethod.Patch, url)) { req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken); req.Content = streamContent; req.Content.Headers.Add("x-ms-file-name", $"{nameCleared}.pdf"); using (var response = await httpClient.SendAsync(req)) { response.EnsureSuccessStatusCode(); } } } } }
额外说明
- 异步编程规范:控制台程序的
Main方法标记为async Task后,可直接用await处理异步任务,彻底避免同步阻塞带来的线程状态问题。 - 流生命周期管理:
FileStream被StreamContent使用时,只要保持using块的正确嵌套,流会在请求完成后自动释放,无需手动关闭。 - HttpClient复用:频繁创建HttpClient会导致系统Socket资源耗尽,推荐在程序生命周期内复用单个实例。
内容的提问来源于stack exchange,提问作者freudi
相关产品推荐
相关产品推荐

