/// <summary> /// API post using multipart/form-data. /// </summary> /// <param name="application">The full Uri you want to call (including any get parameters)</param> /// <param name="getParameters">Get parameters (or null if none)</param> /// <param name="postParameters">Post parameters as an object or JObject /// </param> /// <returns>The result as a JObject, with MetaData filled in.</returns> public async Task <JObject> PostFormAsync(string application, object getParameters, object postParameters, params string[] fileParameterNames) { string uri = AddGetParams(makeUri(application), getParameters); using (DisposableCollection objectsToDispose = new DisposableCollection()) { MultipartFormDataContent content = objectsToDispose.Add(new MultipartFormDataContent()); JObject data = postParameters.ToJObject(); foreach (var o in data) { if (o.Value.Type == JTokenType.Null) { continue; } if (Array.IndexOf(fileParameterNames, o.Key) >= 0) { string filename = o.Value.ToString(); FileStream fs = objectsToDispose.Add(new FileStream(filename, FileMode.Open)); HttpContent v = objectsToDispose.Add(new StreamContent(fs)); content.Add(v, o.Key, Path.GetFileName(filename)); } else { HttpContent v = objectsToDispose.Add(new StringContent(o.Value.ToString())); content.Add(v, o.Key); } } return(await SendMessageAsync(HttpMethod.Post, uri, content)); } }
/// <summary> /// Send a message and get the result. /// Deal with rate limiting return values and redirects. /// </summary> /// <param name="method">Get/Post/etc.</param> /// <param name="uri">The full Uri you want to call (including any get parameters)</param> /// <param name="postParameters">Post parameters as an object or JObject</param> public async Task <HttpResponseMessage> SendMessageAsyncAndGetResponse(HttpMethod method, string uri, object postParameters = null) { LastRequest = ""; LastResponse = ""; for (; ;) { string content = null; using (DisposableCollection disposeMe = new DisposableCollection()) { var message = disposeMe.Add(new HttpRequestMessage(method, uri)); if (!string.IsNullOrEmpty(Settings.AccessToken)) { message.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Settings.AccessToken); } if (!string.IsNullOrEmpty(Settings.CsrfToken)) { message.Headers.Add("X-CSRF-Token", Settings.CsrfToken); } message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html")); message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*")); message.Headers.Add("User-Agent", Settings.ApplicationName); if (postParameters != null) { if (postParameters is string s) { content = s; message.Content = disposeMe.Add(new StringContent(content, Encoding.UTF8, "text/plain")); } else if (postParameters is FileStream f) { content = Path.GetFileName(f.Name); f.Position = 0; message.Content = disposeMe.Add(new StreamContent(f)); string contentType = MimeMapping.MimeUtility.GetMimeMapping(content); message.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType); message.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = content }; message.Content.Headers.ContentLength = f.Length; content = "File: " + content; } else if (postParameters is HttpContent) { message.Content = (HttpContent)postParameters; } else { content = postParameters.ToJson(); message.Content = disposeMe.Add(new StringContent(content, Encoding.UTF8, "application/json")); } } LastRequest = $"{message}:{content}"; HttpResponseMessage result; int backoff = 500; int delay; if (Settings.LogRequest > 0) { Log($"Sent -> {(Settings.LogRequest > 1 ? message.ToString() : message.RequestUri.ToString())}:{content}"); } result = await _client.SendAsync(message); LastResponse = result.ToString(); if (Settings.LogResult > 1) { Log($"Received -> {result}"); } switch (result.StatusCode) { case HttpStatusCode.Found: // Redirect uri = result.Headers.Location.AbsoluteUri; delay = 1; break; case (HttpStatusCode)429: // TooManyRequests delay = 5000; break; case HttpStatusCode.BadGateway: case HttpStatusCode.ServiceUnavailable: case HttpStatusCode.GatewayTimeout: backoff *= 2; delay = backoff; if (delay > 16000) { return(result); } break; default: return(result); } result.Dispose(); Thread.Sleep(delay); } } }