diff --git a/sdks/dotnet/.github/workflows/github-actions.yml b/sdks/dotnet/.github/workflows/github-actions.yml
index 1046c5fd5..d906a4852 100644
--- a/sdks/dotnet/.github/workflows/github-actions.yml
+++ b/sdks/dotnet/.github/workflows/github-actions.yml
@@ -40,7 +40,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore ${SOLUTION}.sln
diff --git a/sdks/dotnet/.gitignore b/sdks/dotnet/.gitignore
index 02e0c345b..78294d932 100644
--- a/sdks/dotnet/.gitignore
+++ b/sdks/dotnet/.gitignore
@@ -361,6 +361,8 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
+git_push.sh
+global.json
vendor
/api
.openapi-generator
diff --git a/sdks/dotnet/.openapi-generator-ignore b/sdks/dotnet/.openapi-generator-ignore
index 77ed52efa..7484ee590 100644
--- a/sdks/dotnet/.openapi-generator-ignore
+++ b/sdks/dotnet/.openapi-generator-ignore
@@ -21,7 +21,3 @@
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
-
-git_push.sh
-**/Model/*AllOf*
-docs/*AllOf*
diff --git a/sdks/dotnet/Dropbox.Sign.sln b/sdks/dotnet/Dropbox.Sign.sln
old mode 100755
new mode 100644
diff --git a/sdks/dotnet/README.md b/sdks/dotnet/README.md
index 4f715b358..e1c6c1734 100644
--- a/sdks/dotnet/README.md
+++ b/sdks/dotnet/README.md
@@ -23,8 +23,8 @@ directory that corresponds to the file you want updated.
This C# SDK is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 3.0.0
-- SDK version: 1.8-dev
-- Generator version: 7.8.0
+- SDK version: 2.0-dev
+- Generator version: 7.12.0
- Build package: org.openapitools.codegen.languages.CSharpClientCodegen
### Building
@@ -49,7 +49,7 @@ this command.
## Dependencies
-- [RestSharp](https://www.nuget.org/packages/RestSharp) - 106.13.0 or later
+- [RestSharp](https://www.nuget.org/packages/RestSharp) - 112.0.0 or later
- [Json.NET](https://www.nuget.org/packages/Newtonsoft.Json/) - 13.0.2 or later
- [JsonSubTypes](https://www.nuget.org/packages/JsonSubTypes/) - 1.8.0 or later
- [System.ComponentModel.Annotations](https://www.nuget.org/packages/System.ComponentModel.Annotations) - 5.0.0 or later
diff --git a/sdks/dotnet/VERSION b/sdks/dotnet/VERSION
index d82db9132..c3bb52e88 100644
--- a/sdks/dotnet/VERSION
+++ b/sdks/dotnet/VERSION
@@ -1 +1 @@
-1.8-dev
+2.0-dev
diff --git a/sdks/dotnet/bin/copy-constants.php b/sdks/dotnet/bin/copy-constants.php
new file mode 100755
index 000000000..885380501
--- /dev/null
+++ b/sdks/dotnet/bin/copy-constants.php
@@ -0,0 +1,64 @@
+#!/usr/bin/env php
+run();
\ No newline at end of file
diff --git a/sdks/dotnet/bin/dotnet b/sdks/dotnet/bin/dotnet
index f1b73acd7..b3e5c445d 100755
--- a/sdks/dotnet/bin/dotnet
+++ b/sdks/dotnet/bin/dotnet
@@ -12,4 +12,4 @@ docker run --rm \
-v "${ROOT_DIR}:${WORKING_DIR}" \
-w "${WORKING_DIR}" \
-u root:root \
- mcr.microsoft.com/dotnet/sdk:6.0 "$@"
+ mcr.microsoft.com/dotnet/sdk:8.0 "$@"
diff --git a/sdks/dotnet/openapi-config.yaml b/sdks/dotnet/openapi-config.yaml
index a33ad8805..986c99a1f 100644
--- a/sdks/dotnet/openapi-config.yaml
+++ b/sdks/dotnet/openapi-config.yaml
@@ -6,11 +6,12 @@ additionalProperties:
packageCompany: Dropbox Sign API Team
packageCopyright: Dropbox 2024
packageDescription: Client library for using the Dropbox Sign API
- packageVersion: 1.8-dev
+ packageVersion: 2.0-dev
packageTitle: Dropbox Sign .Net SDK
sortModelPropertiesByRequiredFlag: true
optionalEmitDefaultValues: true
- targetFramework: net6.0
+ targetFramework: net8.0
+ library: restsharp
packageGuid: "{F8C8232D-7020-4603-8E04-18D060AE530B}"
legacyDiscriminatorBehavior: true
useCustomTemplateCode: true
diff --git a/sdks/dotnet/run-build b/sdks/dotnet/run-build
index 8a2332ad6..d65fff536 100755
--- a/sdks/dotnet/run-build
+++ b/sdks/dotnet/run-build
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-# see https://github.com/OpenAPITools/openapi-generator/tree/v7.8.0/modules/openapi-generator/src/main/resources/csharp
+# see https://github.com/OpenAPITools/openapi-generator/tree/v7.12.0/modules/openapi-generator/src/main/resources/csharp
set -e
@@ -18,7 +18,7 @@ rm -f "${DIR}/src/Dropbox.Sign/Model/"*.cs
docker run --rm \
-v "${DIR}/:/local" \
- openapitools/openapi-generator-cli:v7.8.0 generate \
+ openapitools/openapi-generator-cli:v7.12.0 generate \
-i "/local/openapi-sdk.yaml" \
-c "/local/openapi-config.yaml" \
-t "/local/templates" \
@@ -46,6 +46,9 @@ docker run --rm \
-w "${WORKING_DIR}" \
perl bash ./bin/scan_for
+printf "Adding old-style constant names ...\n"
+bash "${DIR}/bin/php" ./bin/copy-constants.php
+
# avoid docker messing with permissions
if [[ -z "$GITHUB_ACTIONS" ]]; then
chmod 644 "${DIR}/README.md"
diff --git a/sdks/dotnet/src/Dropbox.Sign.Test/Dropbox.Sign.Test.csproj b/sdks/dotnet/src/Dropbox.Sign.Test/Dropbox.Sign.Test.csproj
index 50c2bf70c..3ea5d9d8c 100644
--- a/sdks/dotnet/src/Dropbox.Sign.Test/Dropbox.Sign.Test.csproj
+++ b/sdks/dotnet/src/Dropbox.Sign.Test/Dropbox.Sign.Test.csproj
@@ -3,7 +3,7 @@
Dropbox.Sign.Test
Dropbox.Sign.Test
- net6.0
+ net8.0
false
Dropbox.Sign.Test
diff --git a/sdks/dotnet/src/Dropbox.Sign/Client/ApiClient.cs b/sdks/dotnet/src/Dropbox.Sign/Client/ApiClient.cs
index d43d6f7ec..72c26631b 100644
--- a/sdks/dotnet/src/Dropbox.Sign/Client/ApiClient.cs
+++ b/sdks/dotnet/src/Dropbox.Sign/Client/ApiClient.cs
@@ -110,7 +110,7 @@ internal object Deserialize(RestResponse response, Type type)
if (response.Headers != null)
{
var filePath = string.IsNullOrEmpty(_configuration.TempFolderPath)
- ? Path.GetTempPath()
+ ? global::System.IO.Path.GetTempPath()
: _configuration.TempFolderPath;
var regex = new Regex(@"Content-Disposition=.*filename=['""]?([^'""\s]+)['""]?$");
foreach (var header in response.Headers)
@@ -334,7 +334,7 @@ private RestRequest NewRequest(
{
foreach (var value in headerParam.Value)
{
- request.AddHeader(headerParam.Key, value);
+ request.AddOrUpdateHeader(headerParam.Key, value);
}
}
}
@@ -394,13 +394,21 @@ private RestRequest NewRequest(
var bytes = ClientUtils.ReadAsBytes(file);
var fileStream = file as FileStream;
if (fileStream != null)
- request.AddFile(fileParam.Key, bytes, Path.GetFileName(fileStream.Name));
+ request.AddFile(fileParam.Key, bytes, global::System.IO.Path.GetFileName(fileStream.Name));
else
request.AddFile(fileParam.Key, bytes, "no_file_name_provided");
}
}
}
+ if (options.HeaderParameters != null)
+ {
+ if (options.HeaderParameters.TryGetValue("Content-Type", out var contentTypes) && contentTypes.Any(header => header.Contains("multipart/form-data")))
+ {
+ request.AlwaysMultipartFormData = true;
+ }
+ }
+
return request;
}
@@ -472,7 +480,7 @@ private async Task> ExecClientAsync(Func> ExecClientAsync(Func DeserializeRestResponseFromPolicy(RestClient client, RestRequest request, PolicyResult policyResult)
+ private async Task> DeserializeRestResponseFromPolicyAsync(RestClient client, RestRequest request, PolicyResult policyResult, CancellationToken cancellationToken = default)
{
if (policyResult.Outcome == OutcomeType.Successful)
{
- return client.Deserialize(policyResult.Result);
+ return await client.Deserialize(policyResult.Result, cancellationToken);
}
else
{
@@ -594,7 +602,7 @@ private ApiResponse Exec(RestRequest request, RequestOptions options, IRea
{
var policy = RetryConfiguration.RetryPolicy;
var policyResult = policy.ExecuteAndCapture(() => client.Execute(request));
- return Task.FromResult(DeserializeRestResponseFromPolicy(client, request, policyResult));
+ return DeserializeRestResponseFromPolicyAsync(client, request, policyResult);
}
else
{
@@ -618,7 +626,7 @@ private ApiResponse Exec(RestRequest request, RequestOptions options, IRea
{
var policy = RetryConfiguration.AsyncRetryPolicy;
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
- return DeserializeRestResponseFromPolicy(client, request, policyResult);
+ return await DeserializeRestResponseFromPolicyAsync(client, request, policyResult, cancellationToken);
}
else
{
diff --git a/sdks/dotnet/src/Dropbox.Sign/Client/ClientUtils.cs b/sdks/dotnet/src/Dropbox.Sign/Client/ClientUtils.cs
index 8fb7773d6..ec20198ca 100644
--- a/sdks/dotnet/src/Dropbox.Sign/Client/ClientUtils.cs
+++ b/sdks/dotnet/src/Dropbox.Sign/Client/ClientUtils.cs
@@ -105,6 +105,12 @@ public static string ParameterToString(object obj, IReadableConfiguration config
// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8
// For example: 2009-06-15T13:45:30.0000000
return dateTimeOffset.ToString((configuration ?? GlobalConfiguration.Instance).DateTimeFormat);
+ if (obj is DateOnly dateOnly)
+ // Return a formatted date string - Can be customized with Configuration.DateTimeFormat
+ // Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o")
+ // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8
+ // For example: 2009-06-15
+ return dateOnly.ToString((configuration ?? GlobalConfiguration.Instance).DateTimeFormat);
if (obj is bool boolean)
return boolean ? "true" : "false";
if (obj is ICollection collection)
diff --git a/sdks/dotnet/src/Dropbox.Sign/Client/Configuration.cs b/sdks/dotnet/src/Dropbox.Sign/Client/Configuration.cs
index 127056ed0..8316e9803 100644
--- a/sdks/dotnet/src/Dropbox.Sign/Client/Configuration.cs
+++ b/sdks/dotnet/src/Dropbox.Sign/Client/Configuration.cs
@@ -36,7 +36,7 @@ public class Configuration : IReadableConfiguration
/// Version of the package.
///
/// Version of the package.
- public const string Version = "1.8-dev";
+ public const string Version = "2.0-dev";
///
/// Identifier for ISO 8601 DateTime Format
@@ -120,7 +120,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
- UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.8-dev/csharp");
+ UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/2.0-dev/csharp");
BasePath = "https://api.hellosign.com/v3";
DefaultHeaders = new ConcurrentDictionary();
ApiKey = new ConcurrentDictionary();
@@ -163,7 +163,7 @@ public Configuration()
};
// Setting Timeout has side effects (forces ApiClient creation).
- Timeout = 100000;
+ Timeout = TimeSpan.FromSeconds(100);
}
///
@@ -247,9 +247,9 @@ public virtual IDictionary DefaultHeader
public virtual IDictionary DefaultHeaders { get; set; }
///
- /// Gets or sets the HTTP timeout (milliseconds) of ApiClient. Default to 100000 milliseconds.
+ /// Gets or sets the HTTP timeout of ApiClient. Defaults to 100 seconds.
///
- public virtual int Timeout { get; set; }
+ public virtual TimeSpan Timeout { get; set; }
///
/// Gets or sets the proxy
@@ -567,7 +567,7 @@ public static string ToDebugReport()
report += " OS: " + System.Environment.OSVersion + "\n";
report += " .NET Framework Version: " + System.Environment.Version + "\n";
report += " Version of the API: 3.0.0\n";
- report += " SDK Package Version: 1.8-dev\n";
+ report += " SDK Package Version: 2.0-dev\n";
return report;
}
diff --git a/sdks/dotnet/src/Dropbox.Sign/Client/IReadableConfiguration.cs b/sdks/dotnet/src/Dropbox.Sign/Client/IReadableConfiguration.cs
index a4e493e1c..14469bb07 100644
--- a/sdks/dotnet/src/Dropbox.Sign/Client/IReadableConfiguration.cs
+++ b/sdks/dotnet/src/Dropbox.Sign/Client/IReadableConfiguration.cs
@@ -72,10 +72,10 @@ public interface IReadableConfiguration
string TempFolderPath { get; }
///
- /// Gets the HTTP connection timeout (in milliseconds)
+ /// Gets the HTTP connection timeout.
///
/// HTTP connection timeout.
- int Timeout { get; }
+ TimeSpan Timeout { get; }
///
/// Gets the proxy.
diff --git a/sdks/dotnet/src/Dropbox.Sign/Dropbox.Sign.csproj b/sdks/dotnet/src/Dropbox.Sign/Dropbox.Sign.csproj
index db65ddba1..fd6e98aaa 100644
--- a/sdks/dotnet/src/Dropbox.Sign/Dropbox.Sign.csproj
+++ b/sdks/dotnet/src/Dropbox.Sign/Dropbox.Sign.csproj
@@ -2,7 +2,7 @@
false
- net6.0
+ net8.0
Dropbox.Sign
Dropbox.Sign
Library
@@ -12,7 +12,7 @@
Client library for using the Dropbox Sign API
Dropbox 2024
Dropbox.Sign
- 1.8-dev
+ 2.0-dev
bin\$(Configuration)\$(TargetFramework)\Dropbox.Sign.xml
https://github.com/hellosign/dropbox-sign-dotnet.git
git
diff --git a/sdks/dotnet/src/Dropbox.Sign/Model/SubFormFieldRuleAction.cs b/sdks/dotnet/src/Dropbox.Sign/Model/SubFormFieldRuleAction.cs
index a15a63f13..b6af36b3d 100644
--- a/sdks/dotnet/src/Dropbox.Sign/Model/SubFormFieldRuleAction.cs
+++ b/sdks/dotnet/src/Dropbox.Sign/Model/SubFormFieldRuleAction.cs
@@ -40,16 +40,18 @@ public partial class SubFormFieldRuleAction : IEquatable
public enum TypeEnum
{
///
- /// Enum FieldVisibility for value: change-field-visibility
+ /// Enum ChangeFieldVisibility for value: change-field-visibility
///
[EnumMember(Value = "change-field-visibility")]
- FieldVisibility = 1,
+ ChangeFieldVisibility = 1,
+ FieldVisibility = ChangeFieldVisibility,
///
- /// Enum GroupVisibility for value: change-group-visibility
+ /// Enum ChangeGroupVisibility for value: change-group-visibility
///
[EnumMember(Value = "change-group-visibility")]
- GroupVisibility = 2
+ ChangeGroupVisibility = 2,
+ GroupVisibility = ChangeGroupVisibility
}
diff --git a/sdks/dotnet/templates/ApiClient.mustache b/sdks/dotnet/templates/ApiClient.mustache
index f8798bd23..bd0a31747 100644
--- a/sdks/dotnet/templates/ApiClient.mustache
+++ b/sdks/dotnet/templates/ApiClient.mustache
@@ -109,7 +109,7 @@ namespace {{packageName}}.Client
if (response.Headers != null)
{
var filePath = string.IsNullOrEmpty(_configuration.TempFolderPath)
- ? Path.GetTempPath()
+ ? global::System.IO.Path.GetTempPath()
: _configuration.TempFolderPath;
var regex = new Regex(@"Content-Disposition=.*filename=['""]?([^'""\s]+)['""]?$");
foreach (var header in response.Headers)
@@ -338,7 +338,7 @@ namespace {{packageName}}.Client
{
foreach (var value in headerParam.Value)
{
- request.AddHeader(headerParam.Key, value);
+ request.AddOrUpdateHeader(headerParam.Key, value);
}
}
}
@@ -398,13 +398,21 @@ namespace {{packageName}}.Client
var bytes = ClientUtils.ReadAsBytes(file);
var fileStream = file as FileStream;
if (fileStream != null)
- request.AddFile(fileParam.Key, bytes, Path.GetFileName(fileStream.Name));
+ request.AddFile(fileParam.Key, bytes, global::System.IO.Path.GetFileName(fileStream.Name));
else
request.AddFile(fileParam.Key, bytes, "no_file_name_provided");
}
}
}
+ if (options.HeaderParameters != null)
+ {
+ if (options.HeaderParameters.TryGetValue("Content-Type", out var contentTypes) && contentTypes.Any(header => header.Contains("multipart/form-data")))
+ {
+ request.AlwaysMultipartFormData = true;
+ }
+ }
+
return request;
}
@@ -476,7 +484,7 @@ namespace {{packageName}}.Client
var clientOptions = new RestClientOptions(baseUrl)
{
ClientCertificates = configuration.ClientCertificates,
- MaxTimeout = configuration.Timeout,
+ Timeout = configuration.Timeout,
Proxy = configuration.Proxy,
UserAgent = configuration.UserAgent,
UseDefaultCredentials = configuration.UseDefaultCredentials,
@@ -585,11 +593,11 @@ namespace {{packageName}}.Client
}
}
- private RestResponse DeserializeRestResponseFromPolicy(RestClient client, RestRequest request, PolicyResult policyResult)
+ private async Task> DeserializeRestResponseFromPolicyAsync(RestClient client, RestRequest request, PolicyResult policyResult, CancellationToken cancellationToken = default)
{
if (policyResult.Outcome == OutcomeType.Successful)
{
- return client.Deserialize(policyResult.Result);
+ return await client.Deserialize(policyResult.Result, cancellationToken);
}
else
{
@@ -622,7 +630,7 @@ namespace {{packageName}}.Client
{
var policy = RetryConfiguration.RetryPolicy;
var policyResult = policy.ExecuteAndCapture(() => client.Execute(request));
- return Task.FromResult(DeserializeRestResponseFromPolicy(client, request, policyResult));
+ return DeserializeRestResponseFromPolicyAsync(client, request, policyResult);
}
else
{
@@ -648,7 +656,7 @@ namespace {{packageName}}.Client
{
var policy = RetryConfiguration.AsyncRetryPolicy;
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
- return DeserializeRestResponseFromPolicy(client, request, policyResult);
+ return await DeserializeRestResponseFromPolicyAsync(client, request, policyResult, cancellationToken);
}
else
{
diff --git a/sdks/dotnet/templates/ApiClient.v790.mustache b/sdks/dotnet/templates/ApiClient.v790.mustache
new file mode 100644
index 000000000..a63d1c2be
--- /dev/null
+++ b/sdks/dotnet/templates/ApiClient.v790.mustache
@@ -0,0 +1,838 @@
+{{>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;
+{{^net60OrLater}}
+using System.Web;
+{{/net60OrLater}}
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+using RestSharp;
+using RestSharp.Serializers;
+using RestSharpMethod = RestSharp.Method;
+using FileIO = System.IO.File;
+{{#supportsRetry}}
+using Polly;
+{{/supportsRetry}}
+{{#hasOAuthMethods}}
+using {{packageName}}.Client.Auth;
+{{/hasOAuthMethods}}
+using {{packageName}}.{{modelPackage}};
+
+namespace {{packageName}}.Client
+{
+ ///
+ /// Allows RestSharp to Serialize/Deserialize JSON using our custom logic, but only when ContentType is JSON.
+ ///
+ internal class CustomJsonCodec : IRestSerializer, ISerializer, IDeserializer
+ {
+ private readonly IReadableConfiguration _configuration;
+ 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;
+ }
+
+ ///
+ /// Serialize the object into a JSON string.
+ ///
+ /// Object to be serialized.
+ /// A JSON string.
+ public string Serialize(object obj)
+ {
+ if (obj != null && obj is AbstractOpenAPISchema)
+ {
+ // the object to be serialized is an oneOf/anyOf schema
+ return ((AbstractOpenAPISchema)obj).ToJson();
+ }
+ else
+ {
+ return JsonConvert.SerializeObject(obj, _serializerSettings);
+ }
+ }
+
+ public string Serialize(Parameter bodyParameter) => Serialize(bodyParameter.Value);
+
+ public T Deserialize(RestResponse response)
+ {
+ var result = (T)Deserialize(response, typeof(T));
+ return result;
+ }
+
+ ///
+ /// Deserialize the JSON string into a proper object.
+ ///
+ /// The HTTP response.
+ /// Object type.
+ /// Object representation of the JSON string.
+ internal object Deserialize(RestResponse response, Type type)
+ {
+ if (type == typeof(byte[])) // return byte array
+ {
+ return response.RawBytes;
+ }
+
+ // TODO: ? if (type.IsAssignableFrom(typeof(Stream)))
+ if (type == typeof(Stream))
+ {
+ var bytes = response.RawBytes;
+ if (response.Headers != null)
+ {
+ var filePath = string.IsNullOrEmpty(_configuration.TempFolderPath)
+ ? global::System.IO.Path.GetTempPath()
+ : _configuration.TempFolderPath;
+ var regex = new Regex(@"Content-Disposition=.*filename=['""]?([^'""\s]+)['""]?$");
+ foreach (var header in response.Headers)
+ {
+ var match = regex.Match(header.ToString());
+ if (match.Success)
+ {
+ string fileName = filePath + ClientUtils.SanitizeFilename(match.Groups[1].Value.Replace("\"", "").Replace("'", ""));
+ FileIO.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, null, DateTimeStyles.RoundtripKind);
+ }
+
+ if (type == typeof(string) || type.Name.StartsWith("System.Nullable")) // return primitive type
+ {
+ return Convert.ChangeType(response.Content, type);
+ }
+
+ // at this point, it must be a model (json)
+ try
+ {
+ return JsonConvert.DeserializeObject(response.Content, type, _serializerSettings);
+ }
+ catch (Exception e)
+ {
+ throw new ApiException(500, e.Message);
+ }
+ }
+
+ public ISerializer Serializer => this;
+ public IDeserializer Deserializer => this;
+
+ public string[] AcceptedContentTypes => ContentType.JsonAccept;
+
+ public SupportsContentType SupportsContentType => contentType =>
+ contentType.Value.EndsWith("json", StringComparison.InvariantCultureIgnoreCase) ||
+ contentType.Value.EndsWith("javascript", StringComparison.InvariantCultureIgnoreCase);
+
+ public ContentType ContentType { get; set; } = ContentType.Json;
+
+ public DataFormat DataFormat => DataFormat.Json;
+ }
+ {{! NOTE: Any changes related to RestSharp should be done in this class. All other client classes are for extensibility by consumers.}}
+ ///
+ /// Provides a default implementation of an Api client (both synchronous and asynchronous implementations),
+ /// encapsulating general REST accessor use cases.
+ ///
+ {{>visibility}} partial class ApiClient : ISynchronousClient{{#supportsAsync}}, IAsynchronousClient{{/supportsAsync}}
+ {
+ private readonly string _baseUrl;
+
+ ///
+ /// Specifies the settings on a object.
+ /// These settings can be adjusted to accommodate custom serialization rules.
+ ///
+ 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
+ }
+ }
+ };
+
+ ///
+ /// Allows for extending request processing for generated code.
+ ///
+ /// The RestSharp request object
+ partial void InterceptRequest(RestRequest request);
+
+ ///
+ /// Allows for extending response processing for generated code.
+ ///
+ /// The RestSharp request object
+ /// The RestSharp response object
+ partial void InterceptResponse(RestRequest request, RestResponse response);
+
+ ///
+ /// Initializes a new instance of the , defaulting to the global configurations' base url.
+ ///
+ public ApiClient()
+ {
+ _baseUrl = GlobalConfiguration.Instance.BasePath;
+ }
+
+ ///
+ /// Initializes a new instance of the
+ ///
+ /// The target service's base path in URL format.
+ ///
+ public ApiClient(string basePath)
+ {
+ if (string.IsNullOrEmpty(basePath))
+ throw new ArgumentException("basePath cannot be empty");
+
+ _baseUrl = basePath;
+ }
+
+ ///
+ /// Constructs the RestSharp version of an http method
+ ///
+ /// Swagger Client Custom HttpMethod
+ /// RestSharp's HttpMethod instance.
+ ///
+ private RestSharpMethod Method(HttpMethod method)
+ {
+ RestSharpMethod other;
+ switch (method)
+ {
+ case HttpMethod.Get:
+ other = RestSharpMethod.Get;
+ break;
+ case HttpMethod.Post:
+ other = RestSharpMethod.Post;
+ break;
+ case HttpMethod.Put:
+ other = RestSharpMethod.Put;
+ break;
+ case HttpMethod.Delete:
+ other = RestSharpMethod.Delete;
+ break;
+ case HttpMethod.Head:
+ other = RestSharpMethod.Head;
+ break;
+ case HttpMethod.Options:
+ other = RestSharpMethod.Options;
+ break;
+ case HttpMethod.Patch:
+ other = RestSharpMethod.Patch;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException("method", method, null);
+ }
+
+ return other;
+ }
+
+ ///
+ /// Provides all logic for constructing a new RestSharp .
+ /// At this point, all information for querying the service is known.
+ /// Here, it is simply mapped into the RestSharp request.
+ ///
+ /// The http verb.
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object.
+ /// It is assumed that any merge with GlobalConfiguration has been done before calling this method.
+ /// [private] A new RestRequest instance.
+ ///
+ 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(path, Method(method));
+
+ 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)
+ {
+ foreach (var file in fileParam.Value)
+ {
+ var bytes = ClientUtils.ReadAsBytes(file);
+ var fileStream = file as FileStream;
+ if (fileStream != null)
+ request.AddFile(fileParam.Key, bytes, global::System.IO.Path.GetFileName(fileStream.Name));
+ else
+ request.AddFile(fileParam.Key, bytes, "no_file_name_provided");
+ }
+ }
+ }
+
+ return request;
+ }
+
+ ///
+ /// Transforms a RestResponse instance into a new ApiResponse instance.
+ /// At this point, we have a concrete http response from the service.
+ /// Here, it is simply mapped into the [public] ApiResponse object.
+ ///
+ /// The RestSharp response object
+ /// A new ApiResponse instance.
+ private ApiResponse ToApiResponse(RestResponse response)
+ {
+ T result = response.Data;
+ string rawContent = response.Content;
+
+ var transformed = new ApiResponse(response.StatusCode, new Multimap({{#caseInsensitiveResponseHeaders}}StringComparer.OrdinalIgnoreCase{{/caseInsensitiveResponseHeaders}}), result, rawContent)
+ {
+ ErrorText = response.ErrorMessage,
+ Cookies = new List()
+ };
+
+ if (response.Headers != null)
+ {
+ foreach (var responseHeader in response.Headers)
+ {
+ transformed.Headers.Add(responseHeader.Name, ClientUtils.ParameterToString(responseHeader.Value));
+ }
+ }
+
+ if (response.ContentHeaders != null)
+ {
+ foreach (var responseHeader in response.ContentHeaders)
+ {
+ transformed.Headers.Add(responseHeader.Name, ClientUtils.ParameterToString(responseHeader.Value));
+ }
+ }
+
+ if (response.Cookies != null)
+ {
+ foreach (var responseCookies in response.Cookies.Cast())
+ {
+ transformed.Cookies.Add(
+ new Cookie(
+ responseCookies.Name,
+ responseCookies.Value,
+ responseCookies.Path,
+ responseCookies.Domain)
+ );
+ }
+ }
+
+ return transformed;
+ }
+
+ ///
+ /// Executes the HTTP request for the current service.
+ /// Based on functions received it can be async or sync.
+ ///
+ /// Local function that executes http request and returns http response.
+ /// Local function to specify options for the service.
+ /// The RestSharp request object
+ /// The RestSharp options object
+ /// A per-request configuration object.
+ /// It is assumed that any merge with GlobalConfiguration has been done before calling this method.
+ /// A new ApiResponse instance.
+ private async Task> ExecClientAsync(Func>> getResponse, Action setOptions, RestRequest request, RequestOptions options, IReadableConfiguration configuration)
+ {
+ var baseUrl = configuration.GetOperationServerUrl(options.Operation, options.OperationIndex) ?? _baseUrl;
+ var clientOptions = new RestClientOptions(baseUrl)
+ {
+ ClientCertificates = configuration.ClientCertificates,
+ MaxTimeout = configuration.Timeout,
+ Proxy = configuration.Proxy,
+ UserAgent = configuration.UserAgent,
+ UseDefaultCredentials = configuration.UseDefaultCredentials,
+ RemoteCertificateValidationCallback = configuration.RemoteCertificateValidationCallback
+ };
+ setOptions(clientOptions);
+
+ {{#hasOAuthMethods}}
+ if (!string.IsNullOrEmpty(configuration.OAuthTokenUrl) &&
+ !string.IsNullOrEmpty(configuration.OAuthClientId) &&
+ !string.IsNullOrEmpty(configuration.OAuthClientSecret) &&
+ configuration.OAuthFlow != null)
+ {
+ clientOptions.Authenticator = new OAuthAuthenticator(
+ configuration.OAuthTokenUrl,
+ configuration.OAuthClientId,
+ configuration.OAuthClientSecret,
+ configuration.OAuthScope,
+ configuration.OAuthFlow,
+ SerializerSettings,
+ configuration);
+ }
+
+ {{/hasOAuthMethods}}
+ using (RestClient client = new RestClient(clientOptions,
+ configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(SerializerSettings, configuration))))
+ {
+ InterceptRequest(request);
+
+ RestResponse response = await getResponse(client);
+
+ // if the response type is oneOf/anyOf, call FromJSON to deserialize the data
+ if (typeof(AbstractOpenAPISchema).IsAssignableFrom(typeof(T)))
+ {
+ try
+ {
+ response.Data = (T)typeof(T).GetMethod("FromJson").Invoke(null, new object[] { response.Content });
+ }
+ catch (Exception ex)
+ {
+ throw ex.InnerException != null ? ex.InnerException : ex;
+ }
+ }
+ else if (typeof(T).Name == "Stream") // for binary response
+ {
+ response.Data = (T)(object)new MemoryStream(response.RawBytes);
+ }
+ else if (typeof(T).Name == "Byte[]") // for byte response
+ {
+ response.Data = (T)(object)response.RawBytes;
+ }
+ else if (typeof(T).Name == "String") // for string response
+ {
+ response.Data = (T)(object)response.Content;
+ }
+
+ InterceptResponse(request, response);
+
+ var result = ToApiResponse(response);
+ if (response.ErrorMessage != null)
+ {
+ result.ErrorText = response.ErrorMessage;
+ }
+
+ if (response.Cookies != null && response.Cookies.Count > 0)
+ {
+ if (result.Cookies == null) result.Cookies = new List();
+ foreach (var restResponseCookie in response.Cookies.Cast())
+ {
+ var cookie = new Cookie(
+ restResponseCookie.Name,
+ restResponseCookie.Value,
+ restResponseCookie.Path,
+ restResponseCookie.Domain
+ )
+ {
+ Comment = restResponseCookie.Comment,
+ CommentUri = restResponseCookie.CommentUri,
+ Discard = restResponseCookie.Discard,
+ Expired = restResponseCookie.Expired,
+ Expires = restResponseCookie.Expires,
+ HttpOnly = restResponseCookie.HttpOnly,
+ Port = restResponseCookie.Port,
+ Secure = restResponseCookie.Secure,
+ Version = restResponseCookie.Version
+ };
+
+ result.Cookies.Add(cookie);
+ }
+ }
+ return result;
+ }
+ }
+
+ private async Task> DeserializeRestResponseFromPolicyAsync(RestClient client, RestRequest request, PolicyResult policyResult, CancellationToken cancellationToken = default)
+ {
+ if (policyResult.Outcome == OutcomeType.Successful)
+ {
+ return await client.Deserialize(policyResult.Result, cancellationToken);
+ }
+ else
+ {
+ return new RestResponse(request)
+ {
+ ErrorException = policyResult.FinalException
+ };
+ }
+ }
+
+ private ApiResponse Exec(RestRequest request, RequestOptions options, IReadableConfiguration configuration)
+ {
+ Action setOptions = (clientOptions) =>
+ {
+ var cookies = new CookieContainer();
+
+ if (options.Cookies != null && options.Cookies.Count > 0)
+ {
+ foreach (var cookie in options.Cookies)
+ {
+ cookies.Add(new Cookie(cookie.Name, cookie.Value));
+ }
+ }
+ clientOptions.CookieContainer = cookies;
+ };
+
+ Func>> getResponse = (client) =>
+ {
+ if (RetryConfiguration.RetryPolicy != null)
+ {
+ var policy = RetryConfiguration.RetryPolicy;
+ var policyResult = policy.ExecuteAndCapture(() => client.Execute(request));
+ return DeserializeRestResponseFromPolicyAsync(client, request, policyResult);
+ }
+ else
+ {
+ return Task.FromResult(client.Execute(request));
+ }
+ };
+
+ return ExecClientAsync(getResponse, setOptions, request, options, configuration).GetAwaiter().GetResult();
+ }
+
+ {{#supportsAsync}}
+ private Task> ExecAsync(RestRequest request, RequestOptions options, IReadableConfiguration configuration, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ Action setOptions = (clientOptions) =>
+ {
+ //no extra options
+ };
+
+ Func>> getResponse = async (client) =>
+ {
+ {{#supportsRetry}}
+ if (RetryConfiguration.AsyncRetryPolicy != null)
+ {
+ var policy = RetryConfiguration.AsyncRetryPolicy;
+ var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
+ return await DeserializeRestResponseFromPolicyAsync(client, request, policyResult, cancellationToken);
+ }
+ else
+ {
+ {{/supportsRetry}}
+ return await client.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
+ {{#supportsRetry}}
+ }
+ {{/supportsRetry}}
+ };
+
+ return ExecClientAsync(getResponse, setOptions, request, options, configuration);
+ }
+
+ #region IAsynchronousClient
+ ///
+ /// Make a HTTP GET request (async).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// Token that enables callers to cancel the request.
+ /// A Task containing ApiResponse
+ public Task> GetAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, CancellationToken cancellationToken = default)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return ExecAsync(NewRequest(HttpMethod.Get, path, options, config), options, config, cancellationToken);
+ }
+
+ ///
+ /// Make a HTTP POST request (async).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// Token that enables callers to cancel the request.
+ /// A Task containing ApiResponse
+ public Task> PostAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, CancellationToken cancellationToken = default)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return ExecAsync(NewRequest(HttpMethod.Post, path, options, config), options, config, cancellationToken);
+ }
+
+ ///
+ /// Make a HTTP PUT request (async).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// Token that enables callers to cancel the request.
+ /// A Task containing ApiResponse
+ public Task> PutAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, CancellationToken cancellationToken = default)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return ExecAsync(NewRequest(HttpMethod.Put, path, options, config), options, config, cancellationToken);
+ }
+
+ ///
+ /// Make a HTTP DELETE request (async).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// Token that enables callers to cancel the request.
+ /// A Task containing ApiResponse
+ public Task> DeleteAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, CancellationToken cancellationToken = default)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return ExecAsync(NewRequest(HttpMethod.Delete, path, options, config), options, config, cancellationToken);
+ }
+
+ ///
+ /// Make a HTTP HEAD request (async).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// Token that enables callers to cancel the request.
+ /// A Task containing ApiResponse
+ public Task> HeadAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, CancellationToken cancellationToken = default)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return ExecAsync(NewRequest(HttpMethod.Head, path, options, config), options, config, cancellationToken);
+ }
+
+ ///
+ /// Make a HTTP OPTION request (async).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// Token that enables callers to cancel the request.
+ /// A Task containing ApiResponse
+ public Task> OptionsAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, CancellationToken cancellationToken = default)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return ExecAsync(NewRequest(HttpMethod.Options, path, options, config), options, config, cancellationToken);
+ }
+
+ ///
+ /// Make a HTTP PATCH request (async).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// Token that enables callers to cancel the request.
+ /// A Task containing ApiResponse
+ public Task> PatchAsync(string path, RequestOptions options, IReadableConfiguration configuration = null, CancellationToken cancellationToken = default)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return ExecAsync(NewRequest(HttpMethod.Patch, path, options, config), options, config, cancellationToken);
+ }
+ #endregion IAsynchronousClient
+ {{/supportsAsync}}
+
+ #region ISynchronousClient
+ ///
+ /// Make a HTTP GET request (synchronous).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// A Task containing ApiResponse
+ public ApiResponse Get(string path, RequestOptions options, IReadableConfiguration configuration = null)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return Exec(NewRequest(HttpMethod.Get, path, options, config), options, config);
+ }
+
+ ///
+ /// Make a HTTP POST request (synchronous).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// A Task containing ApiResponse
+ public ApiResponse Post(string path, RequestOptions options, IReadableConfiguration configuration = null)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return Exec(NewRequest(HttpMethod.Post, path, options, config), options, config);
+ }
+
+ ///
+ /// Make a HTTP PUT request (synchronous).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// A Task containing ApiResponse
+ public ApiResponse Put(string path, RequestOptions options, IReadableConfiguration configuration = null)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return Exec(NewRequest(HttpMethod.Put, path, options, config), options, config);
+ }
+
+ ///
+ /// Make a HTTP DELETE request (synchronous).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// A Task containing ApiResponse
+ public ApiResponse Delete(string path, RequestOptions options, IReadableConfiguration configuration = null)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return Exec(NewRequest(HttpMethod.Delete, path, options, config), options, config);
+ }
+
+ ///
+ /// Make a HTTP HEAD request (synchronous).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// A Task containing ApiResponse
+ public ApiResponse Head(string path, RequestOptions options, IReadableConfiguration configuration = null)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return Exec(NewRequest(HttpMethod.Head, path, options, config), options, config);
+ }
+
+ ///
+ /// Make a HTTP OPTION request (synchronous).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// A Task containing ApiResponse
+ public ApiResponse Options(string path, RequestOptions options, IReadableConfiguration configuration = null)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return Exec(NewRequest(HttpMethod.Options, path, options, config), options, config);
+ }
+
+ ///
+ /// Make a HTTP PATCH request (synchronous).
+ ///
+ /// The target path (or resource).
+ /// The additional request options.
+ /// A per-request configuration object. It is assumed that any merge with
+ /// GlobalConfiguration has been done before calling this method.
+ /// A Task containing ApiResponse
+ public ApiResponse Patch(string path, RequestOptions options, IReadableConfiguration configuration = null)
+ {
+ var config = configuration ?? GlobalConfiguration.Instance;
+ return Exec(NewRequest(HttpMethod.Patch, path, options, config), options, config);
+ }
+ #endregion ISynchronousClient
+ }
+}
diff --git a/sdks/dotnet/templates/ClientUtils.mustache b/sdks/dotnet/templates/ClientUtils.mustache
index cacf67e42..f8481e37f 100644
--- a/sdks/dotnet/templates/ClientUtils.mustache
+++ b/sdks/dotnet/templates/ClientUtils.mustache
@@ -118,6 +118,14 @@ namespace {{packageName}}.Client
// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8
// For example: 2009-06-15T13:45:30.0000000
return dateTimeOffset.ToString((configuration ?? GlobalConfiguration.Instance).DateTimeFormat);
+{{#net60OrLater}}
+ if (obj is DateOnly dateOnly)
+ // Return a formatted date string - Can be customized with Configuration.DateTimeFormat
+ // Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o")
+ // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8
+ // For example: 2009-06-15
+ return dateOnly.ToString((configuration ?? GlobalConfiguration.Instance).DateTimeFormat);
+{{/net60OrLater}}
if (obj is bool boolean)
return boolean ? "true" : "false";
if (obj is ICollection collection) {
diff --git a/sdks/dotnet/templates/Configuration.mustache b/sdks/dotnet/templates/Configuration.mustache
index 64441d8de..c81ca2623 100644
--- a/sdks/dotnet/templates/Configuration.mustache
+++ b/sdks/dotnet/templates/Configuration.mustache
@@ -216,7 +216,7 @@ namespace {{packageName}}.Client
};
// Setting Timeout has side effects (forces ApiClient creation).
- Timeout = 100000;
+ Timeout = TimeSpan.FromSeconds(100);
}
///
@@ -300,9 +300,9 @@ namespace {{packageName}}.Client
public virtual IDictionary DefaultHeaders { get; set; }
///
- /// Gets or sets the HTTP timeout (milliseconds) of ApiClient. Default to 100000 milliseconds.
+ /// Gets or sets the HTTP timeout of ApiClient. Defaults to 100 seconds.
///
- public virtual int Timeout { get; set; }
+ public virtual TimeSpan Timeout { get; set; }
///
/// Gets or sets the proxy
diff --git a/sdks/dotnet/templates/Configuration.v790.mustache b/sdks/dotnet/templates/Configuration.v790.mustache
new file mode 100644
index 000000000..2753aafb3
--- /dev/null
+++ b/sdks/dotnet/templates/Configuration.v790.mustache
@@ -0,0 +1,737 @@
+{{>partial_header}}
+
+using System;
+{{^net35}}
+using System.Collections.Concurrent;
+{{/net35}}
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Net.Http;
+using System.Net.Security;
+{{#useRestSharp}}
+{{#hasOAuthMethods}}using {{packageName}}.Client.Auth;
+{{/hasOAuthMethods}}
+{{/useRestSharp}}
+
+namespace {{packageName}}.Client
+{
+ ///
+ /// Represents a set of configuration settings
+ ///
+ {{>visibility}} class Configuration : IReadableConfiguration
+ {
+ #region Constants
+
+ ///
+ /// Version of the package.
+ ///
+ /// Version of the package.
+ public const string Version = "{{packageVersion}}";
+
+ ///
+ /// Identifier for ISO 8601 DateTime Format
+ ///
+ /// See https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8 for more information.
+ // ReSharper disable once InconsistentNaming
+ public const string ISO8601_DATETIME_FORMAT = "o";
+
+ #endregion Constants
+
+ #region Static Members
+
+ ///
+ /// Default creation of exceptions for a given method name and response object
+ ///
+ public static readonly ExceptionFactory DefaultExceptionFactory = (methodName, response) =>
+ {
+ var status = (int)response.StatusCode;
+ if (status >= 400)
+ {
+ return new ApiException(status,
+ string.Format("Error calling {0}: {1}", methodName, response.RawContent),
+ response.RawContent, response.Headers);
+ }
+ {{^netStandard}}
+ if (status == 0)
+ {
+ return new ApiException(status,
+ string.Format("Error calling {0}: {1}", methodName, response.ErrorText), response.ErrorText);
+ }
+ {{/netStandard}}
+ return null;
+ };
+
+ #endregion Static Members
+
+ #region Private Members
+
+ ///
+ /// Defines the base path of the target API server.
+ /// Example: http://localhost:3000/v1/
+ ///
+ private string _basePath;
+
+ private bool _useDefaultCredentials = false;
+
+ ///
+ /// Gets or sets the API key based on the authentication name.
+ /// This is the key and value comprising the "secret" for accessing an API.
+ ///
+ /// The API key.
+ private IDictionary _apiKey;
+
+ ///
+ /// Gets or sets the prefix (e.g. Token) of the API key based on the authentication name.
+ ///
+ /// The prefix of the API key.
+ private IDictionary _apiKeyPrefix;
+
+ private string _dateTimeFormat = ISO8601_DATETIME_FORMAT;
+ private string _tempFolderPath = Path.GetTempPath();
+ {{#servers.0}}
+
+ ///
+ /// Gets or sets the servers defined in the OpenAPI spec.
+ ///
+ /// The servers
+ private IList> _servers;
+ {{/servers.0}}
+
+ ///
+ /// Gets or sets the operation servers defined in the OpenAPI spec.
+ ///
+ /// The operation servers
+ private IReadOnlyDictionary>> _operationServers;
+
+ {{#hasHttpSignatureMethods}}
+
+ ///
+ /// HttpSigning configuration
+ ///
+ private HttpSigningConfiguration _HttpSigningConfiguration = null;
+ {{/hasHttpSignatureMethods}}
+ #endregion Private Members
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")]
+ public Configuration()
+ {
+ Proxy = null;
+ UserAgent = WebUtility.UrlEncode("{{httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{packageVersion}}/csharp{{/httpUserAgent}}");
+ BasePath = "{{{basePath}}}";
+ DefaultHeaders = new {{^net35}}Concurrent{{/net35}}Dictionary();
+ ApiKey = new {{^net35}}Concurrent{{/net35}}Dictionary();
+ ApiKeyPrefix = new {{^net35}}Concurrent{{/net35}}Dictionary();
+ {{#servers}}
+ {{#-first}}
+ Servers = new List>()
+ {
+ {{/-first}}
+ {
+ new Dictionary {
+ {"url", "{{{url}}}"},
+ {"description", "{{{description}}}{{^description}}No description provided{{/description}}"},
+ {{#variables}}
+ {{#-first}}
+ {
+ "variables", new Dictionary {
+ {{/-first}}
+ {
+ "{{{name}}}", new Dictionary {
+ {"description", "{{{description}}}{{^description}}No description provided{{/description}}"},
+ {"default_value", {{#isString}}{{^isEnum}}@{{/isEnum}}{{/isString}}"{{{defaultValue}}}"},
+ {{#enumValues}}
+ {{#-first}}
+ {
+ "enum_values", new List() {
+ {{/-first}}
+ "{{{.}}}"{{^-last}},{{/-last}}
+ {{#-last}}
+ }
+ }
+ {{/-last}}
+ {{/enumValues}}
+ }
+ }{{^-last}},{{/-last}}
+ {{#-last}}
+ }
+ }
+ {{/-last}}
+ {{/variables}}
+ }
+ }{{^-last}},{{/-last}}
+ {{#-last}}
+ };
+ {{/-last}}
+ {{/servers}}
+ OperationServers = new Dictionary>>()
+ {
+ {{#apiInfo}}
+ {{#apis}}
+ {{#operations}}
+ {{#operation}}
+ {{#servers.0}}
+ {
+ "{{{classname}}}.{{{nickname}}}", new List>
+ {
+ {{#servers}}
+ {
+ new Dictionary
+ {
+ {"url", "{{{url}}}"},
+ {"description", "{{{description}}}{{^description}}No description provided{{/description}}"}
+ }
+ },
+ {{/servers}}
+ }
+ },
+ {{/servers.0}}
+ {{/operation}}
+ {{/operations}}
+ {{/apis}}
+ {{/apiInfo}}
+ };
+
+ // Setting Timeout has side effects (forces ApiClient creation).
+ Timeout = 100000;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")]
+ public Configuration(
+ IDictionary defaultHeaders,
+ IDictionary apiKey,
+ IDictionary apiKeyPrefix,
+ string basePath = "{{{basePath}}}") : this()
+ {
+ if (string.{{^net35}}IsNullOrWhiteSpace{{/net35}}{{#net35}}IsNullOrEmpty{{/net35}}(basePath))
+ throw new ArgumentException("The provided basePath is invalid.", "basePath");
+ if (defaultHeaders == null)
+ throw new ArgumentNullException("defaultHeaders");
+ if (apiKey == null)
+ throw new ArgumentNullException("apiKey");
+ if (apiKeyPrefix == null)
+ throw new ArgumentNullException("apiKeyPrefix");
+
+ BasePath = basePath;
+
+ foreach (var keyValuePair in defaultHeaders)
+ {
+ DefaultHeaders.Add(keyValuePair);
+ }
+
+ foreach (var keyValuePair in apiKey)
+ {
+ ApiKey.Add(keyValuePair);
+ }
+
+ foreach (var keyValuePair in apiKeyPrefix)
+ {
+ ApiKeyPrefix.Add(keyValuePair);
+ }
+ }
+
+ #endregion Constructors
+
+ #region Properties
+
+ ///
+ /// Gets or sets the base path for API access.
+ ///
+ public virtual string BasePath
+ {
+ get { return _basePath; }
+ set { _basePath = value; }
+ }
+
+ ///
+ /// Determine whether or not the "default credentials" (e.g. the user account under which the current process is running) will be sent along to the server. The default is false.
+ ///
+ public virtual bool UseDefaultCredentials
+ {
+ get { return _useDefaultCredentials; }
+ set { _useDefaultCredentials = value; }
+ }
+
+ ///
+ /// Gets or sets the default header.
+ ///
+ [Obsolete("Use DefaultHeaders instead.")]
+ public virtual IDictionary DefaultHeader
+ {
+ get
+ {
+ return DefaultHeaders;
+ }
+ set
+ {
+ DefaultHeaders = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the default headers.
+ ///
+ public virtual IDictionary DefaultHeaders { get; set; }
+
+ ///
+ /// Gets or sets the HTTP timeout (milliseconds) of ApiClient. Default to 100000 milliseconds.
+ ///
+ public virtual int Timeout { get; set; }
+
+ ///
+ /// Gets or sets the proxy
+ ///
+ /// Proxy.
+ public virtual WebProxy Proxy { get; set; }
+
+ ///
+ /// Gets or sets the HTTP user agent.
+ ///
+ /// Http user agent.
+ public virtual string UserAgent { get; set; }
+
+ ///
+ /// Gets or sets the username (HTTP basic authentication).
+ ///
+ /// The username.
+ public virtual string Username { get; set; }
+
+ ///
+ /// Gets or sets the password (HTTP basic authentication).
+ ///
+ /// The password.
+ public virtual string Password { get; set; }
+
+ ///
+ /// Gets the API key with prefix.
+ ///
+ /// API key identifier (authentication scheme).
+ /// API key with prefix.
+ public string GetApiKeyWithPrefix(string apiKeyIdentifier)
+ {
+ string apiKeyValue;
+ ApiKey.TryGetValue(apiKeyIdentifier, out apiKeyValue);
+ string apiKeyPrefix;
+ if (ApiKeyPrefix.TryGetValue(apiKeyIdentifier, out apiKeyPrefix))
+ {
+ return apiKeyPrefix + " " + apiKeyValue;
+ }
+
+ return apiKeyValue;
+ }
+
+ ///
+ /// Gets or sets certificate collection to be sent with requests.
+ ///
+ /// X509 Certificate collection.
+ public X509CertificateCollection ClientCertificates { get; set; }
+
+ ///
+ /// Gets or sets the access token for OAuth2 authentication.
+ ///
+ /// This helper property simplifies code generation.
+ ///
+ /// The access token.
+ public virtual string AccessToken { get; set; }
+
+ {{#useRestSharp}}
+ {{#hasOAuthMethods}}
+ ///
+ /// Gets or sets the token URL for OAuth2 authentication.
+ ///
+ /// The OAuth Token URL.
+ public virtual string OAuthTokenUrl { get; set; }
+
+ ///
+ /// Gets or sets the client ID for OAuth2 authentication.
+ ///
+ /// The OAuth Client ID.
+ public virtual string OAuthClientId { get; set; }
+
+ ///
+ /// Gets or sets the client secret for OAuth2 authentication.
+ ///
+ /// The OAuth Client Secret.
+ public virtual string OAuthClientSecret { get; set; }
+
+ ///
+ /// Gets or sets the client scope for OAuth2 authentication.
+ ///
+ /// The OAuth Client Scope.
+ public virtual string{{nrt?}} OAuthScope { get; set; }
+
+ ///
+ /// Gets or sets the flow for OAuth2 authentication.
+ ///
+ /// The OAuth Flow.
+ public virtual OAuthFlow? OAuthFlow { get; set; }
+
+ {{/hasOAuthMethods}}
+ {{/useRestSharp}}
+ ///
+ /// Gets or sets the temporary folder path to store the files downloaded from the server.
+ ///
+ /// Folder path.
+ public virtual string TempFolderPath
+ {
+ get { return _tempFolderPath; }
+
+ set
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ _tempFolderPath = Path.GetTempPath();
+ return;
+ }
+
+ // create the directory if it does not exist
+ if (!Directory.Exists(value))
+ {
+ Directory.CreateDirectory(value);
+ }
+
+ // check if the path contains directory separator at the end
+ if (value[value.Length - 1] == Path.DirectorySeparatorChar)
+ {
+ _tempFolderPath = value;
+ }
+ else
+ {
+ _tempFolderPath = value + Path.DirectorySeparatorChar;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the date time format used when serializing in the ApiClient
+ /// By default, it's set to ISO 8601 - "o", for others see:
+ /// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx
+ /// and https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx
+ /// No validation is done to ensure that the string you're providing is valid
+ ///
+ /// The DateTimeFormat string
+ public virtual string DateTimeFormat
+ {
+ get { return _dateTimeFormat; }
+ set
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ // Never allow a blank or null string, go back to the default
+ _dateTimeFormat = ISO8601_DATETIME_FORMAT;
+ return;
+ }
+
+ // Caution, no validation when you choose date time format other than ISO 8601
+ // Take a look at the above links
+ _dateTimeFormat = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the prefix (e.g. Token) of the API key based on the authentication name.
+ ///
+ /// Whatever you set here will be prepended to the value defined in AddApiKey.
+ ///
+ /// An example invocation here might be:
+ ///
+ /// ApiKeyPrefix["Authorization"] = "Bearer";
+ ///
+ /// … where ApiKey["Authorization"] would then be used to set the value of your bearer token.
+ ///
+ ///
+ /// OAuth2 workflows should set tokens via AccessToken.
+ ///
+ ///
+ /// The prefix of the API key.
+ public virtual IDictionary ApiKeyPrefix
+ {
+ get { return _apiKeyPrefix; }
+ set
+ {
+ if (value == null)
+ {
+ throw new InvalidOperationException("ApiKeyPrefix collection may not be null.");
+ }
+ _apiKeyPrefix = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the API key based on the authentication name.
+ ///
+ /// The API key.
+ public virtual IDictionary ApiKey
+ {
+ get { return _apiKey; }
+ set
+ {
+ if (value == null)
+ {
+ throw new InvalidOperationException("ApiKey collection may not be null.");
+ }
+ _apiKey = value;
+ }
+ }
+ {{#servers.0}}
+
+ ///
+ /// Gets or sets the servers.
+ ///
+ /// The servers.
+ public virtual IList> Servers
+ {
+ get { return _servers; }
+ set
+ {
+ if (value == null)
+ {
+ throw new InvalidOperationException("Servers may not be null.");
+ }
+ _servers = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the operation servers.
+ ///
+ /// The operation servers.
+ public virtual IReadOnlyDictionary>> OperationServers
+ {
+ get { return _operationServers; }
+ set
+ {
+ if (value == null)
+ {
+ throw new InvalidOperationException("Operation servers may not be null.");
+ }
+ _operationServers = value;
+ }
+ }
+
+ ///
+ /// Returns URL based on server settings without providing values
+ /// for the variables
+ ///
+ /// Array index of the server settings.
+ /// The server URL.
+ public string GetServerUrl(int index)
+ {
+ return GetServerUrl(Servers, index, null);
+ }
+
+ ///
+ /// Returns URL based on server settings.
+ ///
+ /// Array index of the server settings.
+ /// Dictionary of the variables and the corresponding values.
+ /// The server URL.
+ public string GetServerUrl(int index, Dictionary inputVariables)
+ {
+ return GetServerUrl(Servers, index, inputVariables);
+ }
+
+ ///
+ /// Returns URL based on operation server settings.
+ ///
+ /// Operation associated with the request path.
+ /// Array index of the server settings.
+ /// The operation server URL.
+ public string GetOperationServerUrl(string operation, int index)
+ {
+ return GetOperationServerUrl(operation, index, null);
+ }
+
+ ///
+ /// Returns URL based on operation server settings.
+ ///
+ /// Operation associated with the request path.
+ /// Array index of the server settings.
+ /// Dictionary of the variables and the corresponding values.
+ /// The operation server URL.
+ public string GetOperationServerUrl(string operation, int index, Dictionary inputVariables)
+ {
+ if (operation != null && OperationServers.TryGetValue(operation, out var operationServer))
+ {
+ return GetServerUrl(operationServer, index, inputVariables);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Returns URL based on server settings.
+ ///
+ /// Dictionary of server settings.
+ /// Array index of the server settings.
+ /// Dictionary of the variables and the corresponding values.
+ /// The server URL.
+ private string GetServerUrl(IList> servers, int index, Dictionary inputVariables)
+ {
+ if (index < 0 || index >= servers.Count)
+ {
+ throw new InvalidOperationException($"Invalid index {index} when selecting the server. Must be less than {servers.Count}.");
+ }
+
+ if (inputVariables == null)
+ {
+ inputVariables = new Dictionary();
+ }
+
+ IReadOnlyDictionary server = servers[index];
+ string url = (string)server["url"];
+
+ if (server.ContainsKey("variables"))
+ {
+ // go through each variable and assign a value
+ foreach (KeyValuePair variable in (IReadOnlyDictionary)server["variables"])
+ {
+
+ IReadOnlyDictionary serverVariables = (IReadOnlyDictionary)(variable.Value);
+
+ if (inputVariables.ContainsKey(variable.Key))
+ {
+ if (((List)serverVariables["enum_values"]).Contains(inputVariables[variable.Key]))
+ {
+ url = url.Replace("{" + variable.Key + "}", inputVariables[variable.Key]);
+ }
+ else
+ {
+ throw new InvalidOperationException($"The variable `{variable.Key}` in the server URL has invalid value #{inputVariables[variable.Key]}. Must be {(List)serverVariables["enum_values"]}");
+ }
+ }
+ else
+ {
+ // use default value
+ url = url.Replace("{" + variable.Key + "}", (string)serverVariables["default_value"]);
+ }
+ }
+ }
+
+ return url;
+ }
+ {{/servers.0}}
+ {{#hasHttpSignatureMethods}}
+
+ ///
+ /// Gets and Sets the HttpSigningConfiguration
+ ///
+ public HttpSigningConfiguration HttpSigningConfiguration
+ {
+ get { return _HttpSigningConfiguration; }
+ set { _HttpSigningConfiguration = value; }
+ }
+ {{/hasHttpSignatureMethods}}
+
+ ///
+ /// Gets and Sets the RemoteCertificateValidationCallback
+ ///
+ public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; }
+
+ #endregion Properties
+
+ #region Methods
+
+ ///
+ /// Returns a string with essential information for debugging.
+ ///
+ public static string ToDebugReport()
+ {
+ string report = "C# SDK ({{{packageName}}}) Debug Report:\n";
+ report += " OS: " + System.Environment.OSVersion + "\n";
+ report += " .NET Framework Version: " + System.Environment.Version + "\n";
+ report += " Version of the API: {{{version}}}\n";
+ report += " SDK Package Version: {{{packageVersion}}}\n";
+
+ return report;
+ }
+
+ ///
+ /// Add Api Key Header.
+ ///
+ /// Api Key name.
+ /// Api Key value.
+ ///
+ public void AddApiKey(string key, string value)
+ {
+ ApiKey[key] = value;
+ }
+
+ ///
+ /// Sets the API key prefix.
+ ///
+ /// Api Key name.
+ /// Api Key value.
+ public void AddApiKeyPrefix(string key, string value)
+ {
+ ApiKeyPrefix[key] = value;
+ }
+
+ #endregion Methods
+
+ #region Static Members
+ ///
+ /// Merge configurations.
+ ///
+ /// First configuration.
+ /// Second configuration.
+ /// Merged configuration.
+ public static IReadableConfiguration MergeConfigurations(IReadableConfiguration first, IReadableConfiguration second)
+ {
+ if (second == null) return first ?? GlobalConfiguration.Instance;
+
+ Dictionary apiKey = first.ApiKey.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
+ Dictionary apiKeyPrefix = first.ApiKeyPrefix.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
+ Dictionary defaultHeaders = first.DefaultHeaders.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
+
+ foreach (var kvp in second.ApiKey) apiKey[kvp.Key] = kvp.Value;
+ foreach (var kvp in second.ApiKeyPrefix) apiKeyPrefix[kvp.Key] = kvp.Value;
+ foreach (var kvp in second.DefaultHeaders) defaultHeaders[kvp.Key] = kvp.Value;
+
+ var config = new Configuration
+ {
+ ApiKey = apiKey,
+ ApiKeyPrefix = apiKeyPrefix,
+ DefaultHeaders = defaultHeaders,
+ BasePath = second.BasePath ?? first.BasePath,
+ Timeout = second.Timeout,
+ Proxy = second.Proxy ?? first.Proxy,
+ UserAgent = second.UserAgent ?? first.UserAgent,
+ Username = second.Username ?? first.Username,
+ Password = second.Password ?? first.Password,
+ AccessToken = second.AccessToken ?? first.AccessToken,
+ {{#useRestSharp}}
+ {{#hasOAuthMethods}}
+ OAuthTokenUrl = second.OAuthTokenUrl ?? first.OAuthTokenUrl,
+ OAuthClientId = second.OAuthClientId ?? first.OAuthClientId,
+ OAuthClientSecret = second.OAuthClientSecret ?? first.OAuthClientSecret,
+ OAuthScope = second.OAuthScope ?? first.OAuthScope,
+ OAuthFlow = second.OAuthFlow ?? first.OAuthFlow,
+ {{/hasOAuthMethods}}
+ {{/useRestSharp}}
+ {{#hasHttpSignatureMethods}}
+ HttpSigningConfiguration = second.HttpSigningConfiguration ?? first.HttpSigningConfiguration,
+ {{/hasHttpSignatureMethods}}
+ TempFolderPath = second.TempFolderPath ?? first.TempFolderPath,
+ DateTimeFormat = second.DateTimeFormat ?? first.DateTimeFormat,
+ ClientCertificates = second.ClientCertificates ?? first.ClientCertificates,
+ UseDefaultCredentials = second.UseDefaultCredentials,
+ RemoteCertificateValidationCallback = second.RemoteCertificateValidationCallback ?? first.RemoteCertificateValidationCallback,
+ };
+ return config;
+ }
+ #endregion Static Members
+ }
+}
diff --git a/sdks/dotnet/templates/HttpSigningConfiguration.mustache b/sdks/dotnet/templates/HttpSigningConfiguration.mustache
index faca67594..97b855dc5 100644
--- a/sdks/dotnet/templates/HttpSigningConfiguration.mustache
+++ b/sdks/dotnet/templates/HttpSigningConfiguration.mustache
@@ -133,16 +133,18 @@ namespace {{packageName}}.Client
foreach (var parameter in requestOptions.QueryParameters)
{
#if (NETCOREAPP)
+ string framework = RuntimeInformation.FrameworkDescription;
+ string key = framework.StartsWith(".NET 9")?parameter.Key:HttpUtility.UrlEncode(parameter.Key);
if (parameter.Value.Count > 1)
{ // array
foreach (var value in parameter.Value)
{
- httpValues.Add(HttpUtility.UrlEncode(parameter.Key) + "[]", value);
+ httpValues.Add(key + "[]", value);
}
}
else
{
- httpValues.Add(HttpUtility.UrlEncode(parameter.Key), parameter.Value[0]);
+ httpValues.Add(key, parameter.Value[0]);
}
#else
if (parameter.Value.Count > 1)
@@ -389,7 +391,7 @@ namespace {{packageName}}.Client
}
///
- /// Convert ANS1 format to DER format. Not recommended to use because it generate inavlid signature occationally.
+ /// Convert ANS1 format to DER format. Not recommended to use because it generate invalid signature occasionally.
///
///
///
diff --git a/sdks/dotnet/templates/IReadableConfiguration.mustache b/sdks/dotnet/templates/IReadableConfiguration.mustache
index 5981728b4..6712aa632 100644
--- a/sdks/dotnet/templates/IReadableConfiguration.mustache
+++ b/sdks/dotnet/templates/IReadableConfiguration.mustache
@@ -101,10 +101,10 @@ namespace {{packageName}}.Client
string TempFolderPath { get; }
///
- /// Gets the HTTP connection timeout (in milliseconds)
+ /// Gets the HTTP connection timeout.
///
/// HTTP connection timeout.
- int Timeout { get; }
+ TimeSpan Timeout { get; }
///
/// Gets the proxy.
diff --git a/sdks/dotnet/templates/IReadableConfiguration.v790.mustache b/sdks/dotnet/templates/IReadableConfiguration.v790.mustache
new file mode 100644
index 000000000..5981728b4
--- /dev/null
+++ b/sdks/dotnet/templates/IReadableConfiguration.v790.mustache
@@ -0,0 +1,178 @@
+{{>partial_header}}
+
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+{{#useRestSharp}}
+{{#hasOAuthMethods}}using {{packageName}}.Client.Auth;
+{{/hasOAuthMethods}}
+{{/useRestSharp}}
+
+namespace {{packageName}}.Client
+{
+ ///
+ /// Represents a readable-only configuration contract.
+ ///
+ public interface IReadableConfiguration
+ {
+ ///
+ /// Gets the access token.
+ ///
+ /// Access token.
+ string AccessToken { get; }
+
+ {{#useRestSharp}}
+ {{#hasOAuthMethods}}
+ ///
+ /// Gets the OAuth token URL.
+ ///
+ /// OAuth Token URL.
+ string OAuthTokenUrl { get; }
+
+ ///
+ /// Gets the OAuth client ID.
+ ///
+ /// OAuth Client ID.
+ string OAuthClientId { get; }
+
+ ///
+ /// Gets the OAuth client secret.
+ ///
+ /// OAuth Client Secret.
+ string OAuthClientSecret { get; }
+
+ ///
+ /// Gets the OAuth token scope.
+ ///
+ /// OAuth Token scope.
+ string{{nrt?}} OAuthScope { get; }
+
+ ///
+ /// Gets the OAuth flow.
+ ///
+ /// OAuth Flow.
+ OAuthFlow? OAuthFlow { get; }
+
+ {{/hasOAuthMethods}}
+ {{/useRestSharp}}
+ ///
+ /// Gets the API key.
+ ///
+ /// API key.
+ IDictionary ApiKey { get; }
+
+ ///
+ /// Gets the API key prefix.
+ ///
+ /// API key prefix.
+ IDictionary ApiKeyPrefix { get; }
+
+ ///
+ /// Gets the base path.
+ ///
+ /// Base path.
+ string BasePath { get; }
+
+ ///
+ /// Gets the date time format.
+ ///
+ /// Date time format.
+ string DateTimeFormat { get; }
+
+ ///
+ /// Gets the default header.
+ ///
+ /// Default header.
+ [Obsolete("Use DefaultHeaders instead.")]
+ IDictionary DefaultHeader { get; }
+
+ ///
+ /// Gets the default headers.
+ ///
+ /// Default headers.
+ IDictionary DefaultHeaders { get; }
+
+ ///
+ /// Gets the temp folder path.
+ ///
+ /// Temp folder path.
+ string TempFolderPath { get; }
+
+ ///
+ /// Gets the HTTP connection timeout (in milliseconds)
+ ///
+ /// HTTP connection timeout.
+ int Timeout { get; }
+
+ ///
+ /// Gets the proxy.
+ ///
+ /// Proxy.
+ WebProxy Proxy { get; }
+
+ ///
+ /// Gets the user agent.
+ ///
+ /// User agent.
+ string UserAgent { get; }
+
+ ///
+ /// Gets the username.
+ ///
+ /// Username.
+ string Username { get; }
+
+ ///
+ /// Gets the password.
+ ///
+ /// Password.
+ string Password { get; }
+
+ ///
+ /// Determine whether or not the "default credentials" (e.g. the user account under which the current process is running) will be sent along to the server. The default is false.
+ ///
+ bool UseDefaultCredentials { get; }
+
+ ///
+ /// Get the servers associated with the operation.
+ ///
+ /// Operation servers.
+ IReadOnlyDictionary>> OperationServers { get; }
+
+ ///
+ /// Gets the API key with prefix.
+ ///
+ /// API key identifier (authentication scheme).
+ /// API key with prefix.
+ string GetApiKeyWithPrefix(string apiKeyIdentifier);
+
+ ///
+ /// Gets the Operation server url at the provided index.
+ ///
+ /// Operation server name.
+ /// Index of the operation server settings.
+ ///
+ string GetOperationServerUrl(string operation, int index);
+
+ ///
+ /// Gets certificate collection to be sent with requests.
+ ///
+ /// X509 Certificate collection.
+ X509CertificateCollection ClientCertificates { get; }
+ {{#hasHttpSignatureMethods}}
+
+ ///
+ /// Gets the HttpSigning configuration
+ ///
+ HttpSigningConfiguration HttpSigningConfiguration { get; }
+ {{/hasHttpSignatureMethods}}
+
+ ///
+ /// Callback function for handling the validation of remote certificates. Useful for certificate pinning and
+ /// overriding certificate errors in the scope of a request.
+ ///
+ RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; }
+ }
+}
diff --git a/sdks/dotnet/templates/README.mustache b/sdks/dotnet/templates/README.mustache
index f70a5dae2..7455a8f95 100644
--- a/sdks/dotnet/templates/README.mustache
+++ b/sdks/dotnet/templates/README.mustache
@@ -67,7 +67,7 @@ this command.
## Dependencies
{{#useRestSharp}}
-- [RestSharp](https://www.nuget.org/packages/RestSharp) - 106.13.0 or later
+- [RestSharp](https://www.nuget.org/packages/RestSharp) - 112.0.0 or later
{{/useRestSharp}}
- [Json.NET](https://www.nuget.org/packages/Newtonsoft.Json/) - 13.0.2 or later
- [JsonSubTypes](https://www.nuget.org/packages/JsonSubTypes/) - 1.8.0 or later
diff --git a/sdks/dotnet/templates/Solution.mustache b/sdks/dotnet/templates/Solution.mustache
index f5589670a..268f8c7f8 100644
--- a/sdks/dotnet/templates/Solution.mustache
+++ b/sdks/dotnet/templates/Solution.mustache
@@ -2,14 +2,16 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio {{^netStandard}}2012{{/netStandard}}{{#netStandard}}14{{/netStandard}}
VisualStudioVersion = {{^netStandard}}12.0.0.0{{/netStandard}}{{#netStandard}}14.0.25420.1{{/netStandard}}
MinimumVisualStudioVersion = {{^netStandard}}10.0.0.1{{/netStandard}}{{#netStandard}}10.0.40219.1{{/netStandard}}
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{packageName}}", "src\{{packageName}}\{{packageName}}.csproj", "{{packageGuid}}"
-EndProject
{{^useCustomTemplateCode}}
-{{^excludeTests}}Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{testPackageName}}", "src\{{testPackageName}}\{{testPackageName}}.csproj", "{19F1DEBC-DE5E-4517-8062-F000CD499087}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{packageName}}", "{{sourceFolder}}\{{packageName}}\{{packageName}}.csproj", "{{packageGuid}}"
+EndProject
+{{^excludeTests}}Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{testPackageName}}", "{{sourceFolder}}\{{testPackageName}}\{{testPackageName}}.csproj", "{19F1DEBC-DE5E-4517-8062-F000CD499087}"
EndProject
{{/excludeTests}}Global
{{/useCustomTemplateCode}}
{{#useCustomTemplateCode}}
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{packageName}}", "src\{{packageName}}\{{packageName}}.csproj", "{{packageGuid}}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dropbox.Sign.Test", "src\Dropbox.Sign.Test\Dropbox.Sign.Test.csproj", "{C305EB17-93FE-4BDA-89A4-120BD8C8A88A}"
EndProject
Global
diff --git a/sdks/dotnet/templates/api.mustache b/sdks/dotnet/templates/api.mustache
index 632833ab9..c0b29af2e 100644
--- a/sdks/dotnet/templates/api.mustache
+++ b/sdks/dotnet/templates/api.mustache
@@ -317,6 +317,7 @@ namespace {{packageName}}.{{apiPackage}}
{{^useCustomTemplateCode}}
var localVarContentType = {{packageName}}.Client.ClientUtils.SelectHeaderContentType(_contentTypes);
+ var localVarMultipartFormData = localVarContentType == "multipart/form-data";
{{/useCustomTemplateCode}}
if (localVarContentType != null)
{
@@ -403,7 +404,7 @@ namespace {{packageName}}.{{apiPackage}}
{{/isArray}}
{{/isFile}}
{{^isFile}}
- localVarRequestOptions.FormParameters.Add("{{baseName}}", {{packageName}}.Client.ClientUtils.{{#isPrimitiveType}}ParameterToString{{/isPrimitiveType}}{{^isPrimitiveType}}Serialize{{/isPrimitiveType}}({{paramName}})); // form parameter
+ localVarRequestOptions.FormParameters.Add("{{baseName}}", {{#isPrimitiveType}}{{packageName}}.Client.ClientUtils.ParameterToString({{paramName}}){{/isPrimitiveType}}{{^isPrimitiveType}}localVarMultipartFormData ? {{packageName}}.Client.ClientUtils.ParameterToString({{paramName}}) : {{packageName}}.Client.ClientUtils.Serialize({{paramName}}){{/isPrimitiveType}}); // form parameter
{{/isFile}}
{{/required}}
{{^required}}
@@ -425,7 +426,7 @@ namespace {{packageName}}.{{apiPackage}}
{{/isArray}}
{{/isFile}}
{{^isFile}}
- localVarRequestOptions.FormParameters.Add("{{baseName}}", {{packageName}}.Client.ClientUtils.{{#isPrimitiveType}}ParameterToString{{/isPrimitiveType}}{{^isPrimitiveType}}Serialize{{/isPrimitiveType}}({{paramName}})); // form parameter
+ localVarRequestOptions.FormParameters.Add("{{baseName}}", {{#isPrimitiveType}}{{packageName}}.Client.ClientUtils.ParameterToString({{paramName}}){{/isPrimitiveType}}{{^isPrimitiveType}}localVarMultipartFormData ? {{packageName}}.Client.ClientUtils.ParameterToString({{paramName}}) : {{packageName}}.Client.ClientUtils.Serialize({{paramName}}){{/isPrimitiveType}}); // form parameter
{{/isFile}}
}
{{/required}}
diff --git a/sdks/dotnet/templates/auth/OAuthAuthenticator.mustache b/sdks/dotnet/templates/auth/OAuthAuthenticator.mustache
index d71f262a8..111270ebf 100644
--- a/sdks/dotnet/templates/auth/OAuthAuthenticator.mustache
+++ b/sdks/dotnet/templates/auth/OAuthAuthenticator.mustache
@@ -11,8 +11,25 @@ namespace {{packageName}}.Client.Auth
///
/// An authenticator for OAuth2 authentication flows
///
- public class OAuthAuthenticator : AuthenticatorBase
+ public class OAuthAuthenticator : IAuthenticator
{
+ private TokenResponse{{nrt?}} _token;
+
+ ///
+ /// Returns the current authentication token. Can return null if there is no authentication token, or it has expired.
+ ///
+ public string{{nrt?}} Token
+ {
+ get
+ {
+ if (_token == null) return null;
+ if (_token.ExpiresIn == null) return _token.AccessToken;
+ if (_token.ExpiresAt < DateTime.Now) return null;
+
+ return _token.AccessToken;
+ }
+ }
+
readonly string _tokenUrl;
readonly string _clientId;
readonly string _clientSecret;
@@ -31,7 +48,7 @@ namespace {{packageName}}.Client.Auth
string{{nrt?}} scope,
OAuthFlow? flow,
JsonSerializerSettings serializerSettings,
- IReadableConfiguration configuration) : base("")
+ IReadableConfiguration configuration)
{
_tokenUrl = tokenUrl;
_clientId = clientId;
@@ -62,9 +79,13 @@ namespace {{packageName}}.Client.Auth
///
/// Creates an authentication parameter from an access token.
///
- /// Access token to create a parameter from.
/// An authentication parameter.
- protected override async ValueTask GetAuthenticationParameter(string accessToken)
+{{^useCustomTemplateCode}}
+ protected async ValueTask GetAuthenticationParameter()
+{{/useCustomTemplateCode}}
+{{#useCustomTemplateCode}}
+ protected async ValueTask GetAuthenticationParameter(string accessToken)
+{{/useCustomTemplateCode}}
{
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
return new HeaderParameter(KnownHeaders.Authorization, token);
@@ -76,31 +97,45 @@ namespace {{packageName}}.Client.Auth
/// An authentication token.
async Task GetToken()
{
- var client = new RestClient(_tokenUrl,
- configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
-
- var request = new RestRequest()
- .AddParameter("grant_type", _grantType)
- .AddParameter("client_id", _clientId)
- .AddParameter("client_secret", _clientSecret);
+ var client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
+ var request = new RestRequest();
+ if (!string.IsNullOrWhiteSpace(_token?.RefreshToken))
+ {
+ request.AddParameter("grant_type", "refresh_token")
+ .AddParameter("refresh_token", _token.RefreshToken);
+ }
+ else
+ {
+ request
+ .AddParameter("grant_type", _grantType)
+ .AddParameter("client_id", _clientId)
+ .AddParameter("client_secret", _clientSecret);
+ }
if (!string.IsNullOrEmpty(_scope))
{
request.AddParameter("scope", _scope);
}
-
- var response = await client.PostAsync(request).ConfigureAwait(false);
-
+ _token = await client.PostAsync(request).ConfigureAwait(false);
// RFC6749 - token_type is case insensitive.
// RFC6750 - In Authorization header Bearer should be capitalized.
// Fix the capitalization irrespective of token_type casing.
- switch (response.TokenType?.ToLower())
+ switch (_token?.TokenType?.ToLower())
{
case "bearer":
- return $"Bearer {response.AccessToken}";
+ return $"Bearer {_token.AccessToken}";
default:
- return $"{response.TokenType} {response.AccessToken}";
+ return $"{_token?.TokenType} {_token?.AccessToken}";
}
}
+
+ ///
+ /// Retrieves the authentication token (creating a new one if necessary) and adds it to the current request
+ ///
+ ///
+ ///
+ ///
+ public async ValueTask Authenticate(IRestClient client, RestRequest request)
+ => request.AddOrUpdateParameter(await GetAuthenticationParameter().ConfigureAwait(false));
}
}
diff --git a/sdks/dotnet/templates/auth/TokenResponse.mustache b/sdks/dotnet/templates/auth/TokenResponse.mustache
index f118b97a9..7a72e04c1 100644
--- a/sdks/dotnet/templates/auth/TokenResponse.mustache
+++ b/sdks/dotnet/templates/auth/TokenResponse.mustache
@@ -1,5 +1,6 @@
{{>partial_header}}
+using System;
using Newtonsoft.Json;
namespace {{packageName}}.Client.Auth
@@ -10,5 +11,14 @@ namespace {{packageName}}.Client.Auth
public string TokenType { get; set; }
[JsonProperty("access_token")]
public string AccessToken { get; set; }
+ [JsonProperty("expires_in")]
+ public int? ExpiresIn { get; set; }
+ [JsonProperty("created")]
+ public DateTime? Created { get; set; }
+
+ [JsonProperty("refresh_token")]
+ public string{{nrt?}} RefreshToken { get; set; }
+
+ public DateTime? ExpiresAt => ExpiresIn == null ? null : Created?.AddSeconds(ExpiresIn.Value);
}
}
\ No newline at end of file
diff --git a/sdks/dotnet/templates/gitignore.mustache b/sdks/dotnet/templates/gitignore.mustache
index a41122f00..da28f4ecd 100644
--- a/sdks/dotnet/templates/gitignore.mustache
+++ b/sdks/dotnet/templates/gitignore.mustache
@@ -364,6 +364,8 @@ MigrationBackup/
FodyWeavers.xsd
{{#useCustomTemplateCode}}
+git_push.sh
+global.json
vendor
/api
.openapi-generator
diff --git a/sdks/dotnet/templates/libraries/generichost/ApiTestsBase.mustache b/sdks/dotnet/templates/libraries/generichost/ApiTestsBase.mustache
index 3292a1e86..c71bc79b9 100644
--- a/sdks/dotnet/templates/libraries/generichost/ApiTestsBase.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/ApiTestsBase.mustache
@@ -31,7 +31,7 @@ namespace {{packageName}}.Test.{{apiPackage}}
{{#lambda.trimTrailingWithNewLine}}
{{#apiKeyMethods}}
string apiKeyTokenValue{{-index}} = context.Configuration[""] ?? throw new Exception("Token not found.");
- ApiKeyToken apiKeyToken{{-index}} = new{{^net70OrLater}} ApiKeyToken{{/net70OrLater}}(apiKeyTokenValue{{-index}}, ClientUtils.ApiKeyHeader.{{#lambda.titlecase}}{{keyParamName}}{{/lambda.titlecase}}, timeout: TimeSpan.FromSeconds(1));
+ ApiKeyToken apiKeyToken{{-index}} = new{{^net70OrLater}} ApiKeyToken{{/net70OrLater}}(apiKeyTokenValue{{-index}}, ClientUtils.ApiKeyHeader.{{#lambda.titlecase}}{{#lambda.alphabet_or_underscore}}{{keyParamName}}{{/lambda.alphabet_or_underscore}}{{/lambda.titlecase}}, timeout: TimeSpan.FromSeconds(1));
options.AddTokens(apiKeyToken{{-index}});
{{/apiKeyMethods}}
diff --git a/sdks/dotnet/templates/libraries/generichost/ClientUtils.mustache b/sdks/dotnet/templates/libraries/generichost/ClientUtils.mustache
index 269d20c4d..357d2197c 100644
--- a/sdks/dotnet/templates/libraries/generichost/ClientUtils.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/ClientUtils.mustache
@@ -12,7 +12,11 @@ using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;{{#useCompareNetObjects}}
using KellermanSoftware.CompareNetObjects;{{/useCompareNetObjects}}
+{{#models}}
+{{#-first}}
using {{packageName}}.{{modelPackage}};
+{{/-first}}
+{{/models}}
using System.Runtime.CompilerServices;
{{>Assembly}}namespace {{packageName}}.{{clientPackage}}
@@ -20,7 +24,7 @@ using System.Runtime.CompilerServices;
///
/// Utility functions providing some benefit to API client consumers.
///
- {{>visibility}} static class ClientUtils
+ {{>visibility}} static {{#net70OrLater}}partial {{/net70OrLater}}class ClientUtils
{
{{#useCompareNetObjects}}
///
@@ -60,7 +64,7 @@ using System.Runtime.CompilerServices;
///
/// The {{keyParamName}} header
///
- {{#lambda.titlecase}}{{keyParamName}}{{/lambda.titlecase}}{{^-last}},{{/-last}}
+ {{#lambda.titlecase}}{{#lambda.alphabet_or_underscore}}{{keyParamName}}{{/lambda.alphabet_or_underscore}}{{/lambda.titlecase}}{{^-last}},{{/-last}}
{{/apiKeyMethods}}
}
@@ -76,7 +80,7 @@ using System.Runtime.CompilerServices;
return value switch
{
{{#apiKeyMethods}}
- ApiKeyHeader.{{#lambda.titlecase}}{{keyParamName}}{{/lambda.titlecase}} => "{{keyParamName}}",
+ ApiKeyHeader.{{#lambda.titlecase}}{{#lambda.alphabet_or_underscore}}{{keyParamName}}{{/lambda.alphabet_or_underscore}}{{/lambda.titlecase}} => "{{keyParamName}}",
{{/apiKeyMethods}}
_ => throw new System.ComponentModel.InvalidEnumArgumentException(nameof(value), (int)value, typeof(ApiKeyHeader)),
};
@@ -85,7 +89,7 @@ using System.Runtime.CompilerServices;
switch(value)
{
{{#apiKeyMethods}}
- case ApiKeyHeader.{{#lambda.titlecase}}{{keyParamName}}{{/lambda.titlecase}}:
+ case ApiKeyHeader.{{#lambda.titlecase}}{{#lambda.alphabet_or_underscore}}{{keyParamName}}{{/lambda.alphabet_or_underscore}}{{/lambda.titlecase}}:
return "{{keyParamName}}";
{{/apiKeyMethods}}
default:
@@ -139,17 +143,6 @@ using System.Runtime.CompilerServices;
}
}
- ///
- /// Sanitize filename by removing the path
- ///
- /// Filename
- /// Filename
- public static string SanitizeFilename(string filename)
- {
- Match match = Regex.Match(filename, @".*[/\\](.*)$");
- return match.Success ? match.Groups[1].Value : filename;
- }
-
///
/// If parameter is DateTime, output in a formatted string (default ISO 8601), customizable with Configuration.DateTime.
/// If parameter is a list, join the list with ",".
@@ -172,6 +165,10 @@ using System.Runtime.CompilerServices;
// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8
// For example: 2009-06-15T13:45:30.0000000
return dateTimeOffset.ToString(format);
+ {{#net60OrLater}}
+ if (obj is DateOnly dateOnly)
+ return dateOnly.ToString(format);
+ {{/net60OrLater}}
if (obj is bool boolean)
return boolean
? "true"
@@ -317,7 +314,13 @@ using System.Runtime.CompilerServices;
///
/// Provides a case-insensitive check that a provided content type is a known JSON-like content type.
///
- public static readonly Regex JsonRegex = new Regex("(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$");
+ {{#net70OrLater}}
+ [GeneratedRegex("(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$")]
+ private static partial Regex JsonRegex();
+ {{/net70OrLater}}
+ {{^net70OrLater}}
+ private static readonly Regex JsonRegex = new Regex("(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$");
+ {{/net70OrLater}}
///
/// Check if the given MIME is a JSON MIME.
@@ -333,7 +336,7 @@ using System.Runtime.CompilerServices;
{
if (string.IsNullOrWhiteSpace(mime)) return false;
- return JsonRegex.IsMatch(mime) || mime.Equals("application/json-patch+json");
+ return {{#net70OrLater}}JsonRegex(){{/net70OrLater}}{{^net70OrLater}}JsonRegex{{/net70OrLater}}.IsMatch(mime) || mime.Equals("application/json-patch+json");
}
///
diff --git a/sdks/dotnet/templates/libraries/generichost/DependencyInjectionTests.mustache b/sdks/dotnet/templates/libraries/generichost/DependencyInjectionTests.mustache
index aadf2c731..6085b51e5 100644
--- a/sdks/dotnet/templates/libraries/generichost/DependencyInjectionTests.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/DependencyInjectionTests.mustache
@@ -21,7 +21,7 @@ namespace {{packageName}}.Test.{{apiPackage}}
{
{{#lambda.trimTrailingWithNewLine}}
{{#apiKeyMethods}}
- ApiKeyToken apiKeyToken{{-index}} = new{{^net70OrLater}} ApiKeyToken{{/net70OrLater}}("", ClientUtils.ApiKeyHeader.{{#lambda.titlecase}}{{keyParamName}}{{/lambda.titlecase}}, timeout: TimeSpan.FromSeconds(1));
+ ApiKeyToken apiKeyToken{{-index}} = new{{^net70OrLater}} ApiKeyToken{{/net70OrLater}}("", ClientUtils.ApiKeyHeader.{{#lambda.titlecase}}{{#lambda.alphabet_or_underscore}}{{keyParamName}}{{/lambda.alphabet_or_underscore}}{{/lambda.titlecase}}, timeout: TimeSpan.FromSeconds(1));
options.AddTokens(apiKeyToken{{-index}});
{{/apiKeyMethods}}
@@ -55,7 +55,7 @@ namespace {{packageName}}.Test.{{apiPackage}}
{
{{#lambda.trimTrailingWithNewLine}}
{{#apiKeyMethods}}
- ApiKeyToken apiKeyToken{{-index}} = new{{^net70OrLater}} ApiKeyToken{{/net70OrLater}}("", ClientUtils.ApiKeyHeader.{{#lambda.titlecase}}{{keyParamName}}{{/lambda.titlecase}}, timeout: TimeSpan.FromSeconds(1));
+ ApiKeyToken apiKeyToken{{-index}} = new{{^net70OrLater}} ApiKeyToken{{/net70OrLater}}("", ClientUtils.ApiKeyHeader.{{#lambda.titlecase}}{{#lambda.alphabet_or_underscore}}{{keyParamName}}{{/lambda.alphabet_or_underscore}}{{/lambda.titlecase}}, timeout: TimeSpan.FromSeconds(1));
options.AddTokens(apiKeyToken{{-index}});
{{/apiKeyMethods}}
@@ -92,7 +92,7 @@ namespace {{packageName}}.Test.{{apiPackage}}
{
{{#lambda.trimTrailingWithNewLine}}
{{#apiKeyMethods}}
- ApiKeyToken apiKeyToken{{-index}} = new{{^net70OrLater}} ApiKeyToken{{/net70OrLater}}("", ClientUtils.ApiKeyHeader.{{#lambda.titlecase}}{{keyParamName}}{{/lambda.titlecase}}, timeout: TimeSpan.FromSeconds(1));
+ ApiKeyToken apiKeyToken{{-index}} = new{{^net70OrLater}} ApiKeyToken{{/net70OrLater}}("", ClientUtils.ApiKeyHeader.{{#lambda.titlecase}}{{#lambda.alphabet_or_underscore}}{{keyParamName}}{{/lambda.alphabet_or_underscore}}{{/lambda.titlecase}}, timeout: TimeSpan.FromSeconds(1));
options.AddTokens(apiKeyToken{{-index}});
{{/apiKeyMethods}}
@@ -129,7 +129,7 @@ namespace {{packageName}}.Test.{{apiPackage}}
{
{{#lambda.trimTrailingWithNewLine}}
{{#apiKeyMethods}}
- ApiKeyToken apiKeyToken{{-index}} = new{{^net70OrLater}} ApiKeyToken{{/net70OrLater}}("", ClientUtils.ApiKeyHeader.{{#lambda.titlecase}}{{keyParamName}}{{/lambda.titlecase}}, timeout: TimeSpan.FromSeconds(1));
+ ApiKeyToken apiKeyToken{{-index}} = new{{^net70OrLater}} ApiKeyToken{{/net70OrLater}}("", ClientUtils.ApiKeyHeader.{{#lambda.titlecase}}{{#lambda.alphabet_or_underscore}}{{keyParamName}}{{/lambda.alphabet_or_underscore}}{{/lambda.titlecase}}, timeout: TimeSpan.FromSeconds(1));
options.AddTokens(apiKeyToken{{-index}});
{{/apiKeyMethods}}
diff --git a/sdks/dotnet/templates/libraries/generichost/ExceptionEventArgs.mustache b/sdks/dotnet/templates/libraries/generichost/ExceptionEventArgs.mustache
index 016ef7c69..b74fcfa0a 100644
--- a/sdks/dotnet/templates/libraries/generichost/ExceptionEventArgs.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/ExceptionEventArgs.mustache
@@ -13,7 +13,7 @@ namespace {{packageName}}.{{clientPackage}}
public Exception Exception { get; }
///
- /// The ExcepetionEventArgs
+ /// The ExceptionEventArgs
///
///
public ExceptionEventArgs(Exception exception)
diff --git a/sdks/dotnet/templates/libraries/generichost/HostConfiguration.mustache b/sdks/dotnet/templates/libraries/generichost/HostConfiguration.mustache
index d7d1e3bf3..1333f0e67 100644
--- a/sdks/dotnet/templates/libraries/generichost/HostConfiguration.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/HostConfiguration.mustache
@@ -11,7 +11,11 @@ using System.Text.Json.Serialization;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using {{packageName}}.{{apiPackage}};
+{{#models}}
+{{#-first}}
using {{packageName}}.{{modelPackage}};
+{{/-first}}
+{{/models}}
namespace {{packageName}}.{{clientPackage}}
{
diff --git a/sdks/dotnet/templates/libraries/generichost/HttpSigningConfiguration.mustache b/sdks/dotnet/templates/libraries/generichost/HttpSigningConfiguration.mustache
index 5e0f7739d..357626fcc 100644
--- a/sdks/dotnet/templates/libraries/generichost/HttpSigningConfiguration.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/HttpSigningConfiguration.mustache
@@ -65,7 +65,7 @@ namespace {{packageName}}.{{clientPackage}}
public string SigningAlgorithm { get; set; }
///
- /// Gets the Signature validaty period in seconds
+ /// Gets the Signature validity period in seconds
///
public int SignatureValidityPeriod { get; set; }
diff --git a/sdks/dotnet/templates/libraries/generichost/JsonConverter.mustache b/sdks/dotnet/templates/libraries/generichost/JsonConverter.mustache
index 189acfd74..0ff2753e3 100644
--- a/sdks/dotnet/templates/libraries/generichost/JsonConverter.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/JsonConverter.mustache
@@ -51,7 +51,7 @@
{{/-first}}
if (discriminator != null && discriminator.Equals("{{name}}"))
- return JsonSerializer.Deserialize<{{{name}}}>(ref utf8JsonReader, jsonSerializerOptions) ?? throw new JsonException("The result was an unexpected value.");
+ return JsonSerializer.Deserialize<{{{classname}}}>(ref utf8JsonReader, jsonSerializerOptions) ?? throw new JsonException("The result was an unexpected value.");
{{/children}}
{{/discriminator}}
@@ -342,13 +342,13 @@
public override void Write(Utf8JsonWriter writer, {{classname}} {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}, JsonSerializerOptions jsonSerializerOptions)
{
{{#lambda.trimLineBreaks}}
- {{#lambda.copy}}
+ {{#lambda.copyText}}
{{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}
- {{/lambda.copy}}
+ {{/lambda.copyText}}
{{#discriminator}}
{{#children}}
- if ({{#lambda.pasteLine}}{{/lambda.pasteLine}} is {{classname}} {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}){
- JsonSerializer.Serialize<{{{name}}}>(writer, {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}, jsonSerializerOptions);
+ if ({{#lambda.paste}}{{/lambda.paste}} is {{classname}} {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}){
+ JsonSerializer.Serialize<{{{classname}}}>(writer, {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}, jsonSerializerOptions);
return;
}
@@ -439,7 +439,7 @@
{{#isDiscriminator}}
{{^model.composedSchemas.anyOf}}
{{^model.composedSchemas.oneOf}}
- writer.WriteString("{{baseName}}", {{^isEnum}}{{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{/isEnum}}{{#isNew}}{{#isEnum}}{{#isInnerEnum}}{{classname}}.{{{datatypeWithEnum}}}ToJsonValue{{/isInnerEnum}}{{^isInnerEnum}}{{{datatypeWithEnum}}}ValueConverter.ToJsonValue{{/isInnerEnum}}({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}.Value{{/required}}){{/isEnum}}{{/isNew}});
+ writer.WriteString("{{baseName}}", {{^isEnum}}{{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{/isEnum}}{{#isEnum}}{{#isInnerEnum}}{{classname}}.{{{datatypeWithEnum}}}ToJsonValue{{/isInnerEnum}}{{^isInnerEnum}}{{{datatypeWithEnum}}}ValueConverter.ToJsonValue{{/isInnerEnum}}({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}.Value{{/required}}){{/isEnum}});
{{/model.composedSchemas.oneOf}}
{{/model.composedSchemas.anyOf}}
@@ -449,9 +449,9 @@
{{^isMap}}
{{^isEnum}}
{{^isUuid}}
- {{#lambda.copy}}
+ {{#lambda.copyText}}
writer.WriteString("{{baseName}}", {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}});
- {{/lambda.copy}}
+ {{/lambda.copyText}}
{{#lambda.indent3}}
{{>WriteProperty}}
{{/lambda.indent3}}
@@ -460,44 +460,44 @@
{{/isMap}}
{{/isString}}
{{#isBoolean}}
- {{#lambda.copy}}
+ {{#lambda.copyText}}
writer.WriteBoolean("{{baseName}}", {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{#vendorExtensions.x-is-value-type}}{{nrt!}}.Value{{/vendorExtensions.x-is-value-type}}{{/required}}{{#required}}{{#isNullable}}.Value{{/isNullable}}{{/required}});
- {{/lambda.copy}}
+ {{/lambda.copyText}}
{{#lambda.indent3}}
{{>WriteProperty}}
{{/lambda.indent3}}
{{/isBoolean}}
{{^isEnum}}
{{#isNumeric}}
- {{#lambda.copy}}
+ {{#lambda.copyText}}
writer.WriteNumber("{{baseName}}", {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{#vendorExtensions.x-is-value-type}}{{nrt!}}.Value{{/vendorExtensions.x-is-value-type}}{{/required}}{{#required}}{{#isNullable}}.Value{{/isNullable}}{{/required}});
- {{/lambda.copy}}
+ {{/lambda.copyText}}
{{#lambda.indent3}}
{{>WriteProperty}}
{{/lambda.indent3}}
{{/isNumeric}}
{{/isEnum}}
{{#isDate}}
- {{#lambda.copy}}
+ {{#lambda.copyText}}
writer.WriteString("{{baseName}}", {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{#vendorExtensions.x-is-value-type}}{{nrt!}}.Value{{/vendorExtensions.x-is-value-type}}{{/required}}{{#required}}{{#isNullable}}.Value{{/isNullable}}{{/required}}.ToString({{name}}Format));
- {{/lambda.copy}}
+ {{/lambda.copyText}}
{{#lambda.indent3}}
{{>WriteProperty}}
{{/lambda.indent3}}
{{/isDate}}
{{#isDateTime}}
- {{#lambda.copy}}
+ {{#lambda.copyText}}
writer.WriteString("{{baseName}}", {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{#vendorExtensions.x-is-value-type}}{{nrt!}}.Value{{/vendorExtensions.x-is-value-type}}{{/required}}{{#required}}{{#isNullable}}.Value{{/isNullable}}{{/required}}.ToString({{name}}Format));
- {{/lambda.copy}}
+ {{/lambda.copyText}}
{{#lambda.indent3}}
{{>WriteProperty}}
{{/lambda.indent3}}
{{/isDateTime}}
{{#isEnum}}
{{#isNumeric}}
- {{#lambda.copy}}
+ {{#lambda.copyText}}
writer.WriteNumber("{{baseName}}", {{#isInnerEnum}}{{classname}}.{{/isInnerEnum}}{{{datatypeWithEnum}}}ToJsonValue({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{#vendorExtensions.x-is-value-type}}{{nrt!}}.Value{{/vendorExtensions.x-is-value-type}}{{/required}}{{#required}}{{#isNullable}}.Value{{/isNullable}}{{/required}}));
- {{/lambda.copy}}
+ {{/lambda.copyText}}
{{#lambda.indent3}}
{{>WriteProperty}}
{{/lambda.indent3}}
@@ -519,9 +519,9 @@
{{/isNullable}}
{{/isInnerEnum}}
{{^isInnerEnum}}
- {{#lambda.copy}}
+ {{#lambda.copyText}}
{{#lambda.camelcase_sanitize_param}}{{name}}{{/lambda.camelcase_sanitize_param}}
- {{/lambda.copy}}
+ {{/lambda.copyText}}
{{#required}}
{{#isNullable}}
if ({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}} == null)
@@ -533,7 +533,7 @@
{{#enumVars}}
{{#-first}}
{{#isString}}
- if ({{#lambda.pasteLine}}{{/lambda.pasteLine}}RawValue != null){{! we cant use name here because enumVar also has a name property, so use the paste lambda instead }}
+ if ({{#lambda.paste}}{{/lambda.paste}}RawValue != null){{! we cant use name here because enumVar also has a name property, so use the paste lambda instead }}
writer.WriteString("{{baseName}}", {{#lambda.camelcase_sanitize_param}}{{nameInPascalCase}}{{/lambda.camelcase_sanitize_param}}RawValue);
else
writer.WriteNull("{{baseName}}");
@@ -552,10 +552,10 @@
{{#enumVars}}
{{#-first}}
{{^isNumeric}}
- writer.WriteString("{{baseName}}", {{#lambda.pasteLine}}{{/lambda.pasteLine}}RawValue);
+ writer.WriteString("{{baseName}}", {{#lambda.paste}}{{/lambda.paste}}RawValue);
{{/isNumeric}}
{{#isNumeric}}
- writer.WriteNumber("{{baseName}}", {{#lambda.camelcase_sanitize_param}}{{#lambda.pasteLine}}{{/lambda.pasteLine}}{{/lambda.camelcase_sanitize_param}}RawValue);
+ writer.WriteNumber("{{baseName}}", {{#lambda.camelcase_sanitize_param}}{{#lambda.paste}}{{/lambda.paste}}{{/lambda.camelcase_sanitize_param}}RawValue);
{{/isNumeric}}
{{/-first}}
{{/enumVars}}
@@ -568,16 +568,16 @@
{{#isNullable}}
if ({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}Option{{nrt!}}.Value != null)
{
- var {{#lambda.pasteLine}}{{/lambda.pasteLine}}RawValue = {{{datatypeWithEnum}}}ValueConverter.ToJsonValue({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}Option.Value{{nrt!}}.Value);
- writer.{{#lambda.first}}{{#allowableValues}}{{#enumVars}}{{^isNumeric}}WriteString {{/isNumeric}}{{#isNumeric}}WriteNumber {{/isNumeric}}{{/enumVars}}{{/allowableValues}}{{/lambda.first}}("{{baseName}}", {{#lambda.pasteLine}}{{/lambda.pasteLine}}RawValue);
+ var {{#lambda.paste}}{{/lambda.paste}}RawValue = {{{datatypeWithEnum}}}ValueConverter.ToJsonValue({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}Option.Value{{nrt!}}.Value);
+ writer.{{#lambda.first}}{{#allowableValues}}{{#enumVars}}{{^isNumeric}}WriteString {{/isNumeric}}{{#isNumeric}}WriteNumber {{/isNumeric}}{{/enumVars}}{{/allowableValues}}{{/lambda.first}}("{{baseName}}", {{#lambda.paste}}{{/lambda.paste}}RawValue);
}
else
writer.WriteNull("{{baseName}}");
{{/isNullable}}
{{^isNullable}}
{
- var {{#lambda.pasteLine}}{{/lambda.pasteLine}}RawValue = {{{datatypeWithEnum}}}ValueConverter.ToJsonValue({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{nrt!}}.Value);
- writer.{{#lambda.first}}{{#allowableValues}}{{#enumVars}}{{^isNumeric}}WriteString {{/isNumeric}}{{#isNumeric}}WriteNumber {{/isNumeric}}{{/enumVars}}{{/allowableValues}}{{/lambda.first}}("{{baseName}}", {{#lambda.pasteLine}}{{/lambda.pasteLine}}RawValue);
+ var {{#lambda.paste}}{{/lambda.paste}}RawValue = {{{datatypeWithEnum}}}ValueConverter.ToJsonValue({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{nrt!}}.Value);
+ writer.{{#lambda.first}}{{#allowableValues}}{{#enumVars}}{{^isNumeric}}WriteString {{/isNumeric}}{{#isNumeric}}WriteNumber {{/isNumeric}}{{/enumVars}}{{/allowableValues}}{{/lambda.first}}("{{baseName}}", {{#lambda.paste}}{{/lambda.paste}}RawValue);
}
{{/isNullable}}
{{/required}}
@@ -586,9 +586,9 @@
{{/isMap}}
{{/isEnum}}
{{#isUuid}}
- {{#lambda.copy}}
+ {{#lambda.copyText}}
writer.WriteString("{{baseName}}", {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{#vendorExtensions.x-is-value-type}}{{nrt!}}.Value{{/vendorExtensions.x-is-value-type}}{{/required}}{{#required}}{{#isNullable}}.Value{{/isNullable}}{{/required}});
- {{/lambda.copy}}
+ {{/lambda.copyText}}
{{#lambda.indent3}}
{{>WriteProperty}}
{{/lambda.indent3}}
diff --git a/sdks/dotnet/templates/libraries/generichost/OnErrorDefaultImplementation.mustache b/sdks/dotnet/templates/libraries/generichost/OnErrorDefaultImplementation.mustache
index 7af8e0760..a1a9fa976 100644
--- a/sdks/dotnet/templates/libraries/generichost/OnErrorDefaultImplementation.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/OnErrorDefaultImplementation.mustache
@@ -1,2 +1,2 @@
- if (!suppressDefaultLog)
- Logger.LogError(exception, "An error occurred while sending the request to the server.");
\ No newline at end of file
+ if (!suppressDefaultLogLocalVar)
+ Logger.LogError(exceptionLocalVar, "An error occurred while sending the request to the server.");
\ No newline at end of file
diff --git a/sdks/dotnet/templates/libraries/generichost/RateLimitProvider`1.mustache b/sdks/dotnet/templates/libraries/generichost/RateLimitProvider`1.mustache
index 857a505ab..bafe525c0 100644
--- a/sdks/dotnet/templates/libraries/generichost/RateLimitProvider`1.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/RateLimitProvider`1.mustache
@@ -7,7 +7,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Threading.Channels;
namespace {{packageName}}.{{clientPackage}}
{
@@ -17,7 +16,7 @@ namespace {{packageName}}.{{clientPackage}}
///
{{>visibility}} class RateLimitProvider : TokenProvider where TTokenBase : TokenBase
{
- internal Dictionary> AvailableTokens { get; } = new{{^net70OrLater}} Dictionary>{{/net70OrLater}}();
+ internal Dictionary> AvailableTokens { get; } = new{{^net70OrLater}} Dictionary>{{/net70OrLater}}();
///
/// Instantiates a ThrottledTokenProvider. Your tokens will be rate limited based on the token's timeout.
@@ -29,12 +28,12 @@ namespace {{packageName}}.{{clientPackage}}
token.StartTimer(token.Timeout ?? TimeSpan.FromMilliseconds(40));
{{#lambda.copy}}
- BoundedChannelOptions options = new BoundedChannelOptions(_tokens.Length)
+ global::System.Threading.Channels.BoundedChannelOptions options = new global::System.Threading.Channels.BoundedChannelOptions(_tokens.Length)
{
- FullMode = BoundedChannelFullMode.DropWrite
+ FullMode = global::System.Threading.Channels.BoundedChannelFullMode.DropWrite
};
- AvailableTokens.Add(string.Empty, Channel.CreateBounded(options));
+ AvailableTokens.Add(string.Empty, global::System.Threading.Channels.Channel.CreateBounded(options));
{{/lambda.copy}}
{{#hasApiKeyMethods}}
if (container is TokenContainer apiKeyTokenContainer)
@@ -43,31 +42,35 @@ namespace {{packageName}}.{{clientPackage}}
foreach (string header in headers)
{
- BoundedChannelOptions options = new BoundedChannelOptions(apiKeyTokenContainer.Tokens.Count(t => ClientUtils.ApiKeyHeaderToString(t.Header).Equals(header)))
+ global::System.Threading.Channels.BoundedChannelOptions options = new global::System.Threading.Channels.BoundedChannelOptions(apiKeyTokenContainer.Tokens.Count(t => ClientUtils.ApiKeyHeaderToString(t.Header).Equals(header)))
{
- FullMode = BoundedChannelFullMode.DropWrite
+ FullMode = global::System.Threading.Channels.BoundedChannelFullMode.DropWrite
};
- AvailableTokens.Add(header, Channel.CreateBounded(options));
+ AvailableTokens.Add(header, global::System.Threading.Channels.Channel.CreateBounded(options));
}
}
else
{
- {{#lambda.indent1}}{{#lambda.pasteLine}}{{/lambda.pasteLine}}{{/lambda.indent1}}
+ {{#lambda.indentAll1}}
+ {{#lambda.paste}}
+ {{/lambda.paste}}
+ {{/lambda.indentAll1}}
}
{{/hasApiKeyMethods}}
{{^hasApiKeyMethods}}
- {{#lambda.pasteLine}}{{/lambda.pasteLine}}
+ {{#lambda.paste}}
+ {{/lambda.paste}}
{{/hasApiKeyMethods}}
- foreach(Channel tokens in AvailableTokens.Values)
+ foreach(global::System.Threading.Channels.Channel tokens in AvailableTokens.Values)
for (int i = 0; i < _tokens.Length; i++)
_tokens[i].TokenBecameAvailable += ((sender) => tokens.Writer.TryWrite((TTokenBase) sender));
}
internal override async System.Threading.Tasks.ValueTask GetAsync(string header = "", System.Threading.CancellationToken cancellation = default{{^netstandard20OrLater}}(global::System.Threading.CancellationToken){{/netstandard20OrLater}})
{
- if (!AvailableTokens.TryGetValue(header, out Channel{{nrt?}} tokens))
+ if (!AvailableTokens.TryGetValue(header, out global::System.Threading.Channels.Channel{{nrt?}} tokens))
throw new KeyNotFoundException($"Could not locate a token for header '{header}'.");
return await tokens.Reader.ReadAsync(cancellation).ConfigureAwait(false);
diff --git a/sdks/dotnet/templates/libraries/generichost/ValidateRegex.mustache b/sdks/dotnet/templates/libraries/generichost/ValidateRegex.mustache
index 78aba8fb3..8918b8cf4 100644
--- a/sdks/dotnet/templates/libraries/generichost/ValidateRegex.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/ValidateRegex.mustache
@@ -1,7 +1,7 @@
// {{{name}}} ({{{dataType}}}) pattern
Regex regex{{{name}}} = new Regex(@"{{{vendorExtensions.x-regex}}}"{{#vendorExtensions.x-modifiers}}{{#-first}}, {{/-first}}RegexOptions.{{{.}}}{{^-last}} | {{/-last}}{{/vendorExtensions.x-modifiers}});
{{#lambda.copy}}this.{{{name}}}{{#useGenericHost}}{{^required}}Option.Value{{/required}}{{/useGenericHost}} != null && {{/lambda.copy}}
-if ({{#lambda.first}}{{^required}}{{#lambda.pasteLine}}{{/lambda.pasteLine}} {{/required}}{{#isNullable}}{{#lambda.pasteLine}}{{/lambda.pasteLine}}{{/isNullable}}{{/lambda.first}}!regex{{{name}}}.Match(this.{{{name}}}{{#useGenericHost}}{{^required}}Option.Value{{/required}}{{/useGenericHost}}{{#isUuid}}.ToString(){{#lambda.first}}{{^required}}{{nrt!}} {{/required}}{{#isNullable}}! {{/isNullable}}{{/lambda.first}}{{/isUuid}}).Success)
+if ({{#lambda.first}}{{^required}}{{#lambda.paste}}{{/lambda.paste}} {{/required}}{{#isNullable}}{{#lambda.paste}}{{/lambda.paste}}{{/isNullable}}{{/lambda.first}}!regex{{{name}}}.Match(this.{{{name}}}{{#useGenericHost}}{{^required}}Option.Value{{/required}}{{/useGenericHost}}{{#isUuid}}.ToString(){{#lambda.first}}{{^required}}{{nrt!}} {{/required}}{{#isNullable}}! {{/isNullable}}{{/lambda.first}}{{/isUuid}}).Success)
{
yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for {{{name}}}, must match a pattern of " + regex{{{name}}}, new [] { "{{{name}}}" });
}
\ No newline at end of file
diff --git a/sdks/dotnet/templates/libraries/generichost/WritePropertyHelper.mustache b/sdks/dotnet/templates/libraries/generichost/WritePropertyHelper.mustache
index 183946cf7..616993bce 100644
--- a/sdks/dotnet/templates/libraries/generichost/WritePropertyHelper.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/WritePropertyHelper.mustache
@@ -1,9 +1,10 @@
{{#isNullable}}
if ({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{/required}} != null)
- {{#lambda.pasteLine}}{{/lambda.pasteLine}}
+ {{#lambda.paste}}{{/lambda.paste}}
else
writer.WriteNull("{{baseName}}");
{{/isNullable}}
{{^isNullable}}
-{{#lambda.pasteLine}}{{/lambda.pasteLine}}
+{{#lambda.paste}}
+{{/lambda.paste}}
{{/isNullable}}
\ No newline at end of file
diff --git a/sdks/dotnet/templates/libraries/generichost/api.mustache b/sdks/dotnet/templates/libraries/generichost/api.mustache
index 8c02da8f1..b33115f0a 100644
--- a/sdks/dotnet/templates/libraries/generichost/api.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/api.mustache
@@ -85,6 +85,7 @@ namespace {{packageName}}.{{apiPackage}}
{{/operation}}
}
{{#operation}}
+ {{^vendorExtensions.x-duplicates}}
{{#responses}}
{{#-first}}
@@ -115,6 +116,7 @@ namespace {{packageName}}.{{apiPackage}}
}
{{/-first}}
{{/responses}}
+ {{/vendorExtensions.x-duplicates}}
{{/operation}}
///
@@ -134,7 +136,7 @@ namespace {{packageName}}.{{apiPackage}}
///
public event EventHandler{{nrt?}} OnError{{operationId}};
- internal void ExecuteOn{{operationId}}({{classname}}.{{operationId}}ApiResponse apiResponse)
+ internal void ExecuteOn{{operationId}}({{#vendorExtensions.x-duplicates}}{{.}}{{/vendorExtensions.x-duplicates}}{{^vendorExtensions.x-duplicates}}{{classname}}{{/vendorExtensions.x-duplicates}}.{{operationId}}ApiResponse apiResponse)
{
On{{operationId}}?.Invoke(this, new ApiResponseEventArgs(apiResponse));
}
@@ -303,30 +305,30 @@ namespace {{packageName}}.{{apiPackage}}
///
/// Logs exceptions that occur while retrieving the server response
///
- ///
- ///
- ///
+ ///
+ ///
+ ///
{{#allParams}}
///
{{/allParams}}
- private void OnError{{operationId}}DefaultImplementation({{#lambda.joinWithComma}}Exception exception string pathFormat string path {{#allParams}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}} {{/allParams}}{{/lambda.joinWithComma}})
+ private void OnError{{operationId}}DefaultImplementation({{#lambda.joinWithComma}}Exception exceptionLocalVar string pathFormatLocalVar string pathLocalVar {{#allParams}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}} {{/allParams}}{{/lambda.joinWithComma}})
{
- bool suppressDefaultLog = false;
- OnError{{operationId}}({{#lambda.joinWithComma}}ref suppressDefaultLog exception pathFormat path {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}});
+ bool suppressDefaultLogLocalVar = false;
+ OnError{{operationId}}({{#lambda.joinWithComma}}ref suppressDefaultLogLocalVar exceptionLocalVar pathFormatLocalVar pathLocalVar {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}});
{{>OnErrorDefaultImplementation}}
}
///
/// A partial method that gives developers a way to provide customized exception handling
///
- ///
- ///
- ///
- ///
+ ///
+ ///
+ ///
+ ///
{{#allParams}}
///
{{/allParams}}
- partial void OnError{{operationId}}({{#lambda.joinWithComma}}ref bool suppressDefaultLog Exception exception string pathFormat string path {{#allParams}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}} {{/allParams}}{{/lambda.joinWithComma}});
+ partial void OnError{{operationId}}({{#lambda.joinWithComma}}ref bool suppressDefaultLogLocalVar Exception exceptionLocalVar string pathFormatLocalVar string pathLocalVar {{#allParams}}{{^required}}Option<{{/required}}{{{dataType}}}{{>NullConditionalParameter}}{{^required}}>{{/required}} {{paramName}} {{/allParams}}{{/lambda.joinWithComma}});
///
/// {{summary}} {{notes}}
@@ -380,7 +382,7 @@ namespace {{packageName}}.{{apiPackage}}
uriBuilderLocalVar.Host = HttpClient.BaseAddress{{nrt!}}.Host;
uriBuilderLocalVar.Port = HttpClient.BaseAddress.Port;
uriBuilderLocalVar.Scheme = HttpClient.BaseAddress.Scheme;
- uriBuilderLocalVar.Path = ClientUtils.CONTEXT_PATH + "{{path}}";
+ uriBuilderLocalVar.Path = ClientUtils.CONTEXT_PATH + "{{{path}}}";
{{/servers}}
{{#servers}}
{{#-first}}
@@ -619,9 +621,9 @@ namespace {{packageName}}.{{apiPackage}}
{
string responseContentLocalVar = await httpResponseMessageLocalVar.Content.ReadAsStringAsync({{#net60OrLater}}cancellationToken{{/net60OrLater}}).ConfigureAwait(false);
- ILogger<{{operationId}}ApiResponse> apiResponseLoggerLocalVar = LoggerFactory.CreateLogger<{{operationId}}ApiResponse>();
+ ILogger<{{#vendorExtensions.x-duplicates}}{{.}}.{{/vendorExtensions.x-duplicates}}{{operationId}}ApiResponse> apiResponseLoggerLocalVar = LoggerFactory.CreateLogger<{{#vendorExtensions.x-duplicates}}{{.}}.{{/vendorExtensions.x-duplicates}}{{operationId}}ApiResponse>();
- {{operationId}}ApiResponse apiResponseLocalVar = new{{^net60OrLater}} {{operationId}}ApiResponse{{/net60OrLater}}(apiResponseLoggerLocalVar, httpRequestMessageLocalVar, httpResponseMessageLocalVar, responseContentLocalVar, "{{path}}", requestedAtLocalVar, _jsonSerializerOptions);
+ {{#vendorExtensions.x-duplicates}}{{.}}.{{/vendorExtensions.x-duplicates}}{{operationId}}ApiResponse apiResponseLocalVar = new{{^net60OrLater}} {{operationId}}ApiResponse{{/net60OrLater}}(apiResponseLoggerLocalVar, httpRequestMessageLocalVar, httpResponseMessageLocalVar, responseContentLocalVar, "{{{path}}}", requestedAtLocalVar, _jsonSerializerOptions);
After{{operationId}}DefaultImplementation({{#lambda.joinWithComma}}apiResponseLocalVar {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}});
@@ -674,12 +676,13 @@ namespace {{packageName}}.{{apiPackage}}
}
catch(Exception e)
{
- OnError{{operationId}}DefaultImplementation({{#lambda.joinWithComma}}e "{{path}}" uriBuilderLocalVar.Path {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}});
+ OnError{{operationId}}DefaultImplementation({{#lambda.joinWithComma}}e "{{{path}}}" uriBuilderLocalVar.Path {{#allParams}}{{paramName}} {{/allParams}}{{/lambda.joinWithComma}});
Events.ExecuteOnError{{operationId}}(e);
throw;
}
{{/lambda.trimLineBreaks}}
}
+ {{^vendorExtensions.x-duplicates}}
{{#responses}}
{{#-first}}
@@ -792,6 +795,7 @@ namespace {{packageName}}.{{apiPackage}}
}
{{/-first}}
{{/responses}}
+ {{/vendorExtensions.x-duplicates}}
{{/operation}}
}
{{/operations}}
diff --git a/sdks/dotnet/templates/libraries/generichost/modelGeneric.mustache b/sdks/dotnet/templates/libraries/generichost/modelGeneric.mustache
index 6bf210bbc..04fb37138 100644
--- a/sdks/dotnet/templates/libraries/generichost/modelGeneric.mustache
+++ b/sdks/dotnet/templates/libraries/generichost/modelGeneric.mustache
@@ -34,6 +34,13 @@
{{/isNew}}
{{/isInherited}}
{{/isDiscriminator}}
+ {{#vendorExtensions.x-is-base-or-new-discriminator}}
+ {{^model.composedSchemas.anyOf}}
+ {{^model.composedSchemas.oneOf}}
+ {{name}} = {{^isEnum}}this.GetType().Name{{/isEnum}}{{#isEnum}}({{datatypeWithEnum}})Enum.Parse(typeof({{datatypeWithEnum}}), this.GetType().Name){{/isEnum}};
+ {{/model.composedSchemas.oneOf}}
+ {{/model.composedSchemas.anyOf}}
+ {{/vendorExtensions.x-is-base-or-new-discriminator}}
{{/allVars}}
OnCreated();
}
@@ -71,6 +78,13 @@
{{/isNew}}
{{/isInherited}}
{{/isDiscriminator}}
+ {{#vendorExtensions.x-is-base-or-new-discriminator}}
+ {{^model.composedSchemas.anyOf}}
+ {{^model.composedSchemas.oneOf}}
+ {{name}} = {{^isEnum}}this.GetType().Name{{/isEnum}}{{#isEnum}}({{datatypeWithEnum}})Enum.Parse(typeof({{datatypeWithEnum}}), this.GetType().Name){{/isEnum}};
+ {{/model.composedSchemas.oneOf}}
+ {{/model.composedSchemas.anyOf}}
+ {{/vendorExtensions.x-is-base-or-new-discriminator}}
{{/allVars}}
OnCreated();
}
@@ -109,7 +123,7 @@
/// {{.}}
{{/description}}
{{#example}}
- /// {{.}}
+ /* {{.}} */
{{/example}}
[JsonPropertyName("{{baseName}}")]
{{#deprecated}}
@@ -136,7 +150,7 @@
/// {{#description}}
/// {{.}}{{/description}}
{{#example}}
- /// {{.}}
+ /* {{.}} */
{{/example}}
{{#deprecated}}
[Obsolete]
@@ -152,7 +166,7 @@
/// {{#description}}
/// {{.}}{{/description}}
{{#example}}
- /// {{.}}
+ /* {{.}} */
{{/example}}
{{#deprecated}}
[Obsolete]
@@ -162,7 +176,7 @@
{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.oneOf}}
{{#allVars}}
- {{#isDiscriminator}}
+ {{#vendorExtensions.x-is-base-or-new-discriminator}}
{{^model.composedSchemas.anyOf}}
{{^model.composedSchemas.oneOf}}
///
@@ -170,12 +184,12 @@
///
[JsonIgnore]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
- public {{#isNew}}new {{/isNew}}{{datatypeWithEnum}} {{name}} { get; } = {{^isNew}}"{{classname}}"{{/isNew}}{{#isNew}}{{^isEnum}}"{{classname}}"{{/isEnum}}{{#isEnum}}({{datatypeWithEnum}})Enum.Parse(typeof({{datatypeWithEnum}}), "{{classname}}"){{/isEnum}}{{/isNew}};
+ public {{#isNew}}new {{/isNew}}{{datatypeWithEnum}} {{name}} { get; }
{{/model.composedSchemas.oneOf}}
{{/model.composedSchemas.anyOf}}
- {{/isDiscriminator}}
- {{^isDiscriminator}}
+ {{/vendorExtensions.x-is-base-or-new-discriminator}}
+ {{^vendorExtensions.x-is-base-or-new-discriminator}}
{{^isEnum}}
{{#isInherited}}
{{#isNew}}
@@ -193,7 +207,7 @@
/// {{#description}}
/// {{.}}{{/description}}
{{#example}}
- /// {{.}}
+ /* {{.}} */
{{/example}}
[JsonPropertyName("{{baseName}}")]
{{#deprecated}}
@@ -218,7 +232,7 @@
/// {{#description}}
/// {{.}}{{/description}}
{{#example}}
- /// {{.}}
+ /* {{.}} */
{{/example}}
[JsonPropertyName("{{baseName}}")]
{{#deprecated}}
@@ -228,7 +242,7 @@
{{/isInherited}}
{{/isEnum}}
- {{/isDiscriminator}}
+ {{/vendorExtensions.x-is-base-or-new-discriminator}}
{{/allVars}}
{{#isAdditionalPropertiesTrue}}
{{^parentModel}}
@@ -345,15 +359,17 @@
{{/readOnlyVars}}
{{#readOnlyVars}}
{{#lambda.copy}}
-
if ({{name}} != null)
hashCode = (hashCode * 59) + {{name}}.GetHashCode();
+
{{/lambda.copy}}
{{#isNullable}}
- {{#lambda.pasteOnce}}{{/lambda.pasteOnce}}
+ {{#lambda.pasteOnce}}
+ {{/lambda.pasteOnce}}
{{/isNullable}}
{{^required}}
- {{#lambda.pasteOnce}}{{/lambda.pasteOnce}}
+ {{#lambda.pasteOnce}}
+ {{/lambda.pasteOnce}}
{{/required}}
{{/readOnlyVars}}
{{#isAdditionalPropertiesTrue}}
diff --git a/sdks/dotnet/templates/libraries/httpclient/ApiClient.mustache b/sdks/dotnet/templates/libraries/httpclient/ApiClient.mustache
index cefe6be9f..603284acb 100644
--- a/sdks/dotnet/templates/libraries/httpclient/ApiClient.mustache
+++ b/sdks/dotnet/templates/libraries/httpclient/ApiClient.mustache
@@ -481,7 +481,7 @@ namespace {{packageName}}.Client
try
{
- if (configuration.Timeout > 0)
+ if (configuration.Timeout > TimeSpan.Zero)
{
timeoutTokenSource = new CancellationTokenSource(configuration.Timeout);
finalTokenSource = CancellationTokenSource.CreateLinkedTokenSource(finalToken, timeoutTokenSource.Token);
diff --git a/sdks/dotnet/templates/modelGeneric.mustache b/sdks/dotnet/templates/modelGeneric.mustache
index 7392b272f..5075f0e64 100644
--- a/sdks/dotnet/templates/modelGeneric.mustache
+++ b/sdks/dotnet/templates/modelGeneric.mustache
@@ -10,7 +10,9 @@
[DataContract(Name = "{{{name}}}")]
{{^useUnityWebRequest}}
{{#discriminator}}
+ {{#mappedModels.size}}
[JsonConverter(typeof(JsonSubtypes), "{{{discriminatorName}}}")]
+ {{/mappedModels.size}}
{{#mappedModels}}
[JsonSubtypes.KnownSubType(typeof({{{modelName}}}), "{{^vendorExtensions.x-discriminator-value}}{{{mappingName}}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{.}}}{{/vendorExtensions.x-discriminator-value}}")]
{{/mappedModels}}
@@ -46,7 +48,14 @@
/// {{.}}
{{/description}}
{{#example}}
+{{^useCustomTemplateCode}}
+ /*
+ {{.}}
+ */
+{{/useCustomTemplateCode}}
+{{#useCustomTemplateCode}}
/// {{.}}
+{{/useCustomTemplateCode}}
{{/example}}
{{^conditionalSerialization}}
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#required}}true{{/required}}{{^required}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/required}}{{/vendorExtensions.x-emit-default-value}})]
@@ -290,7 +299,14 @@
/// {{#description}}
/// {{.}}{{/description}}
{{#example}}
+{{^useCustomTemplateCode}}
+ /*
+ {{.}}
+ */
+{{/useCustomTemplateCode}}
+{{#useCustomTemplateCode}}
/// {{.}}
+{{/useCustomTemplateCode}}
{{/example}}
{{^conditionalSerialization}}
[DataMember(Name = "{{baseName}}"{{#required}}, IsRequired = true{{/required}}, EmitDefaultValue = {{#vendorExtensions.x-emit-default-value}}true{{/vendorExtensions.x-emit-default-value}}{{^vendorExtensions.x-emit-default-value}}{{#required}}true{{/required}}{{^required}}{{#isBoolean}}true{{/isBoolean}}{{^isBoolean}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/isBoolean}}{{/required}}{{/vendorExtensions.x-emit-default-value}})]
diff --git a/sdks/dotnet/templates/netcore_project.mustache b/sdks/dotnet/templates/netcore_project.mustache
index 01717e65a..06243449e 100644
--- a/sdks/dotnet/templates/netcore_project.mustache
+++ b/sdks/dotnet/templates/netcore_project.mustache
@@ -38,21 +38,16 @@
{{/useGenericHost}}
{{#useRestSharp}}
-{{^useCustomTemplateCode}}
-
-{{/useCustomTemplateCode}}
-{{#useCustomTemplateCode}}
-{{/useCustomTemplateCode}}
{{/useRestSharp}}
{{#useGenericHost}}
-
-
+
+
{{#supportsRetry}}
-
+
{{/supportsRetry}}
{{#net80OrLater}}
-
+
{{/net80OrLater}}
{{^net60OrLater}}
diff --git a/sdks/dotnet/templates/netcore_testproject.mustache b/sdks/dotnet/templates/netcore_testproject.mustache
index 90d11eb82..90434b77e 100644
--- a/sdks/dotnet/templates/netcore_testproject.mustache
+++ b/sdks/dotnet/templates/netcore_testproject.mustache
@@ -9,9 +9,9 @@
-
-
-
+
+
+
diff --git a/sdks/dotnet/templates/nuspec.mustache b/sdks/dotnet/templates/nuspec.mustache
index b473cbd64..680ee2fe4 100644
--- a/sdks/dotnet/templates/nuspec.mustache
+++ b/sdks/dotnet/templates/nuspec.mustache
@@ -32,12 +32,7 @@
{{#useRestSharp}}
-{{^useCustomTemplateCode}}
-
-{{/useCustomTemplateCode}}
-{{#useCustomTemplateCode}}
-{{/useCustomTemplateCode}}
{{/useRestSharp}}
{{#useCompareNetObjects}}