forked from loafle/openapi-generator-original
Add ApiClient.mustache for http client library (#8859)
* add api client mustache for http client * clean up api client template for restsharp * test c# httpclient in appveyor * remove apiclient.cs * regenerate apiclient.cs * set library for http client * remove Libraries * use libraries folder
This commit is contained in:
parent
16e7408eb7
commit
f7b2baf38e
@ -43,6 +43,8 @@ build_script:
|
||||
- dotnet build samples\server\petstore\aspnetcore-3.0\Org.OpenAPITools.sln
|
||||
# build C# aspnetcore 2.2 server
|
||||
- dotnet build samples\server\petstore\aspnetcore\Org.OpenAPITools.sln
|
||||
# build C# API client (httpclient)
|
||||
- dotnet build samples\client\petstore\csharp-netcore\OpenAPIClient-httpclient\Org.OpenAPITools.sln
|
||||
# build C# API client (netcore)
|
||||
- dotnet build samples\client\petstore\csharp-netcore\OpenAPIClient\Org.OpenAPITools.sln
|
||||
- dotnet build samples\client\petstore\csharp-netcore\OpenAPIClientCore\Org.OpenAPITools.sln
|
||||
@ -64,6 +66,8 @@ build_script:
|
||||
# run the locally installed openapi-generator-gradle-plugin
|
||||
- gradle -b modules\openapi-generator-gradle-plugin\samples\local-spec\build.gradle buildGoSdk --stacktrace
|
||||
test_script:
|
||||
# test c# API client (httpclient)
|
||||
- dotnet test samples\client\petstore\csharp-netcore\OpenAPIClient-httpclient\src\Org.OpenAPITools.Test\Org.OpenAPITools.Test.csproj
|
||||
# test c# API client (netcore)
|
||||
- dotnet test samples\client\petstore\csharp-netcore\OpenAPIClientCore\src\Org.OpenAPITools.Test\Org.OpenAPITools.Test.csproj
|
||||
- dotnet test samples\client\petstore\csharp-netcore\OpenAPIClient\src\Org.OpenAPITools.Test\Org.OpenAPITools.Test.csproj
|
||||
|
@ -583,8 +583,11 @@ public class CSharpNetCoreClientCodegen extends AbstractCSharpCodegen {
|
||||
additionalProperties.put("useRestSharp", true);
|
||||
needsCustomHttpMethod = true;
|
||||
} else if (HTTPCLIENT.equals(getLibrary())) {
|
||||
setLibrary(HTTPCLIENT);
|
||||
additionalProperties.put("useHttpClient", true);
|
||||
needsUriBuilder = true;
|
||||
} else {
|
||||
throw new RuntimeException("Invalid HTTP library " + getLibrary() + ". Only restsharp, httpclient are supported.");
|
||||
}
|
||||
|
||||
String framework = (String) additionalProperties.getOrDefault(CodegenConstants.DOTNET_FRAMEWORK, defaultFramework.name);
|
||||
@ -607,7 +610,6 @@ public class CSharpNetCoreClientCodegen extends AbstractCSharpCodegen {
|
||||
}
|
||||
|
||||
strategy.configureAdditionalProperties(additionalProperties);
|
||||
|
||||
setTargetFrameworkNuget(strategy.getNugetFrameworkIdentifier());
|
||||
setTargetFramework(strategy.name);
|
||||
setTestTargetFramework(strategy.testTargetFramework);
|
||||
|
@ -20,17 +20,12 @@ using System.Web;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||
{{#useRestSharp}}
|
||||
using RestSharp;
|
||||
using RestSharp.Deserializers;
|
||||
using RestSharpMethod = RestSharp.Method;
|
||||
{{/useRestSharp}}
|
||||
{{#useWebRequest}}
|
||||
using System.Net.Http;
|
||||
{{/useWebRequest}}
|
||||
{{#useHttpClient}}
|
||||
using System.Net.Http;
|
||||
{{/useHttpClient}}
|
||||
{{#supportsRetry}}
|
||||
using Polly;
|
||||
{{/supportsRetry}}
|
||||
@ -40,7 +35,7 @@ namespace {{packageName}}.Client
|
||||
/// <summary>
|
||||
/// Allows RestSharp to Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON.
|
||||
/// </summary>
|
||||
internal class CustomJsonCodec {{#useRestSharp}} : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer {{/useRestSharp}}
|
||||
internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer
|
||||
{
|
||||
private readonly IReadableConfiguration _configuration;
|
||||
private static readonly string _contentType = "application/json";
|
||||
@ -86,12 +81,7 @@ namespace {{packageName}}.Client
|
||||
}
|
||||
}
|
||||
|
||||
{{#useRestSharp}}
|
||||
public T Deserialize<T>(IRestResponse response)
|
||||
{{/useRestSharp}}
|
||||
{{#useHttpClient}}
|
||||
public T Deserialize<T>(HttpResponseMessage response)
|
||||
{{/useHttpClient}}
|
||||
{
|
||||
var result = (T)Deserialize(response, typeof(T));
|
||||
return result;
|
||||
@ -103,36 +93,19 @@ namespace {{packageName}}.Client
|
||||
/// <param name="response">The HTTP response.</param>
|
||||
/// <param name="type">Object type.</param>
|
||||
/// <returns>Object representation of the JSON string.</returns>
|
||||
{{#useRestSharp}}
|
||||
internal object Deserialize(IRestResponse response, Type type)
|
||||
{
|
||||
IList<Parameter> headers = response.Headers;
|
||||
{{/useRestSharp}}
|
||||
{{#useHttpClient}}
|
||||
internal object Deserialize(HttpResponseMessage response, Type type)
|
||||
{
|
||||
IList<string> headers = response.Headers.Select(x => x.Key + "=" + x.Value).ToList();
|
||||
{{/useHttpClient}}
|
||||
|
||||
if (type == typeof(byte[])) // return byte array
|
||||
{
|
||||
{{#useRestSharp}}
|
||||
return response.RawBytes;
|
||||
{{/useRestSharp}}
|
||||
{{#useHttpClient}}
|
||||
return response.Content.ReadAsByteArrayAsync().Result;
|
||||
{{/useHttpClient}}
|
||||
}
|
||||
|
||||
// TODO: ? if (type.IsAssignableFrom(typeof(Stream)))
|
||||
if (type == typeof(Stream))
|
||||
{
|
||||
{{#useRestSharp}}
|
||||
var bytes = response.RawBytes;
|
||||
{{/useRestSharp}}
|
||||
{{#useHttpClient}}
|
||||
var bytes = response.Content.ReadAsByteArrayAsync().Result;
|
||||
{{/useHttpClient}}
|
||||
if (headers != null)
|
||||
{
|
||||
var filePath = String.IsNullOrEmpty(_configuration.TempFolderPath)
|
||||
@ -156,33 +129,18 @@ namespace {{packageName}}.Client
|
||||
|
||||
if (type.Name.StartsWith("System.Nullable`1[[System.DateTime")) // return a datetime object
|
||||
{
|
||||
{{#useRestSharp}}
|
||||
return DateTime.Parse(response.Content, null, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
{{/useRestSharp}}
|
||||
{{#useHttpClient}}
|
||||
return DateTime.Parse(response.Content.ReadAsStringAsync().Result, null, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
{{/useHttpClient}}
|
||||
}
|
||||
|
||||
if (type == typeof(String) || type.Name.StartsWith("System.Nullable")) // return primitive type
|
||||
{
|
||||
{{#useRestSharp}}
|
||||
return Convert.ChangeType(response.Content, type);
|
||||
{{/useRestSharp}}
|
||||
{{#useHttpClient}}
|
||||
return Convert.ChangeType(response.Content.ReadAsStringAsync().Result, type);
|
||||
{{/useHttpClient}}
|
||||
}
|
||||
|
||||
// at this point, it must be a model (json)
|
||||
try
|
||||
{
|
||||
{{#useRestSharp}}
|
||||
return JsonConvert.DeserializeObject(response.Content, type, _serializerSettings);
|
||||
{{/useRestSharp}}
|
||||
{{#useHttpClient}}
|
||||
return JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result, type, _serializerSettings);
|
||||
{{/useHttpClient}}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -208,12 +166,6 @@ namespace {{packageName}}.Client
|
||||
{{>visibility}} partial class ApiClient : ISynchronousClient{{#supportsAsync}}, IAsynchronousClient{{/supportsAsync}}
|
||||
{
|
||||
private readonly String _baseUrl;
|
||||
{{#useHttpClient}}
|
||||
{{#reUseHttpClient}}
|
||||
private readonly HttpClientHandler _httpClientHandler;
|
||||
private readonly HttpClient _httpClient;
|
||||
{{/reUseHttpClient}}
|
||||
{{/useHttpClient}}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the settings on a <see cref="JsonSerializer" /> object.
|
||||
@ -231,7 +183,7 @@ namespace {{packageName}}.Client
|
||||
}
|
||||
}
|
||||
};
|
||||
{{#useRestSharp}}
|
||||
|
||||
/// <summary>
|
||||
/// Allows for extending request processing for <see cref="ApiClient"/> generated code.
|
||||
/// </summary>
|
||||
@ -244,7 +196,6 @@ namespace {{packageName}}.Client
|
||||
/// <param name="request">The RestSharp request object</param>
|
||||
/// <param name="response">The RestSharp response object</param>
|
||||
partial void InterceptResponse(IRestRequest request, IRestResponse response);
|
||||
{{/useRestSharp}}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiClient" />, defaulting to the global configurations' base url.
|
||||
@ -252,12 +203,6 @@ namespace {{packageName}}.Client
|
||||
public ApiClient()
|
||||
{
|
||||
_baseUrl = {{packageName}}.Client.GlobalConfiguration.Instance.BasePath;
|
||||
{{#useHttpClient}}
|
||||
{{#reUseHttpClient}}
|
||||
_httpClientHandler = new HttpClientHandler();
|
||||
_httpClient = new HttpClient(_httpClientHandler);
|
||||
{{/reUseHttpClient}}
|
||||
{{/useHttpClient}}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -271,15 +216,8 @@ namespace {{packageName}}.Client
|
||||
throw new ArgumentException("basePath cannot be empty");
|
||||
|
||||
_baseUrl = basePath;
|
||||
{{#useHttpClient}}
|
||||
{{#reUseHttpClient}}
|
||||
_httpClientHandler = new HttpClientHandler();
|
||||
_httpClient = new HttpClient(_httpClientHandler);
|
||||
{{/reUseHttpClient}}
|
||||
{{/useHttpClient}}
|
||||
}
|
||||
|
||||
{{#useRestSharp}}
|
||||
/// <summary>
|
||||
/// Constructs the RestSharp version of an http method
|
||||
/// </summary>
|
||||
@ -590,258 +528,8 @@ namespace {{packageName}}.Client
|
||||
}
|
||||
return result;
|
||||
}
|
||||
{{/useRestSharp}}
|
||||
|
||||
{{#useHttpClient}}
|
||||
/// <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;
|
||||
}
|
||||
|
||||
partial void InterceptRequest(HttpRequestMessage req, HttpClientHandler handler);
|
||||
partial void InterceptResponse(HttpRequestMessage req, HttpResponseMessage response);
|
||||
|
||||
private ApiResponse<T> ToApiResponse<T>(HttpResponseMessage response, object responseData, HttpClientHandler handler, Uri uri)
|
||||
{
|
||||
T result = (T) responseData;
|
||||
string rawContent = response.Content.ToString();
|
||||
|
||||
var transformed = new ApiResponse<T>(response.StatusCode, new Multimap<string, string>({{#caseInsensitiveResponseHeaders}}StringComparer.OrdinalIgnoreCase{{/caseInsensitiveResponseHeaders}}), result, rawContent)
|
||||
{
|
||||
ErrorText = response.ReasonPhrase,
|
||||
Cookies = new List<Cookie>()
|
||||
};
|
||||
|
||||
if (response.Headers != null)
|
||||
{
|
||||
foreach (var responseHeader in response.Headers)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
foreach (Cookie cookie in handler.CookieContainer.GetCookies(uri))
|
||||
{
|
||||
transformed.Cookies.Add(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
return transformed;
|
||||
}
|
||||
|
||||
private ApiResponse<T> Exec<T>(HttpRequestMessage req, IReadableConfiguration configuration)
|
||||
{
|
||||
return ExecAsync<T>(req, configuration).Result;
|
||||
}
|
||||
|
||||
private async Task<ApiResponse<T>> ExecAsync<T>(HttpRequestMessage req,
|
||||
IReadableConfiguration configuration,
|
||||
System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
{{^reUseHttpClient}}
|
||||
var handler = new HttpClientHandler();
|
||||
var client = new HttpClient();
|
||||
{{/reUseHttpClient}}
|
||||
{{#reUseHttpClient}}
|
||||
var handler = _httpClientHandler;
|
||||
var client = _httpClient;
|
||||
{{/reUseHttpClient}}
|
||||
var deserializer = new CustomJsonCodec(SerializerSettings, configuration);
|
||||
|
||||
var finalToken = cancellationToken;
|
||||
|
||||
if (configuration.Timeout > 0)
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource(configuration.Timeout);
|
||||
finalToken = CancellationTokenSource.CreateLinkedTokenSource(finalToken, tokenSource.Token).Token;
|
||||
}
|
||||
|
||||
if (configuration.Proxy != null)
|
||||
{
|
||||
handler.Proxy = configuration.Proxy;
|
||||
}
|
||||
|
||||
if (configuration.UserAgent != null)
|
||||
{
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", configuration.UserAgent);
|
||||
}
|
||||
|
||||
if (configuration.ClientCertificates != null)
|
||||
{
|
||||
handler.ClientCertificates.AddRange(configuration.ClientCertificates);
|
||||
}
|
||||
|
||||
var cookieContainer = req.Properties.ContainsKey("CookieContainer") ? req.Properties["CookieContainer"] as List<Cookie> : null;
|
||||
|
||||
if (cookieContainer != null)
|
||||
{
|
||||
foreach (var cookie in cookieContainer)
|
||||
{
|
||||
handler.CookieContainer.Add(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
InterceptRequest(req, handler);
|
||||
|
||||
HttpResponseMessage response;
|
||||
{{#supportsRetry}}
|
||||
if (RetryConfiguration.AsyncRetryPolicy != null)
|
||||
{
|
||||
var policy = RetryConfiguration.AsyncRetryPolicy;
|
||||
var policyResult = await policy
|
||||
.ExecuteAndCaptureAsync(() => client.SendAsync(req, cancellationToken))
|
||||
.ConfigureAwait(false);
|
||||
response = (policyResult.Outcome == OutcomeType.Successful) ?
|
||||
policyResult.Result : new HttpResponseMessage()
|
||||
{
|
||||
ReasonPhrase = policyResult.FinalException.ToString(),
|
||||
RequestMessage = req
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
{{/supportsRetry}}
|
||||
response = await client.SendAsync(req, cancellationToken).ConfigureAwait(false);
|
||||
{{#supportsRetry}}
|
||||
}
|
||||
{{/supportsRetry}}
|
||||
|
||||
object responseData = deserializer.Deserialize<T>(response);
|
||||
|
||||
// if the response type is oneOf/anyOf, call FromJSON to deserialize the data
|
||||
if (typeof({{{packageName}}}.{{modelPackage}}.AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
T instance = (T) Activator.CreateInstance(typeof(T));
|
||||
MethodInfo method = typeof(T).GetMethod("FromJson");
|
||||
method.Invoke(instance, new object[] {response.Content});
|
||||
responseData = instance;
|
||||
}
|
||||
else if (typeof(T).Name == "Stream") // for binary response
|
||||
{
|
||||
responseData = (T) (object) await response.Content.ReadAsStreamAsync();
|
||||
}
|
||||
|
||||
InterceptResponse(req, response);
|
||||
|
||||
var result = ToApiResponse<T>(response, responseData, handler, req.RequestUri);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
{{/useHttpClient}}
|
||||
|
||||
|
||||
|
||||
{{#supportsAsync}}
|
||||
{{#useRestSharp}}
|
||||
private async Task<ApiResponse<T>> ExecAsync<T>(RestRequest req, IReadableConfiguration configuration, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
RestClient client = new RestClient(_baseUrl);
|
||||
@ -960,7 +648,6 @@ namespace {{packageName}}.Client
|
||||
}
|
||||
return result;
|
||||
}
|
||||
{{/useRestSharp}}
|
||||
|
||||
#region IAsynchronousClient
|
||||
/// <summary>
|
||||
@ -1065,12 +752,7 @@ namespace {{packageName}}.Client
|
||||
public Task<ApiResponse<T>> PatchAsync<T>(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
{{#useRestSharp}}
|
||||
return ExecAsync<T>(NewRequest(HttpMethod.Patch, path, options, config), config, cancellationToken);
|
||||
{{/useRestSharp}}
|
||||
{{#useHttpClient}}
|
||||
return ExecAsync<T>(NewRequest(new HttpMethod("PATCH"), path, options, config), config, cancellationToken);
|
||||
{{/useHttpClient}}
|
||||
}
|
||||
#endregion IAsynchronousClient
|
||||
{{/supportsAsync}}
|
||||
@ -1171,12 +853,7 @@ namespace {{packageName}}.Client
|
||||
public ApiResponse<T> Patch<T>(string path, RequestOptions options, IReadableConfiguration configuration = null)
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
{{#useRestSharp}}
|
||||
return Exec<T>(NewRequest(HttpMethod.Patch, path, options, config), config);
|
||||
{{/useRestSharp}}
|
||||
{{#useHttpClient}}
|
||||
return Exec<T>(NewRequest(new HttpMethod("PATCH"), path, options, config), config);
|
||||
{{/useHttpClient}}
|
||||
}
|
||||
#endregion ISynchronousClient
|
||||
}
|
||||
|
669
modules/openapi-generator/src/main/resources/csharp-netcore/libraries/httpclient/ApiClient.mustache
vendored
Normal file
669
modules/openapi-generator/src/main/resources/csharp-netcore/libraries/httpclient/ApiClient.mustache
vendored
Normal file
@ -0,0 +1,669 @@
|
||||
{{>partial_header}}
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
{{^netStandard}}
|
||||
using System.Web;
|
||||
{{/netStandard}}
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||
{{#useWebRequest}}
|
||||
using System.Net.Http;
|
||||
{{/useWebRequest}}
|
||||
using System.Net.Http;
|
||||
{{#supportsRetry}}
|
||||
using Polly;
|
||||
{{/supportsRetry}}
|
||||
|
||||
namespace {{packageName}}.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// To Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON.
|
||||
/// </summary>
|
||||
internal class CustomJsonCodec
|
||||
{
|
||||
private readonly IReadableConfiguration _configuration;
|
||||
private static readonly string _contentType = "application/json";
|
||||
private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings
|
||||
{
|
||||
// OpenAPI generated types generally hide default constructors.
|
||||
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
|
||||
ContractResolver = new DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new CamelCaseNamingStrategy
|
||||
{
|
||||
OverrideSpecifiedNames = false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public CustomJsonCodec(IReadableConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public CustomJsonCodec(JsonSerializerSettings serializerSettings, IReadableConfiguration configuration)
|
||||
{
|
||||
_serializerSettings = serializerSettings;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize the object into a JSON string.
|
||||
/// </summary>
|
||||
/// <param name="obj">Object to be serialized.</param>
|
||||
/// <returns>A JSON string.</returns>
|
||||
public string Serialize(object obj)
|
||||
{
|
||||
if (obj != null && obj is {{{packageName}}}.{{modelPackage}}.AbstractOpenAPISchema)
|
||||
{
|
||||
// the object to be serialized is an oneOf/anyOf schema
|
||||
return (({{{packageName}}}.{{modelPackage}}.AbstractOpenAPISchema)obj).ToJson();
|
||||
}
|
||||
else
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj, _serializerSettings);
|
||||
}
|
||||
}
|
||||
|
||||
public T Deserialize<T>(HttpResponseMessage response)
|
||||
{
|
||||
var result = (T)Deserialize(response, typeof(T));
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize the JSON string into a proper object.
|
||||
/// </summary>
|
||||
/// <param name="response">The HTTP response.</param>
|
||||
/// <param name="type">Object type.</param>
|
||||
/// <returns>Object representation of the JSON string.</returns>
|
||||
internal object Deserialize(HttpResponseMessage response, Type type)
|
||||
{
|
||||
IList<string> headers = response.Headers.Select(x => x.Key + "=" + x.Value).ToList();
|
||||
|
||||
if (type == typeof(byte[])) // return byte array
|
||||
{
|
||||
return response.Content.ReadAsByteArrayAsync().Result;
|
||||
}
|
||||
|
||||
// TODO: ? if (type.IsAssignableFrom(typeof(Stream)))
|
||||
if (type == typeof(Stream))
|
||||
{
|
||||
var bytes = response.Content.ReadAsByteArrayAsync().Result;
|
||||
if (headers != null)
|
||||
{
|
||||
var filePath = String.IsNullOrEmpty(_configuration.TempFolderPath)
|
||||
? Path.GetTempPath()
|
||||
: _configuration.TempFolderPath;
|
||||
var regex = new Regex(@"Content-Disposition=.*filename=['""]?([^'""\s]+)['""]?$");
|
||||
foreach (var header in headers)
|
||||
{
|
||||
var match = regex.Match(header.ToString());
|
||||
if (match.Success)
|
||||
{
|
||||
string fileName = filePath + ClientUtils.SanitizeFilename(match.Groups[1].Value.Replace("\"", "").Replace("'", ""));
|
||||
File.WriteAllBytes(fileName, bytes);
|
||||
return new FileStream(fileName, FileMode.Open);
|
||||
}
|
||||
}
|
||||
}
|
||||
var stream = new MemoryStream(bytes);
|
||||
return stream;
|
||||
}
|
||||
|
||||
if (type.Name.StartsWith("System.Nullable`1[[System.DateTime")) // return a datetime object
|
||||
{
|
||||
return DateTime.Parse(response.Content.ReadAsStringAsync().Result, null, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
}
|
||||
|
||||
if (type == typeof(String) || type.Name.StartsWith("System.Nullable")) // return primitive type
|
||||
{
|
||||
return Convert.ChangeType(response.Content.ReadAsStringAsync().Result, type);
|
||||
}
|
||||
|
||||
// at this point, it must be a model (json)
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result, type, _serializerSettings);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ApiException(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public string RootElement { get; set; }
|
||||
public string Namespace { get; set; }
|
||||
public string DateFormat { get; set; }
|
||||
|
||||
public string ContentType
|
||||
{
|
||||
get { return _contentType; }
|
||||
set { throw new InvalidOperationException("Not allowed to set content type."); }
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Provides a default implementation of an Api client (both synchronous and asynchronous implementatios),
|
||||
/// encapsulating general REST accessor use cases.
|
||||
/// </summary>
|
||||
{{>visibility}} partial class ApiClient : ISynchronousClient{{#supportsAsync}}, IAsynchronousClient{{/supportsAsync}}
|
||||
{
|
||||
private readonly String _baseUrl;
|
||||
{{#reUseHttpClient}}
|
||||
private readonly HttpClientHandler _httpClientHandler;
|
||||
private readonly HttpClient _httpClient;
|
||||
{{/reUseHttpClient}}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the settings on a <see cref="JsonSerializer" /> object.
|
||||
/// These settings can be adjusted to accomodate custom serialization rules.
|
||||
/// </summary>
|
||||
public JsonSerializerSettings SerializerSettings { get; set; } = new JsonSerializerSettings
|
||||
{
|
||||
// OpenAPI generated types generally hide default constructors.
|
||||
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
|
||||
ContractResolver = new DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new CamelCaseNamingStrategy
|
||||
{
|
||||
OverrideSpecifiedNames = false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiClient" />, defaulting to the global configurations' base url.
|
||||
/// </summary>
|
||||
public ApiClient()
|
||||
{
|
||||
_baseUrl = {{packageName}}.Client.GlobalConfiguration.Instance.BasePath;
|
||||
{{#reUseHttpClient}}
|
||||
_httpClientHandler = new HttpClientHandler();
|
||||
_httpClient = new HttpClient(_httpClientHandler);
|
||||
{{/reUseHttpClient}}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiClient" />
|
||||
/// </summary>
|
||||
/// <param name="basePath">The target service's base path in URL format.</param>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public ApiClient(String basePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(basePath))
|
||||
throw new ArgumentException("basePath cannot be empty");
|
||||
|
||||
_baseUrl = basePath;
|
||||
{{#reUseHttpClient}}
|
||||
_httpClientHandler = new HttpClientHandler();
|
||||
_httpClient = new HttpClient(_httpClientHandler);
|
||||
{{/reUseHttpClient}}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
partial void InterceptRequest(HttpRequestMessage req, HttpClientHandler handler);
|
||||
partial void InterceptResponse(HttpRequestMessage req, HttpResponseMessage response);
|
||||
|
||||
private ApiResponse<T> ToApiResponse<T>(HttpResponseMessage response, object responseData, HttpClientHandler handler, Uri uri)
|
||||
{
|
||||
T result = (T) responseData;
|
||||
string rawContent = response.Content.ToString();
|
||||
|
||||
var transformed = new ApiResponse<T>(response.StatusCode, new Multimap<string, string>({{#caseInsensitiveResponseHeaders}}StringComparer.OrdinalIgnoreCase{{/caseInsensitiveResponseHeaders}}), result, rawContent)
|
||||
{
|
||||
ErrorText = response.ReasonPhrase,
|
||||
Cookies = new List<Cookie>()
|
||||
};
|
||||
|
||||
if (response.Headers != null)
|
||||
{
|
||||
foreach (var responseHeader in response.Headers)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
foreach (Cookie cookie in handler.CookieContainer.GetCookies(uri))
|
||||
{
|
||||
transformed.Cookies.Add(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
return transformed;
|
||||
}
|
||||
|
||||
private ApiResponse<T> Exec<T>(HttpRequestMessage req, IReadableConfiguration configuration)
|
||||
{
|
||||
return ExecAsync<T>(req, configuration).Result;
|
||||
}
|
||||
|
||||
private async Task<ApiResponse<T>> ExecAsync<T>(HttpRequestMessage req,
|
||||
IReadableConfiguration configuration,
|
||||
System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
{{^reUseHttpClient}}
|
||||
var handler = new HttpClientHandler();
|
||||
var client = new HttpClient();
|
||||
{{/reUseHttpClient}}
|
||||
{{#reUseHttpClient}}
|
||||
var handler = _httpClientHandler;
|
||||
var client = _httpClient;
|
||||
{{/reUseHttpClient}}
|
||||
var deserializer = new CustomJsonCodec(SerializerSettings, configuration);
|
||||
|
||||
var finalToken = cancellationToken;
|
||||
|
||||
if (configuration.Timeout > 0)
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource(configuration.Timeout);
|
||||
finalToken = CancellationTokenSource.CreateLinkedTokenSource(finalToken, tokenSource.Token).Token;
|
||||
}
|
||||
|
||||
if (configuration.Proxy != null)
|
||||
{
|
||||
handler.Proxy = configuration.Proxy;
|
||||
}
|
||||
|
||||
if (configuration.UserAgent != null)
|
||||
{
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", configuration.UserAgent);
|
||||
}
|
||||
|
||||
if (configuration.ClientCertificates != null)
|
||||
{
|
||||
handler.ClientCertificates.AddRange(configuration.ClientCertificates);
|
||||
}
|
||||
|
||||
var cookieContainer = req.Properties.ContainsKey("CookieContainer") ? req.Properties["CookieContainer"] as List<Cookie> : null;
|
||||
|
||||
if (cookieContainer != null)
|
||||
{
|
||||
foreach (var cookie in cookieContainer)
|
||||
{
|
||||
handler.CookieContainer.Add(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
InterceptRequest(req, handler);
|
||||
|
||||
HttpResponseMessage response;
|
||||
{{#supportsRetry}}
|
||||
if (RetryConfiguration.AsyncRetryPolicy != null)
|
||||
{
|
||||
var policy = RetryConfiguration.AsyncRetryPolicy;
|
||||
var policyResult = await policy
|
||||
.ExecuteAndCaptureAsync(() => client.SendAsync(req, cancellationToken))
|
||||
.ConfigureAwait(false);
|
||||
response = (policyResult.Outcome == OutcomeType.Successful) ?
|
||||
policyResult.Result : new HttpResponseMessage()
|
||||
{
|
||||
ReasonPhrase = policyResult.FinalException.ToString(),
|
||||
RequestMessage = req
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
{{/supportsRetry}}
|
||||
response = await client.SendAsync(req, cancellationToken).ConfigureAwait(false);
|
||||
{{#supportsRetry}}
|
||||
}
|
||||
{{/supportsRetry}}
|
||||
|
||||
object responseData = deserializer.Deserialize<T>(response);
|
||||
|
||||
// if the response type is oneOf/anyOf, call FromJSON to deserialize the data
|
||||
if (typeof({{{packageName}}}.{{modelPackage}}.AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
T instance = (T) Activator.CreateInstance(typeof(T));
|
||||
MethodInfo method = typeof(T).GetMethod("FromJson");
|
||||
method.Invoke(instance, new object[] {response.Content});
|
||||
responseData = instance;
|
||||
}
|
||||
else if (typeof(T).Name == "Stream") // for binary response
|
||||
{
|
||||
responseData = (T) (object) await response.Content.ReadAsStreamAsync();
|
||||
}
|
||||
|
||||
InterceptResponse(req, response);
|
||||
|
||||
var result = ToApiResponse<T>(response, responseData, handler, req.RequestUri);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
{{#supportsAsync}}
|
||||
#region IAsynchronousClient
|
||||
/// <summary>
|
||||
/// Make a HTTP GET request (async).
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="cancellationToken">Token that enables callers to cancel the request.</param>
|
||||
/// <returns>A Task containing ApiResponse</returns>
|
||||
public Task<ApiResponse<T>> GetAsync<T>(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return ExecAsync<T>(NewRequest(HttpMethod.Get, path, options, config), config, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP POST request (async).
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="cancellationToken">Token that enables callers to cancel the request.</param>
|
||||
/// <returns>A Task containing ApiResponse</returns>
|
||||
public Task<ApiResponse<T>> PostAsync<T>(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return ExecAsync<T>(NewRequest(HttpMethod.Post, path, options, config), config, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP PUT request (async).
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="cancellationToken">Token that enables callers to cancel the request.</param>
|
||||
/// <returns>A Task containing ApiResponse</returns>
|
||||
public Task<ApiResponse<T>> PutAsync<T>(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return ExecAsync<T>(NewRequest(HttpMethod.Put, path, options, config), config, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP DELETE request (async).
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="cancellationToken">Token that enables callers to cancel the request.</param>
|
||||
/// <returns>A Task containing ApiResponse</returns>
|
||||
public Task<ApiResponse<T>> DeleteAsync<T>(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return ExecAsync<T>(NewRequest(HttpMethod.Delete, path, options, config), config, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP HEAD request (async).
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="cancellationToken">Token that enables callers to cancel the request.</param>
|
||||
/// <returns>A Task containing ApiResponse</returns>
|
||||
public Task<ApiResponse<T>> HeadAsync<T>(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return ExecAsync<T>(NewRequest(HttpMethod.Head, path, options, config), config, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP OPTION request (async).
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="cancellationToken">Token that enables callers to cancel the request.</param>
|
||||
/// <returns>A Task containing ApiResponse</returns>
|
||||
public Task<ApiResponse<T>> OptionsAsync<T>(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return ExecAsync<T>(NewRequest(HttpMethod.Options, path, options, config), config, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP PATCH request (async).
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <param name="cancellationToken">Token that enables callers to cancel the request.</param>
|
||||
/// <returns>A Task containing ApiResponse</returns>
|
||||
public Task<ApiResponse<T>> PatchAsync<T>(string path, RequestOptions options, IReadableConfiguration configuration = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return ExecAsync<T>(NewRequest(new HttpMethod("PATCH"), path, options, config), config, cancellationToken);
|
||||
}
|
||||
#endregion IAsynchronousClient
|
||||
{{/supportsAsync}}
|
||||
|
||||
#region ISynchronousClient
|
||||
/// <summary>
|
||||
/// Make a HTTP GET request (synchronous).
|
||||
/// </summary>
|
||||
/// <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>A Task containing ApiResponse</returns>
|
||||
public ApiResponse<T> Get<T>(string path, RequestOptions options, IReadableConfiguration configuration = null)
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return Exec<T>(NewRequest(HttpMethod.Get, path, options, config), config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP POST request (synchronous).
|
||||
/// </summary>
|
||||
/// <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>A Task containing ApiResponse</returns>
|
||||
public ApiResponse<T> Post<T>(string path, RequestOptions options, IReadableConfiguration configuration = null)
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return Exec<T>(NewRequest(HttpMethod.Post, path, options, config), config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP PUT request (synchronous).
|
||||
/// </summary>
|
||||
/// <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>A Task containing ApiResponse</returns>
|
||||
public ApiResponse<T> Put<T>(string path, RequestOptions options, IReadableConfiguration configuration = null)
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return Exec<T>(NewRequest(HttpMethod.Put, path, options, config), config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP DELETE request (synchronous).
|
||||
/// </summary>
|
||||
/// <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>A Task containing ApiResponse</returns>
|
||||
public ApiResponse<T> Delete<T>(string path, RequestOptions options, IReadableConfiguration configuration = null)
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return Exec<T>(NewRequest(HttpMethod.Delete, path, options, config), config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP HEAD request (synchronous).
|
||||
/// </summary>
|
||||
/// <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>A Task containing ApiResponse</returns>
|
||||
public ApiResponse<T> Head<T>(string path, RequestOptions options, IReadableConfiguration configuration = null)
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return Exec<T>(NewRequest(HttpMethod.Head, path, options, config), config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP OPTION request (synchronous).
|
||||
/// </summary>
|
||||
/// <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>A Task containing ApiResponse</returns>
|
||||
public ApiResponse<T> Options<T>(string path, RequestOptions options, IReadableConfiguration configuration = null)
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return Exec<T>(NewRequest(HttpMethod.Options, path, options, config), config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a HTTP PATCH request (synchronous).
|
||||
/// </summary>
|
||||
/// <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>A Task containing ApiResponse</returns>
|
||||
public ApiResponse<T> Patch<T>(string path, RequestOptions options, IReadableConfiguration configuration = null)
|
||||
{
|
||||
var config = configuration ?? GlobalConfiguration.Instance;
|
||||
return Exec<T>(NewRequest(new HttpMethod("PATCH"), path, options, config), config);
|
||||
}
|
||||
#endregion ISynchronousClient
|
||||
}
|
||||
}
|
@ -31,9 +31,9 @@ using Polly;
|
||||
namespace Org.OpenAPITools.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows RestSharp to Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON.
|
||||
/// To Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON.
|
||||
/// </summary>
|
||||
internal class CustomJsonCodec
|
||||
internal class CustomJsonCodec
|
||||
{
|
||||
private readonly IReadableConfiguration _configuration;
|
||||
private static readonly string _contentType = "application/json";
|
||||
@ -202,8 +202,7 @@ namespace Org.OpenAPITools.Client
|
||||
_baseUrl = basePath;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <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.
|
||||
@ -436,10 +435,6 @@ namespace Org.OpenAPITools.Client
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#region IAsynchronousClient
|
||||
/// <summary>
|
||||
/// Make a HTTP GET request (async).
|
||||
|
@ -36,7 +36,7 @@ namespace Org.OpenAPITools.Client
|
||||
/// <summary>
|
||||
/// Allows RestSharp to Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON.
|
||||
/// </summary>
|
||||
internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer
|
||||
internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer
|
||||
{
|
||||
private readonly IReadableConfiguration _configuration;
|
||||
private static readonly string _contentType = "application/json";
|
||||
@ -183,6 +183,7 @@ namespace Org.OpenAPITools.Client
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Allows for extending request processing for <see cref="ApiClient"/> generated code.
|
||||
/// </summary>
|
||||
@ -528,9 +529,6 @@ namespace Org.OpenAPITools.Client
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private async Task<ApiResponse<T>> ExecAsync<T>(RestRequest req, IReadableConfiguration configuration, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
RestClient client = new RestClient(_baseUrl);
|
||||
|
@ -36,7 +36,7 @@ namespace Org.OpenAPITools.Client
|
||||
/// <summary>
|
||||
/// Allows RestSharp to Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON.
|
||||
/// </summary>
|
||||
internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer
|
||||
internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer
|
||||
{
|
||||
private readonly IReadableConfiguration _configuration;
|
||||
private static readonly string _contentType = "application/json";
|
||||
@ -183,6 +183,7 @@ namespace Org.OpenAPITools.Client
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Allows for extending request processing for <see cref="ApiClient"/> generated code.
|
||||
/// </summary>
|
||||
@ -528,9 +529,6 @@ namespace Org.OpenAPITools.Client
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private async Task<ApiResponse<T>> ExecAsync<T>(RestRequest req, IReadableConfiguration configuration, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
RestClient client = new RestClient(_baseUrl);
|
||||
|
@ -35,7 +35,7 @@ namespace Org.OpenAPITools.Client
|
||||
/// <summary>
|
||||
/// Allows RestSharp to Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON.
|
||||
/// </summary>
|
||||
internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer
|
||||
internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer
|
||||
{
|
||||
private readonly IReadableConfiguration _configuration;
|
||||
private static readonly string _contentType = "application/json";
|
||||
@ -182,6 +182,7 @@ namespace Org.OpenAPITools.Client
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Allows for extending request processing for <see cref="ApiClient"/> generated code.
|
||||
/// </summary>
|
||||
@ -527,9 +528,6 @@ namespace Org.OpenAPITools.Client
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private async Task<ApiResponse<T>> ExecAsync<T>(RestRequest req, IReadableConfiguration configuration, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
RestClient client = new RestClient(_baseUrl);
|
||||
|
@ -36,7 +36,7 @@ namespace Org.OpenAPITools.Client
|
||||
/// <summary>
|
||||
/// Allows RestSharp to Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON.
|
||||
/// </summary>
|
||||
internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer
|
||||
internal class CustomJsonCodec : RestSharp.Serializers.ISerializer, RestSharp.Deserializers.IDeserializer
|
||||
{
|
||||
private readonly IReadableConfiguration _configuration;
|
||||
private static readonly string _contentType = "application/json";
|
||||
@ -183,6 +183,7 @@ namespace Org.OpenAPITools.Client
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Allows for extending request processing for <see cref="ApiClient"/> generated code.
|
||||
/// </summary>
|
||||
@ -528,9 +529,6 @@ namespace Org.OpenAPITools.Client
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private async Task<ApiResponse<T>> ExecAsync<T>(RestRequest req, IReadableConfiguration configuration, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
|
||||
{
|
||||
RestClient client = new RestClient(_baseUrl);
|
||||
|
Loading…
x
Reference in New Issue
Block a user