通过C#代码调用Dynamics 365 Web API执行批量操作
我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面的微软最有价值专家(Microsoft MVP),欢迎关注我的微信公众号 MSFTDynamics365erLuoYong ,回复356或者20190830可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!
之前的文章 使用JS通过Web API执行批量操作,多个操作是一个事务! 讲的是JavaScript的做法,今天我实验了一阵子终于搞定了C#做法。
不多说,上代码,这个代码的用途简单,就是新建一个注释,然后将某个注释的stepid字段值设置为Y,两个操作做成一个事务:
private static async Task<string> ExecuteBatch(string ODataBaseUrl) { Guid batchId = Guid.NewGuid(); Guid changesetId = Guid.NewGuid(); string returnVal = string.Empty; StringBuilder requestBody = new StringBuilder(); requestBody.Append($"--batch_{batchId}"); requestBody.Append(" "); requestBody.Append($"Content-Type: multipart/mixed;boundary=changeset_{changesetId}"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append($"--changeset_{changesetId}"); requestBody.Append(" "); requestBody.Append("Content-Type: application/http"); requestBody.Append(" "); requestBody.Append("Content-Transfer-Encoding:binary"); requestBody.Append(" "); requestBody.Append("Content-ID: 1"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append($"POST {ODataBaseUrl}annotations HTTP/1.1"); requestBody.Append(" "); requestBody.Append("Content-Type: application/json;type=entry"); requestBody.Append(" "); requestBody.Append(" "); JObject jObject = new JObject( new JProperty("subject", "克隆出来的记录"), new JProperty("filename", "MSFTDynamics365erLuoYong.jpg"), new JProperty("filesize", 39372), new JProperty("documentbody", "/9j/4AAQSkZJRgAB2cFFABRRRQAUUUUAf//Z" requestBody.Append(" "); requestBody.Append($"--changeset_{changesetId}"); requestBody.Append(" "); requestBody.Append("Content-Type: application/http"); requestBody.Append(" "); requestBody.Append("Content-Transfer-Encoding:binary"); requestBody.Append(" "); requestBody.Append("Content-ID: 2"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append($"PUT {ODataBaseUrl}annotations(4B502B89-4520-E911-B0C6-E05D5152C120)/stepid HTTP/1.1"); requestBody.Append(" "); requestBody.Append("Content-Type: application/json;type=entry"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append("{"value":"Y"}"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append($"--changeset_{changesetId}--"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append($"--batch_{batchId}--"); HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create($"{ODataBaseUrl}$batch"); request.Credentials = new NetworkCredential(ConfigurationManager.AppSettings["userName"], ConfigurationManager.AppSettings["passWord"]); request.Method = "POST"; request.ContentType = $"multipart/mixed;boundary=batch_{batchId}"; request.Accept = "application/json"; request.Headers.Add("OData-MaxVersion", "4.0"); request.Headers.Add("OData-Version", "4.0"); byte[] buffer = Encoding.UTF8.GetBytes(requestBody.ToString()); request.ContentLength = buffer.Length; using (Stream stream = await request.GetRequestStreamAsync()) { stream.Write(buffer, 0, buffer.Length); stream.Flush(); } using (WebResponse response = await request.GetResponseAsync()) { var webResponse = response as HttpWebResponse; if (webResponse.StatusCode == HttpStatusCode.OK) { Stream Answer = response.GetResponseStream(); StreamReader _Answer = new StreamReader(Answer); returnVal = _Answer.ReadToEnd(); } else { throw new Exception($"Error. {webResponse.StatusCode}"); } } return returnVal; }
我的执行效果如下,我这里是执行成功HTTP STATUS CODE = 200)后显示了返回内容:
如果改成用 HttpClient 来发起请求,代码如下,个人推荐使用这种:
private static async Task<string> ExecuteBatch(string ODataBaseUrl) { Guid batchId = Guid.NewGuid(); Guid changesetId = Guid.NewGuid(); string returnVal = string.Empty; StringBuilder requestBody = new StringBuilder(); requestBody.Append($"--batch_{batchId}"); requestBody.Append(" "); requestBody.Append($"Content-Type: multipart/mixed;boundary=changeset_{changesetId}"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append($"--changeset_{changesetId}"); requestBody.Append(" "); requestBody.Append("Content-Type: application/http"); requestBody.Append(" "); requestBody.Append("Content-Transfer-Encoding:binary"); requestBody.Append(" "); requestBody.Append("Content-ID: 1"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append($"POST {ODataBaseUrl}annotations HTTP/1.1"); requestBody.Append(" "); requestBody.Append("Content-Type: application/json;type=entry"); requestBody.Append(" "); requestBody.Append(" "); JObject jObject = new JObject( new JProperty("subject", "克隆出来的记录"), new JProperty("filename", "MSFTDynamics365erLuoYong.jpg"), new JProperty("filesize", 39372), new JProperty("documentbody", "/9j/4AAQSkZJRRRQAUUUUAf//Z"), new JProperty("isdocument", true), new JProperty("mimetype", "image/jpeg"), new JProperty("notetext", "罗勇测试用的"), new JProperty("objectid_account@odata.bind", "/accounts(C543D891-9FBD-E911-B0D1-8280A40FB795)") ); requestBody.Append(JsonConvert.SerializeObject(jObject)); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append($"--changeset_{changesetId}"); requestBody.Append(" "); requestBody.Append("Content-Type: application/http"); requestBody.Append(" "); requestBody.Append("Content-Transfer-Encoding:binary"); requestBody.Append(" "); requestBody.Append("Content-ID: 2"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append($"PUT {ODataBaseUrl}annotations(85412E8C-B08D-E911-B0C9-C8187530CEF1)/stepid HTTP/1.1"); requestBody.Append(" "); requestBody.Append("Content-Type: application/json;type=entry"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append("{"value":"Y"}"); requestBody.Append(" "); requestBody.Append(" "); requestBody.Append($"--changeset_{changesetId}--"); NetworkCredential credentials = new NetworkCredential(ConfigurationManager.AppSettings["userName"], ConfigurationManager.AppSettings["passWord"]); HttpMessageHandler messageHandler = new HttpClientHandler() { Credentials = credentials }; using (HttpClient httpClient = new HttpClient(messageHandler)) { httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0"); httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0"); httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); MultipartContent mainContent = new MultipartContent("mixed", $"batch_{batchId.ToString().Replace(""","")}"); StringContent sc = new StringContent(requestBody.ToString()); sc.Headers.Clear(); sc.Headers.Add("Content-Type", $"multipart/mixed;boundary={changesetId.ToString()}"); mainContent.Add(sc); var response = await httpClient.PostAsync($"{ODataBaseUrl}$batch", mainContent); if (response.IsSuccessStatusCode) { returnVal = await response.Content.ReadAsStringAsync(); } else { var errorMsg = await response.Content.ReadAsStringAsync(); throw new Exception(errorMsg); } return returnVal; } }