如何通过现有CreateRecord方法上传ServiceNow附件(Rest API)
ServiceNow附件上传实现方案(基于不可修改的CreateRecord方法)
要通过固定参数的CreateRecord通用方法完成ServiceNow附件上传,核心是让通用方法适配ServiceNowapi/now/attachment/file接口要求的multipart/form-data请求格式,具体实现步骤如下:
1. 确保ServiceNowAttachment类包含必填字段
你的ServiceNowAttachment实体类必须包含ServiceNow接口要求的两个核心参数,同时保留文件相关属性:
public class ServiceNowAttachment { // 目标表名(例如 incident、change_request) public string table_name { get; set; } // 要附加附件的记录Sys ID public string table_sys_id { get; set; } // 文件名 public string FileName { get; set; } // 文件二进制数据 public byte[] FileData { get; set; } // 其他可选字段(如描述等) }
2. 调整UploadAttachment方法的参数传递逻辑
无需手动构造MultipartFormDataContent,而是通过标记请求类型的方式,让CreateRecord内部自动处理文件上传逻辑:
private async Task UploadAttachment(CRMContext crmContext, ServiceNowAttachment attachment, ServiceNowQueryOptions requestOptions) { // 校验必填参数 if (string.IsNullOrEmpty(attachment.table_name) || string.IsNullOrEmpty(attachment.table_sys_id)) throw new ArgumentException("table_name和table_sys_id为附件上传必填字段"); if (attachment.FileData == null || attachment.FileData.Length == 0) throw new ArgumentException("待上传文件数据不能为空"); // 在请求选项中标记这是附件上传请求,用于CreateRecord内部识别 requestOptions.Headers.Add("X-Upload-Type", "Attachment"); // 直接调用CreateRecord,无需额外构造内容 await this.serviceNowClient.CreateRecord<ServiceNowAttachment>( crmContext, attachment, null, // 附件上传无需额外字段 requestOptions).ConfigureAwait(false); }
3. 修改CreateRecord内部逻辑(核心适配)
虽然CreateRecord的对外参数不能修改,但内部需要增加附件上传的分支处理,自动构建符合要求的多部分请求:
public async Task<T> CreateRecord<T>(CRMContext context, T entity, JObject additionalFields, ServiceNowQueryOptions options) { // 附件上传使用专属端点,其他实体使用常规表端点 string endpoint = typeof(T) == typeof(ServiceNowAttachment) ? "/api/now/attachment/file" : "/api/now/table/" + GetTableName<T>(); HttpContent content; // 判断是否为附件上传请求,构建multipart/form-data内容 if (entity is ServiceNowAttachment attachment && attachment.FileData != null) { var multipartContent = new MultipartFormDataContent(); // 先添加table_name和table_sys_id(必须在file参数之前) multipartContent.Add(new StringContent(attachment.table_name), "table_name"); multipartContent.Add(new StringContent(attachment.table_sys_id), "table_sys_id"); // 最后添加文件参数(ServiceNow要求必须放在最后) using var fileContent = new ByteArrayContent(attachment.FileData); // 可根据实际文件类型替换MIME,比如image/png、application/pdf fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream"); multipartContent.Add(fileContent, "file", attachment.FileName); content = multipartContent; } else { // 原有JSON请求逻辑保持不变 var jsonContent = new StringContent(JsonConvert.SerializeObject(entity), Encoding.UTF8, "application/json"); // 处理additionalFields的原有逻辑... content = jsonContent; } // 发送请求并处理响应 var response = await _httpClient.PostAsync(endpoint, content, options.CancellationToken); response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject<T>(responseContent); }
关键注意事项
- 参数顺序严格遵守:ServiceNow的
api/now/attachment/file接口要求file参数必须是请求的最后一个参数,不能调整顺序。 - MIME类型优化:如果明确知道文件的具体类型,替换
application/octet-stream为对应类型(如image/jpeg)可以提升接口兼容性。 - 自动处理请求头:
MultipartFormDataContent会自动生成正确的Content-Type头(包含边界信息),无需手动设置。
内容的提问来源于stack exchange,提问作者nikom
相关产品推荐
相关产品推荐

