/// <summary> /// Internal method for copying cookies from an HttpRequest to an HttpRequestMessage's headers /// NOTE: Assumes that the HttpClientHandler is set as such /// <code> /// services.AddHttpClient<ColorApiClient>(options => { // options.BaseAddress = new Uri(SOME_URI); // }).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { // UseCookies = false // }); /// </code> /// </summary> /// <param name="msg"></param> /// <param name="req"></param> /// <param name="options"></param> /// <returns></returns> public static HttpRequestMessage CopyCookies(this HttpRequestMessage msg, HttpRequest req, RequestForwardingOptions options = null) { options ??= new RequestForwardingOptions(); if (req.Cookies != null && req.Cookies.Count > 0) { var sb = new StringBuilder(); foreach (var cookie in req.Cookies.Where(c => options.CookiesToForward.Contains(c.Key))) { sb.Append(cookie.Key); sb.Append("="); sb.Append(cookie.Value); sb.Append("; "); } msg.Headers.Add("Cookie", sb.ToString().TrimEnd()); } return(msg); }
/// <summary> /// Internal method for copying Headers from an HttpRequest to an HttpRequestMessage /// </summary> /// <param name="msg"></param> /// <param name="req"></param> /// <param name="options"></param> /// <returns></returns> public static HttpRequestMessage CopyHeaders(this HttpRequestMessage msg, HttpRequest req, RequestForwardingOptions options = null) { options ??= new RequestForwardingOptions(); var headers = req.Headers.Where(h => options.HeadersToForward.Contains(h.Key)); foreach (var header in headers) { if (header.Key.StartsWith(":")) { msg.Headers.Add(header.Key.Substring(1), header.Value.AsEnumerable()); } else { msg.Headers.Add(header.Key, header.Value.AsEnumerable()); } } return(msg); }
/// <summary> /// Internal method for copying Headers from an HttpRequest to an HttpRequestMessage /// </summary> /// <param name="msg"></param> /// <param name="req"></param> /// <param name="client"></param> /// <param name="options"></param> /// <returns></returns> public static HttpRequestMessage CopyHeaders(this HttpRequestMessage msg, HttpRequest req, HttpClient client, RequestForwardingOptions options = null) { options ??= new RequestForwardingOptions(); var currentHeaders = client.DefaultRequestHeaders.Select(x => x.Key); var headers = req.Headers.Where(h => options.HeadersToForward.Contains(h.Key) && !currentHeaders.Contains(h.Key)); foreach (var header in headers) { if (header.Key.StartsWith(":")) { msg.Headers.Add(header.Key.Substring(1), header.Value.AsEnumerable()); } else { msg.Headers.Add(header.Key, header.Value.AsEnumerable()); } } msg.Headers.Host = client.BaseAddress.Host; return(msg); }
/// <summary> /// Internal method for building an HttpRequestMessage from a parent HttpRequest /// </summary> /// <param name="httpRequest"></param> /// <param name="client"></param> /// <param name="options"></param> /// <returns></returns> private static HttpRequestMessage ToHttpRequestMessage <TRequestBody>(this HttpRequest httpRequest, HttpClient client, TRequestBody body, RequestForwardingOptions options = null) { var msg = new HttpRequestMessage(); msg .CopyMethod(httpRequest) .CopyHeaders(httpRequest, client, options) .CopyCookies(httpRequest, options); if (options?.ForwardQueryString ?? true) { msg.CopyQueryString(httpRequest); } msg.AddJsonContent(body); return(msg); }
/// <summary> /// Forwards a request through the provided HttpClient to another endpoint. /// NOTE: This overload of the Forward method takes a TRequestBody object representing a request body /// and returns a TResponseBody object representing the response body. The method is /// particularly well-suited for PATCH scenarios. /// </summary> /// <typeparam name="TRequestBody">The type of the request body</typeparam> /// <typeparam name="TResponseBody">The type of the response body</typeparam> /// <param name="client">The HttpClient making the request</param> /// <param name="request">The incoming HttpRequest object</param> /// <param name="relativeUrlFromBase">Relative URL from the HttpClient's base url</param> /// <param name="body">The request body (prior to serialization)</param> /// <param name="options">Optionally specify certain aspects of the request to copy</param> /// <returns>A ObjectResult consisting of a status code and a deserialized response body.</returns> /// <see cref="Forward{TRequestBody,TResponseBody}(HttpClient, HttpRequest, string, TRequestBody, RequestForwardingOptions)"/> public static async Task <ObjectResult <TResponseBody> > ForwardAsync <TRequestBody, TResponseBody>(this HttpClient client, HttpRequest request, string relativeUrlFromBase, TRequestBody body, RequestForwardingOptions options = null) { var msg = request.ToHttpRequestMessage(client, body, options); var url = relativeUrlFromBase + (msg.Properties["QueryString"] ?? ""); return(await ForwardRequestAsync <TResponseBody>(client, msg, url)); }
/// <summary> /// Forwards a request through the provided HttpClient to another endpoint. /// NOTE: This overload of the Forward method takes a TRequestBody object representing a request body /// and returns a TResponseBody object representing the response body. The method is /// particularly well-suited for PATCH scenarios. /// </summary> /// <typeparam name="TRequestBody">The type of the request body</typeparam> /// <typeparam name="TResponseBody">The type of the response body</typeparam> /// <param name="client">The HttpClient making the request</param> /// <param name="request">The incoming HttpRequest object</param> /// <param name="relativeUrlFromBase">Relative URL from the HttpClient's base url</param> /// <param name="body">The request body (prior to serialization)</param> /// <param name="options">Optionally specify certain aspects of the request to copy</param> /// <returns>A ObjectResult consisting of a status code and a deserialized response body.</returns> /// <see cref="ForwardAsync{TRequestBody,TResponseBody}(HttpClient, HttpRequest, string, TRequestBody, RequestForwardingOptions)"/> public static ObjectResult <TResponseBody> Forward <TRequestBody, TResponseBody>(this HttpClient client, HttpRequest request, string relativeUrlFromBase, TRequestBody body, RequestForwardingOptions options = null) => ForwardAsync <TRequestBody, TResponseBody>(client, request, relativeUrlFromBase, body, options).Result;