/// <summary> /// Log telemetry to ETW and AppInsights /// </summary> /// <returns></returns> private void LogRequestEvent(Uri serviceUri, RequestDescriptor descriptor) { string userName = string.Empty; if (descriptor.Headers != null) { descriptor.Headers.TryGetValue(_UserNameHeader, out userName); } Dictionary <string, string> properties = new Dictionary <string, string> { { "method", descriptor.Method } }; // Add username to logging if its enabled if (_IsUserInfoLoggingEnabled) { properties.Add("username", userName ?? string.Empty); } // Log non-groups method. if (descriptor.Method != "groups") { if (!string.IsNullOrEmpty(descriptor.QueryString)) { properties.Add("query", descriptor.QueryString); } } ServiceEventSource.Current.Message($"Request: {serviceUri.ToString()}"); _StaticLogger.LogInformation(serviceUri.ToString(), properties); }
/// <summary> /// Make request using reverse proxy /// </summary> /// <returns></returns> private async Task <ApiResult> MakeRequestUsingReverseProxy(RequestDescriptor descriptor, ServicePartitionKey servicePartitionKey) { ApiResult result = new ApiResult(); Uri serviceUri = new Uri($"https://localhost:{_ReverseProxyPort}/{descriptor.Application}/{descriptor.Service}/"); // This is logged mainly to track usage LogRequestEvent(serviceUri, descriptor); // Don't log queryString for 'groups' method as it contains sensitive info string queryString = (descriptor.Method == "groups" || descriptor.QueryString == null) ? string.Empty : descriptor.QueryString; // Generate request and receive response HttpRequestMessage request = CreateMicroserviceRequest(serviceUri, descriptor); HttpResponseMessage response = null; try { response = await _HttpClient.SendAsync(request); } catch (Exception ex) { // We have seen cases where SendAsync can fail. Log telemetry for those cases. Dictionary <string, string> properties = new Dictionary <string, string>(); // Add endpoint uri for all requests except 'groups' if (!string.IsNullOrEmpty(request.RequestUri.AbsoluteUri) && descriptor.Method != "groups") { properties.Add("endpointUri", request.RequestUri.AbsoluteUri); } ServiceEventSource.Current.Message($"Exception: {ex.ToString()}"); _StaticLogger.LogError(ex, ex.Message, properties); throw; } ProxyResponse(result, response); // Log body for post calls/message if available. While this is not really responseCode value, // this is very useful for debugging. string responseCode = string.Format("StatusCode:{0}", response.StatusCode); if (!string.IsNullOrEmpty(result.Message)) { responseCode = string.Format("{0}, Message:{1}", responseCode, result.Message); } // Log endpoint uri (e.g. http://10.0.0.5:20097) except groups calls. if (!string.IsNullOrEmpty(request.RequestUri.AbsoluteUri) && descriptor.Method != "groups") { responseCode = string.Format("{0}, EndpointUri:{1}", responseCode, request.RequestUri.AbsoluteUri); } ServiceEventSource.Current.Message($"Response: {responseCode}"); _StaticLogger.LogInformation($"ResponseCode: {responseCode}; response.IsSuccessStatusCode: {response.IsSuccessStatusCode}"); return(result); }
public void GetParameters() { var req = RequestDescriptor.Create(new { param = new { x = "1ф", y = "2 ф+1" } }); Assert.AreEqual("http://127.0.0.1/?x=1ф&y=2 ф%2B1", req.Uri.ToString()); }
public void GetParametersJsonMode() { var req = RequestDescriptor.Create(new { enc = "json", param = new { x = "1ф", y = "2 ф+1" } }); Assert.AreEqual("http://127.0.0.1/?{\"x\":\"1ф\"%2C\"y\":\"2 ф%2B1\"}", req.Uri.ToString()); }
public static string BuildUrl(this RequestDescriptor requestDescriptor, Dictionary <string, object> context = null) { var url = requestDescriptor.Href; if (requestDescriptor.Templated && context?.Count > 0) { foreach (var entry in context) { var filter = new Regex(@"\{" + entry.Key + @"\??\}", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); url = filter.Replace(url, $"{UrlEncode(entry.Value.ToString())}"); } } return(OptionalRouteFilter.Replace(url, string.Empty)); }
public void FormData() { var req = RequestDescriptor.Create(new { method = "POST", param = new { x = "1ф", y = "2 ф+1" } }); Assert.AreEqual("POST", req.Method); Assert.AreEqual("x=1%D1%84&y=2%20%D1%84%2B1", req.PostData); Assert.AreEqual("http://127.0.0.1/", req.Uri.ToString()); }
public void PostData() { var req = RequestDescriptor.Create(new { param = new { a = 1, b = 2 }, data = new { x = "1ф", y = "2 ф+1" } }); Assert.AreEqual("POST", req.Method); Assert.AreEqual("{\"x\":\"1ф\",\"y\":\"2 ф+1\"}", req.PostData); Assert.AreEqual("http://127.0.0.1/?a=1&b=2", req.Uri.ToString()); }
public static HttpRequestMessage BuildRequest(this RequestDescriptor requestDescriptor, Dictionary <string, object> context = null) { var fullUrl = requestDescriptor.BuildFullUri(context); var request = new HttpRequestMessage { RequestUri = new Uri(fullUrl, UriKind.RelativeOrAbsolute) }; switch (requestDescriptor.Method) { case "POST": request.Method = HttpMethod.Post; break; case "DELETE": request.Method = HttpMethod.Delete; break; case "PUT": request.Method = HttpMethod.Put; break; case "HEAD": request.Method = HttpMethod.Head; break; case "OPTIONS": request.Method = HttpMethod.Options; break; case "TRACE": request.Method = HttpMethod.Trace; break; default: request.Method = HttpMethod.Get; break; } return(request); }
public static string BuildFullUri(this RequestDescriptor requestDescriptor, Dictionary <string, object> context = null) { var url = requestDescriptor.BuildUrl(context); var queryString = requestDescriptor.BuildQueryString(context); var fullUrl = url; if (!string.IsNullOrWhiteSpace(queryString)) { var joinSymbol = "?"; if (url.IndexOf("?", StringComparison.InvariantCultureIgnoreCase) >= 0) { joinSymbol = "&"; } fullUrl = $"{url}{joinSymbol}{queryString}"; } return(fullUrl); }
private async Task <ApiResult> Query(HttpRequestMessage request, string application, string service, string method, HttpMethod httpMethod) { var roles = ((ClaimsIdentity)User.Identity).Claims .Where(c => c.Type == ClaimTypes.Role) .Select(c => c.Value).ToList(); var clientId = $"{ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value}.{ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid")?.Value}"; if (roles.Intersect(_AllowedUserRoles).Any() || _ClientWhitelist.Contains(clientId)) { // Merge original headers with custom headers // Note: currently gets only the first value for a particular header Dictionary <string, string> headers = request.Headers != null ? request.Headers .Where(e => e.Key.StartsWith("X-")) .ToDictionary(e => e.Key, e => e.Value.FirstOrDefault()) : new Dictionary <string, string>(); foreach (KeyValuePair <string, string> entry in FetchUserHeaders()) { headers[entry.Key] = entry.Value; } RequestDescriptor descriptor = new RequestDescriptor { HttpMethod = httpMethod, Application = application, Service = service, Method = method, QueryString = request.RequestUri.Query + string.Format("&Timeout={0}", _DefaultHttpTimeoutSecs),//set a timeout for reverseProxy Body = httpMethod == HttpMethod.Post ? (await request.Content.ReadAsStringAsync()) : null, Headers = headers }; return(await MakeRequestUsingReverseProxy(descriptor, new ServicePartitionKey())); } else { return(ApiResult.CreateError(string.Join(" or ", _AllowedUserRoles) + " role required.")); } }
public static string BuildQueryString(this RequestDescriptor requestDescriptor, Dictionary <string, object> context = null) { var parts = new List <string>(); if (context?.Count > 0) { if (context.TryGetValue("hostOrigin", out var hostOrigin)) { parts.Add($"hostOrigin={UrlEncode(hostOrigin.ToString())}"); } foreach (var property in requestDescriptor.Properties ?? Enumerable.Empty <RequestDescriptorProperty>()) { if (context.TryGetValue(property.Name, out var propertyValue)) { parts.Add($"{property.Name}={UrlEncode(propertyValue.ToString())}"); } } } return(string.Join("&", parts)); }
public override List <T> Get(RequestDescriptor request, int row = -1) { List <T> res = new List <T>(); T a = null; string condition = "WHERE `" + request.PropertyName + "`"; switch (request.Op) { case RequestOperator.Equal: condition += " = "; break; case RequestOperator.NotEqual: condition += " != "; break; case RequestOperator.Greater: condition += " > "; break; case RequestOperator.GreaterOrEqual: condition += " >= "; break; case RequestOperator.Less: condition += " < "; break; case RequestOperator.LessOrEqual: condition += " <= "; break; case RequestOperator.And: condition += " AND "; break; case RequestOperator.Or: condition += " OR "; break; } condition += "'" + request.Value + "' "; var reader = ExecuteReader("SELECT * FROM `" + Descriptor.ModelTypeName + "` " + condition + (row == -1 ? "" : "LIMIT " + row + "," + Config.GetAllSize)); do { a = Read(reader); if (a != null) { res.Add(a); } } while (a != null); return(res); }
/// <summary> /// Create request to other microservices /// </summary> /// <returns></returns> private HttpRequestMessage CreateMicroserviceRequest(Uri serviceUri, RequestDescriptor descriptor) { // Construct URI base path UriBuilder apiUri = new UriBuilder(new Uri(serviceUri, $"api/{descriptor.Method}")); // Add query string to URI if one was given if (!string.IsNullOrEmpty(descriptor.QueryString)) { // Have to slice the ? off apiUri.Query = descriptor.QueryString.Substring(1); } // Build HTTP request HttpRequestMessage request = new HttpRequestMessage { RequestUri = apiUri.Uri, Method = descriptor.HttpMethod }; // Attach body if one was given. Assumes body is application/json. if (!string.IsNullOrEmpty(descriptor.Body)) { request.Content = new StringContent(descriptor.Body, Encoding.UTF8, "application/json"); } // Attach headers if any are given if (descriptor.Headers != null) { foreach (KeyValuePair <string, string> entry in descriptor.Headers) { request.Headers.Add(entry.Key, entry.Value); } } return(request); }
public override List <T> Get(RequestDescriptor request, int row = -1) { List <T> res = new List <T>(); T a = null; var reader = new TestDataReader(Datas.Values.ToArray()); PropertyDescriptor descriptor = null; try { foreach (var p in Descriptor.Props) { if (p.Name.Equals(request.PropertyName)) { descriptor = p; break; } } if (descriptor == null) { return(res); } do { a = Read(reader); if (a != null) { bool match = false; object value = Descriptor.GetValue(a, descriptor.Name); switch (request.Op) { case RequestOperator.Equal: match = value == null ? value == request.Value : value.Equals(request.Value); break; case RequestOperator.NotEqual: match = value == null ? value != request.Value : !value.Equals(request.Value); break; case RequestOperator.Greater: match = (double)value > (double)request.Value; break; case RequestOperator.GreaterOrEqual: match = (double)value >= (double)request.Value; break; case RequestOperator.Less: match = (double)value < (double)request.Value; break; case RequestOperator.LessOrEqual: match = (double)value <= (double)request.Value; break; case RequestOperator.And: match = (bool)value && (bool)request.Value; break; case RequestOperator.Or: match = (bool)value || (bool)request.Value; break; } if (match) { res.Add(a); } } } while (a != null); } catch (Exception e) { throw new RequestException(request, descriptor, a, "Error in request processing:\n" + e.ToString()); } if (row != -1) { if (res.Count >= row) { res.RemoveRange(0, row); } if (Config.GetAllSize < res.Count) { res.RemoveRange(Config.GetAllSize, res.Count - Config.GetAllSize); } } return(res); }
/// <summary> /// /// </summary> /// <param name="client"></param> /// <param name="descriptor"></param> /// <param name="token"></param> /// <returns></returns> public static async Task SendAsync(this IHttpClientWrapper client, RequestDescriptor descriptor, CancellationToken token = default) { await client.SendAndWrapAsync(descriptor, token); }
private static void AddTimeoutHeader(this ClientConfiguration configuration, HttpRequestMessage request, RequestDescriptor requestDescriptor = null) { request.Headers.Remove("Timeout"); var timeoutMs = configuration.DefaultTimeoutMs.ToString(CultureInfo.InvariantCulture); if (requestDescriptor != null && requestDescriptor.TimeoutMs > 0) { timeoutMs = requestDescriptor.TimeoutMs.ToString(CultureInfo.InvariantCulture); } request.Headers.Add("Timeout", timeoutMs); }
private static HttpRequestMessage BuildRequestWithHeaders(this ClientConfiguration configuration, RequestDescriptor requestDescriptor, string hostOrigin, Dictionary <string, object> context = null) { var safeContext = context ?? new Dictionary <string, object>(); if (hostOrigin != null) { safeContext["hostOrigin"] = hostOrigin; } var request = requestDescriptor.BuildRequest(safeContext); configuration.AddConfigurationVersionIdHeader(request); configuration.AddTimeoutHeader(request, requestDescriptor); return(request); }
/// <summary> /// /// </summary> /// <typeparam name="TOutData"></typeparam> /// <param name="client"></param> /// <param name="descriptor"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <TOutData> SendAsync <TOutData>(this IHttpClientWrapper client, RequestDescriptor descriptor, CancellationToken token = default) { var response = await client.SendAndWrapAsync <TOutData>(descriptor, token); return(response.Data); }
public RequestException(RequestDescriptor request, PropertyDescriptor property, DataModel model, string message) : base(message) { Request = request; Property = property; Model = model; }