使用C#和Web API上传文件到CRM实体文件字段返回Bad Request如何解决
问题描述
我尝试将PDF文件上传至CRM实体的文件字段,参考了微软官方的相关开发文档。目前我已经实现了通过Client ID和Client Secret调用OAuth生成Access Token的代码,但请求返回Bad Request响应。
相关参数如下:
- 实体名称:msnfp_request
- 文件字段名称:bna_file
原有代码如下:
var fileStream = System.IO.File.OpenRead(<file path>); var url = new Uri("https://mydev.crm.dynamics.com/api/data/v9.1/msnfp_request(a528f300-7b53-ec11-8c62-0022482a2e7a)/bna_file); AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/<domain>"); ClientCredential credential = new Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential(<client id>,<client secret>); AuthenticationResult result = authContext.AcquireToken("https://mydev.crm.dynamics.com/", credential); using (var req = new HttpRequestMessage(new HttpMethod("PATCH"), url)) { req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken); req.Content = new StreamContent(fileStream); req.Content.Headers.Add("Content-Type", "application/octet-stream"); req.Content.Headers.Add("x-ms-file-name", "test.pdf"); HttpClient Client = new HttpClient(); using (var response = await Client.SendAsync(req)) { response.EnsureSuccessStatusCode(); } }
请问上述代码存在什么问题?
解答
核心问题(直接导致400错误)
- URL端点配置错误:上传Dataverse文件字段的内容时,需要在字段名称后追加
/value后缀,原有代码的URL直接指向字段本身,不符合接口要求。 - 语法错误:定义Uri的代码行中,URL字符串末尾缺少闭合双引号,会直接导致编译失败。
- HTTP方法使用错误:上传文件内容到
/value端点需要使用PUT方法,原有代码使用的PATCH方法仅适用于更新实体普通属性,不满足文件上传的要求。
优化建议(不直接导致400,但影响代码稳定性)
- 不要在每次请求时都新建
HttpClient实例,频繁实例化会导致套接字资源耗尽,建议将HttpClient设置为全局单例复用。 - 你使用的
Microsoft.IdentityModel.Clients.ActiveDirectory包已经停止维护,建议替换为官方推荐的Microsoft.Identity.Client包来获取访问令牌。
修正后的参考代码
// 建议将HttpClient设为静态单例全局复用 private static readonly HttpClient _httpClient = new HttpClient(); // 业务逻辑代码 var fileStream = System.IO.File.OpenRead("<实际文件路径>"); // 修正URL:补全双引号,增加/value后缀 var url = new Uri("https://mydev.crm.dynamics.com/api/data/v9.1/msnfp_request(a528f300-7b53-ec11-8c62-0022482a2e7a)/bna_file/value"); AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/<你的租户域名/ID>"); ClientCredential credential = new Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential("<你的Client ID>", "<你的Client Secret>"); AuthenticationResult result = authContext.AcquireToken("https://mydev.crm.dynamics.com/", credential); using (var req = new HttpRequestMessage(HttpMethod.Put, url)) // 修正为PUT请求方法 { req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken); req.Content = new StreamContent(fileStream); req.Content.Headers.Add("Content-Type", "application/octet-stream"); req.Content.Headers.Add("x-ms-file-name", "test.pdf"); using (var response = await _httpClient.SendAsync(req)) { response.EnsureSuccessStatusCode(); } }
内容的提问来源于stack exchange,提问作者V.Mulik
相关产品推荐
相关产品推荐

