public HTTPHandlerAttribute(string Path = "", HttpMethods Method = HttpMethods.Post, ParamsPlacedIn ParametersIn = ParamsPlacedIn.URLPath, int CacheMilliseconds = 0) { this.Method = Method; this.CacheMilliseconds = CacheMilliseconds; this.Path = Path; this.ParametersIn = ParametersIn; }
public static object Call(string PrcName, Uri url, string httpMethod, object args, Type argType, ParamsPlacedIn paramsPlaced, Type resType) { if (args == null) { throw new ArgumentNullException(nameof(args)); } object?res = null; string sguid = Guid.NewGuid().ToString(); Exception?ex = null; HttpClient cli; using var handler = new HttpClientHandler(); if (IgnoreServerCertificateValidationError) { handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true; } if (Credentials != null) { handler.Credentials = Credentials; cli = new HttpClient(handler); } else { cli = new HttpClient(handler); } using (cli) { cli.DefaultRequestHeaders.Accept.Clear(); cli.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); Task <HttpResponseMessage>?tsk = null; #pragma warning disable CA1308 // Normalize strings to uppercase var lUrl = new Uri((url + "/" + PrcName).ToLowerInvariant()); #pragma warning restore CA1308 // Normalize strings to uppercase string urlArgs = ""; StringContent?content = null; try { // Pass parameters for Get request in URL if (httpMethod == HttpMethods.Get.ToString().ToUpperInvariant()) { if (paramsPlaced == ParamsPlacedIn.URLPath && argType != null) { foreach (var p in argType.GetProperties()) { string val = JsonSerializer.Serialize(p.GetValue(args)); if (p.PropertyType == typeof(string)) { val = val.Replace("\\", Constants.BACKSLASHJOKER, StringComparison.Ordinal); } val = Uri.EscapeUriString(val); urlArgs += val + "/"; } if (!string.IsNullOrEmpty(urlArgs)) { urlArgs = "/" + urlArgs.Trim('/'); lUrl = new Uri(lUrl.AbsoluteUri + urlArgs); } } else if (paramsPlaced == ParamsPlacedIn.Query && argType != null) { var prps = argType.GetProperties(); if (prps != null && prps.Length > 0) { var query = "?"; for (int i = 0; i < prps.Length; i++) { string val = JsonSerializer.Serialize(prps[i].GetValue(args)); if (prps[i].PropertyType == typeof(string)) { val = val.Replace("\\", Constants.BACKSLASHJOKER, StringComparison.Ordinal); } val = Uri.EscapeUriString(val); // Escape does not work for + character because according standard // specification + is legal character in url used as alias for space val = val.Replace("+", "%2B", StringComparison.Ordinal); // Here we manually escape plus #pragma warning disable CA1308 // Normalize strings to uppercase query += prps[i].Name.ToLowerInvariant() + "=" + val; #pragma warning restore CA1308 // Normalize strings to uppercase if (i < prps.Length - 1) { query += "&"; } } var qBld = new UriBuilder(lUrl) { Query = query }; lUrl = qBld.Uri; } } else { #pragma warning disable CA1303 // Do not pass literals as localized parameters var exception = new Exception("Method attributed as used GET http request. Parameters for such requests can be passed only in URL or in QUERY but not in BODY"); #pragma warning restore CA1303 // Do not pass literals as localized parameters throw exception; } tsk = cli.GetAsync(lUrl); } else if (httpMethod == HttpMethods.Post.ToString().ToUpperInvariant()) { var rs = JsonSerializer.Serialize(args, args.GetType()); content = new StringContent(JsonSerializer.Serialize(args), Encoding.UTF8, "application/json"); tsk = cli.PostAsync(lUrl, content); } else if (httpMethod == HttpMethods.Put.ToString().ToUpperInvariant()) { content = new StringContent(JsonSerializer.Serialize(args), Encoding.UTF8, "application/json"); tsk = cli.PutAsync(lUrl, content); } else if (httpMethod == HttpMethods.Delete.ToString().ToUpperInvariant()) { content = new StringContent(JsonSerializer.Serialize(args), Encoding.UTF8, "application/json"); tsk = cli.PutAsync(lUrl, content); } else { throw new Exception("Unknown HTTP METHOD: " + httpMethod); } var clientError = string.Empty; var isTimout = !tsk.Wait(WaitResponseTimeoutMs); if (isTimout) { clientError = $"Wait server response exceed timeout ({WaitResponseTimeoutMs} ms)"; } content?.Dispose(); var hasError = isTimout || tsk == null || !tsk.Result.IsSuccessStatusCode; if (!hasError && tsk != null) { var contentType = tsk.Result.Content.Headers.ContentType; if (contentType.MediaType == "text/html" || contentType.MediaType == "application/json") { var ltsk = tsk.Result.Content.ReadAsStringAsync(); if (ltsk.Wait(ReadContentTimeoutMs)) { res = JsonSerializer.Deserialize(ltsk.Result, resType); } else { clientError = $"Read response content exceed timeout ({ReadContentTimeoutMs} ms)"; hasError = true; } } /* * if (resType != typeof(HTTPBinaryResult)) * { * var ltsk = tsk.Result.Content.ReadAsStringAsync(); * ltsk.Wait(); * json = ltsk.Result; * var resp = JsonConvert.DeserializeObject<RPCResponse>(json); * var responseType = Utils.GetMethodResponseHolderType(PrcName, resType); * if (resp.res is Newtonsoft.Json.Linq.JObject && resType.IsClass) * { * res = ((Newtonsoft.Json.Linq.JObject)resp.res).ToObject(resType); * } * else * res = resp.res; * //else res= JsonConvert.DeserializeObject(json,restype); * } * else // Manage Binary Result * { * var ltsk = tsk.Result.Content.ReadAsByteArrayAsync(); * ltsk.Wait(); * HTTPBinaryResult binres = new HTTPBinaryResult() * { * Data = ltsk.Result * }; * if (tsk.Result.Headers.Contains(Constants.HEADER_CONTINUE_TOKEN)) * binres.ContinueToken = tsk.Result.Headers.GetValues(Constants.HEADER_CONTINUE_TOKEN).First(); * res = binres; * } */ } if (hasError) { if (!string.IsNullOrEmpty(clientError)) { throw new Exception($"Http client error: {clientError}"); } var ServerReason = "Unknown"; if (tsk != null && tsk.Result.StatusCode == HttpStatusCode.InternalServerError) { var ltsk = tsk.Result.Content.ReadAsStringAsync(); if (ltsk.Wait(ReadContentTimeoutMs)) { ServerReason = ltsk.Result; } else { ServerReason = "Unable to get server side reason. Timeout ({ReadContentTimeoutMs} ms) happens when tried to read server response content"; } } var statusCode = tsk != null ? tsk.Result.StatusCode : HttpStatusCode.NoContent; throw new Exception($"Http non-successful result: StatusCode:{statusCode}, ServerReason: {ServerReason}"); } } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception ex1) { Exception lex = ex1; while (lex.InnerException != null) { lex = lex.InnerException; } ex = lex; } #pragma warning restore CA1031 // Do not catch general exception types if (ex != null) { throw ex; } } if (res == null) { #pragma warning disable CA1303 // Do not pass literals as localized parameters throw new Exception("Can't get result from remote call"); #pragma warning restore CA1303 // Do not pass literals as localized parameters } return(res); }