/// <summary> /// Provides all logic for constructing a new RestSharp <see cref="RestRequest"/>. /// At this point, all information for querying the service is known. Here, it is simply /// mapped into the RestSharp request. /// </summary> /// <param name="method">The http verb.</param> /// <param name="path">The target path (or resource).</param> /// <param name="options">The additional request options.</param> /// <param name="configuration">A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method.</param> /// <returns>[private] A new RestRequest instance.</returns> /// <exception cref="ArgumentNullException"></exception> private RestRequest NewRequest( HttpMethod method, string path, RequestOptions options, IReadableConfiguration configuration) { if (path == null) { throw new ArgumentNullException("path"); } if (options == null) { throw new ArgumentNullException("options"); } if (configuration == null) { throw new ArgumentNullException("configuration"); } RestRequest request = new RestRequest(Method(method)) { Resource = path, JsonSerializer = new CustomJsonCodec(SerializerSettings, configuration) }; if (options.PathParameters != null) { foreach (var pathParam in options.PathParameters) { request.AddParameter(pathParam.Key, pathParam.Value, ParameterType.UrlSegment); } } if (options.QueryParameters != null) { foreach (var queryParam in options.QueryParameters) { foreach (var value in queryParam.Value) { request.AddQueryParameter(queryParam.Key, value); } } } if (configuration.DefaultHeaders != null) { foreach (var headerParam in configuration.DefaultHeaders) { request.AddHeader(headerParam.Key, headerParam.Value); } } if (options.HeaderParameters != null) { foreach (var headerParam in options.HeaderParameters) { foreach (var value in headerParam.Value) { request.AddHeader(headerParam.Key, value); } } } if (options.FormParameters != null) { foreach (var formParam in options.FormParameters) { request.AddParameter(formParam.Key, formParam.Value); } } if (options.Data != null) { if (options.Data is Stream stream) { var contentType = "application/octet-stream"; if (options.HeaderParameters != null) { var contentTypes = options.HeaderParameters["Content-Type"]; contentType = contentTypes[0]; } var bytes = ClientUtils.ReadAsBytes(stream); request.AddParameter(contentType, bytes, ParameterType.RequestBody); } else { if (options.HeaderParameters != null) { var contentTypes = options.HeaderParameters["Content-Type"]; if (contentTypes == null || contentTypes.Any(header => header.Contains("application/json"))) { request.RequestFormat = DataFormat.Json; } else { // TODO: Generated client user should add additional handlers. RestSharp only supports XML and JSON, with XML as default. } } else { // Here, we'll assume JSON APIs are more common. XML can be forced by adding produces/consumes to openapi spec explicitly. request.RequestFormat = DataFormat.Json; } request.AddJsonBody(options.Data); } } if (options.FileParameters != null) { foreach (var fileParam in options.FileParameters) { var bytes = ClientUtils.ReadAsBytes(fileParam.Value); var fileStream = fileParam.Value as FileStream; if (fileStream != null) { request.Files.Add(FileParameter.Create(fileParam.Key, bytes, System.IO.Path.GetFileName(fileStream.Name))); } else { request.Files.Add(FileParameter.Create(fileParam.Key, bytes, "no_file_name_provided")); } } } if (options.Cookies != null && options.Cookies.Count > 0) { foreach (var cookie in options.Cookies) { request.AddCookie(cookie.Name, cookie.Value); } } return(request); }
/// <summary> /// Provides all logic for constructing a new HttpRequestMessage. /// At this point, all information for querying the service is known. Here, it is simply /// mapped into the a HttpRequestMessage. /// </summary> /// <param name="method">The http verb.</param> /// <param name="path">The target path (or resource).</param> /// <param name="options">The additional request options.</param> /// <param name="configuration">A per-request configuration object. It is assumed that any merge with /// GlobalConfiguration has been done before calling this method.</param> /// <returns>[private] A new HttpRequestMessage instance.</returns> /// <exception cref="ArgumentNullException"></exception> private HttpRequestMessage NewRequest( HttpMethod method, String path, RequestOptions options, IReadableConfiguration configuration) { if (path == null) { throw new ArgumentNullException("path"); } if (options == null) { throw new ArgumentNullException("options"); } if (configuration == null) { throw new ArgumentNullException("configuration"); } WebRequestPathBuilder builder = new WebRequestPathBuilder(_baseUrl, path); builder.AddPathParameters(options.PathParameters); // In case of POST or PUT pass query parameters in request body if (method != HttpMethod.Post && method != HttpMethod.Put) { builder.AddQueryParameters(options.QueryParameters); } HttpRequestMessage request = new HttpRequestMessage(method, builder.GetFullUri()); if (configuration.DefaultHeaders != null) { foreach (var headerParam in configuration.DefaultHeaders) { request.Headers.Add(headerParam.Key, headerParam.Value); } } if (options.HeaderParameters != null) { foreach (var headerParam in options.HeaderParameters) { foreach (var value in headerParam.Value) { // Todo make content headers actually content headers request.Headers.TryAddWithoutValidation(headerParam.Key, value); } } } List <Tuple <HttpContent, string, string> > contentList = new List <Tuple <HttpContent, string, string> >(); if (options.FormParameters != null && options.FormParameters.Count > 0) { contentList.Add(new Tuple <HttpContent, string, string>(new FormUrlEncodedContent(options.FormParameters), null, null)); } if (options.Data != null) { var serializer = new CustomJsonCodec(SerializerSettings, configuration); contentList.Add( new Tuple <HttpContent, string, string>(new StringContent(serializer.Serialize(options.Data), new UTF8Encoding(), "application/json"), null, null)); } if (options.FileParameters != null && options.FileParameters.Count > 0) { foreach (var fileParam in options.FileParameters) { var bytes = ClientUtils.ReadAsBytes(fileParam.Value); var fileStream = fileParam.Value as FileStream; contentList.Add(new Tuple <HttpContent, string, string>(new ByteArrayContent(bytes), fileParam.Key, fileStream?.Name ?? "no_file_name_provided")); } } if (contentList.Count > 1) { string boundary = "---------" + Guid.NewGuid().ToString().ToUpperInvariant(); var multipartContent = new MultipartFormDataContent(boundary); foreach (var content in contentList) { if (content.Item2 != null) { multipartContent.Add(content.Item1, content.Item2, content.Item3); } else { multipartContent.Add(content.Item1); } } request.Content = multipartContent; } else { request.Content = contentList.FirstOrDefault()?.Item1; } // TODO provide an alternative that allows cookies per request instead of per API client if (options.Cookies != null && options.Cookies.Count > 0) { request.Properties["CookieContainer"] = options.Cookies; } return(request); }