using System; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; namespace BatchSamples { /* * Example use of Advanced REST Web API call to /batch endpoint using .NET 4.5 web client. * * The /batch endpoint supports multiple REST Web API calls at once via a MIME multipart message containing all the individual HTTP messages you want to issue. * The batched calls can be executed serially (in the order they appear in the MIME content), or in parallel. The choice is indicated via the multipart content type of "mixed" versus "parallel". * The results are returned in the response MIME contents in the same order as the requests. * * Build notes: Targets .NET Framework 4.5 + * Requires additional nuget packages "System.Net.Http" and "System.Net.Http.Formatting.Extension" */ class BatchSample { // these values must be adjusted to your environment in order for the sample to work static string _webApiUser = "cis_userid"; // CIS UserId to be used to authenticate with WebApi static string _webApiPassword = "cis_password"; // CIS password associated with the CIS UserId above static string _webApiRootUrl = "https://webapi.yourserver.com/"; // URL Root of the REST Web API server to be used public static void Main() { try { RunAsync().Wait(); } catch (AggregateException ex) { Console.WriteLine("Errors occurred during the HTTP interactions with the REST WebApi server:"); foreach (var item in ex.InnerExceptions) { Console.WriteLine(item.ToString()); } } } private static async Task RunAsync() { try { Console.WriteLine("Building batch request..."); using (var client = new HttpClient()) { client.BaseAddress = new Uri(_webApiRootUrl); client.DefaultRequestHeaders.Accept.Clear(); //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var basicAuth = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", _webApiUser, _webApiPassword)))); client.DefaultRequestHeaders.Authorization = basicAuth; // Create the multipart MIME content of the batch request in preparation for adding each request MultipartContent multipartContent = new MultipartContent("mixed", "batch_" + Guid.NewGuid().ToString()); // Request 1: a GET LIST of states with some query strings { var url = _webApiRootUrl + "data/state?page=2&pagesize=5&where=code like '%N%' and O_Key gt 5&order=-description&fields=*"; Console.WriteLine("Request 1: GET: {0}", url); var req = new HttpRequestMessage(HttpMethod.Get, url); multipartContent.Add(new HttpMessageContent(req)); } // Request 2: a PUT to update existing state code "ON" { var url = _webApiRootUrl + "data/state/ON"; var body = "{ \"code\": \"ON\", \"description\": \"Ontario\", \"disabled\": false }"; Console.WriteLine("Request 2: PUT: {0} <<{1}>>", url, body); var req = new HttpRequestMessage(HttpMethod.Put, url); req.Content = new StringContent(body, System.Text.Encoding.UTF8, "application/json"); req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); multipartContent.Add(new HttpMessageContent(req)); } // Request 3: a GET against /about endpoint { var url = _webApiRootUrl + "about"; Console.WriteLine("Request 3: GET: {0}", url); var req = new HttpRequestMessage(HttpMethod.Get, url); // (this one adds an explicit authentication header just for demonstration - without this the main authentication header would apply) req.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", _webApiUser, _webApiPassword)))); req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); multipartContent.Add(new HttpMessageContent(req)); } Console.WriteLine(); // -- Send the batch request to the host and wait for the response -- Console.WriteLine("Sending batch request to '{0}batch' using user '{1}'", _webApiRootUrl, _webApiUser); HttpResponseMessage response = await client.PostAsync(_webApiRootUrl + "batch", multipartContent); if (response.IsSuccessStatusCode) { // HTTP response code 200 (OK) indicates the request succeeded, and the response body contains a multipart message with each part corresponding to the requests we sent, in the same order Console.WriteLine("Successfully retrieved batch responses:"); if (response.Content.IsMimeMultipartContent()) { // parse the MIME multipart response content into the individual response bodies and handle each as needed var multipartData = await response.Content.ReadAsMultipartAsync(); var i = 0; foreach (var part in multipartData.Contents) { i++; var r = await part.ReadAsHttpResponseMessageAsync(); var body = await r.Content.ReadAsStringAsync(); body = (body ?? "").Trim(); body = body.Replace("\n", "\\").Replace("\r", "\\").Replace("\t", " "); if (body.Length > 143) body = body.Substring(0, 140) + " ..."; Console.WriteLine("Response {0}: {1} ({2}) <<{3}>>", i, (int)r.StatusCode, r.ReasonPhrase, body); } } } else { Console.WriteLine("Batch request failed with result {0} ({1})", (int)response.StatusCode, response.ReasonPhrase); } } } catch (Exception ex) { Console.WriteLine("Exception occurred: {0}\r\n{1}", ex.Message, ex.StackTrace); } Console.WriteLine(); Console.WriteLine("Done."); } } }