diff --git a/bin/csharp-petstore-all-httpClient.sh b/bin/csharp-petstore-all-httpClient.sh
new file mode 100644
index 00000000000..e21736f2f91
--- /dev/null
+++ b/bin/csharp-petstore-all-httpClient.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# C# Petstore API client (.NET 3.5)
+./bin/csharp-petstore-httpClient.sh
+
+# C# Petstore API client (v5.0 for .net standarnd 1.3+)
+./bin/csharp-petstore-net-standard-httpClient.sh
+
+./bin/csharp-petstore-netcore-project-httpClient.sh
+
diff --git a/bin/csharp-petstore-httpClient.json b/bin/csharp-petstore-httpClient.json
new file mode 100644
index 00000000000..35be7406a46
--- /dev/null
+++ b/bin/csharp-petstore-httpClient.json
@@ -0,0 +1,3 @@
+{
+ "library": "httpClient"
+}
\ No newline at end of file
diff --git a/bin/csharp-petstore-httpClient.sh b/bin/csharp-petstore-httpClient.sh
new file mode 100644
index 00000000000..2ab88161456
--- /dev/null
+++ b/bin/csharp-petstore-httpClient.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+SCRIPT="$0"
+
+while [ -h "$SCRIPT" ] ; do
+ ls=`ls -ld "$SCRIPT"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ SCRIPT="$link"
+ else
+ SCRIPT=`dirname "$SCRIPT"`/"$link"
+ fi
+done
+
+if [ ! -d "${APP_DIR}" ]; then
+ APP_DIR=`dirname "$SCRIPT"`/..
+ APP_DIR=`cd "${APP_DIR}"; pwd`
+fi
+
+executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar"
+
+if [ ! -f "$executable" ]
+then
+ mvn clean package
+fi
+
+# if you've executed sbt assembly previously it will use that instead.
+export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
+ags="generate $@ -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l csharp -o samples/client/petstore/httpClient/csharp/SwaggerClient --additional-properties packageGuid={321C8C3F-0156-40C1-AE42-D59761FB9B6C}" -c ./bin/csharp-petstore-httpClient.json"
+
+java $JAVA_OPTS -jar $executable $ags
diff --git a/bin/csharp-petstore-net-standard-httpClient.json b/bin/csharp-petstore-net-standard-httpClient.json
new file mode 100644
index 00000000000..ce25674ab13
--- /dev/null
+++ b/bin/csharp-petstore-net-standard-httpClient.json
@@ -0,0 +1,4 @@
+{
+ "targetFramework": "v5.0",
+ "library": "httpClient"
+}
diff --git a/bin/csharp-petstore-net-standard-httpClient.sh b/bin/csharp-petstore-net-standard-httpClient.sh
new file mode 100644
index 00000000000..f335e0aa0be
--- /dev/null
+++ b/bin/csharp-petstore-net-standard-httpClient.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+SCRIPT="$0"
+
+while [ -h "$SCRIPT" ] ; do
+ ls=`ls -ld "$SCRIPT"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ SCRIPT="$link"
+ else
+ SCRIPT=`dirname "$SCRIPT"`/"$link"
+ fi
+done
+
+if [ ! -d "${APP_DIR}" ]; then
+ APP_DIR=`dirname "$SCRIPT"`/..
+ APP_DIR=`cd "${APP_DIR}"; pwd`
+fi
+
+executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar"
+
+if [ ! -f "$executable" ]
+then
+ mvn clean package
+fi
+
+# if you've executed sbt assembly previously it will use that instead.
+export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
+ags="generate $@ -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l csharp -o samples/client/petstore/csharp/httpClient/SwaggerClientNetStandard --additional-properties packageGuid={321C8C3F-0156-40C1-AE42-D59761FB9B6C} -c ./bin/csharp-petstore-net-standard-httpClient.json"
+
+java $JAVA_OPTS -jar $executable $ags
diff --git a/bin/csharp-petstore-netcore-project-httpClient.json b/bin/csharp-petstore-netcore-project-httpClient.json
new file mode 100644
index 00000000000..35be7406a46
--- /dev/null
+++ b/bin/csharp-petstore-netcore-project-httpClient.json
@@ -0,0 +1,3 @@
+{
+ "library": "httpClient"
+}
\ No newline at end of file
diff --git a/bin/csharp-petstore-netcore-project-httpClient.sh b/bin/csharp-petstore-netcore-project-httpClient.sh
new file mode 100644
index 00000000000..f88044eb00b
--- /dev/null
+++ b/bin/csharp-petstore-netcore-project-httpClient.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+SCRIPT="$0"
+
+while [ -h "$SCRIPT" ] ; do
+ ls=`ls -ld "$SCRIPT"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ SCRIPT="$link"
+ else
+ SCRIPT=`dirname "$SCRIPT"`/"$link"
+ fi
+done
+
+if [ ! -d "${APP_DIR}" ]; then
+ APP_DIR=`dirname "$SCRIPT"`/..
+ APP_DIR=`cd "${APP_DIR}"; pwd`
+fi
+
+executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar"
+
+if [ ! -f "$executable" ]
+then
+ mvn clean package
+fi
+
+# if you've executed sbt assembly previously it will use that instead.
+export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
+ags="generate $@ -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l csharp -o samples/client/petstore/csharp/httpClient/SwaggerClientNetCoreProject --additional-properties packageGuid={67035b31-f8e5-41a4-9673-954035084f7d},netCoreProjectFile=true -c ./bin/csharp-petstore-net-standard-httpClient.json"
+
+java $JAVA_OPTS -jar $executable $ags
diff --git a/bin/windows/csharp-petstore-all-httpClient.bat b/bin/windows/csharp-petstore-all-httpClient.bat
new file mode 100644
index 00000000000..9dc78bb0dc8
--- /dev/null
+++ b/bin/windows/csharp-petstore-all-httpClient.bat
@@ -0,0 +1,8 @@
+REM C# Petstore API client
+call .\bin\windows\csharp-petstore-httpClient.bat
+
+REM C# Petstore API client (v5.0 for .net standarnd 1.3+)
+call .\bin\windows\csharp-petstore-netstandard-httpClient.bat
+
+call .\bin\windows\csharp-petstore-netcore-project-httpClient.bat
+
diff --git a/bin/windows/csharp-petstore-httpClient.bat b/bin/windows/csharp-petstore-httpClient.bat
new file mode 100644
index 00000000000..1df71fee655
--- /dev/null
+++ b/bin/windows/csharp-petstore-httpClient.bat
@@ -0,0 +1,10 @@
+set executable=.\modules\swagger-codegen-cli\target\swagger-codegen-cli.jar
+
+If Not Exist %executable% (
+ mvn clean package
+)
+
+REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M
+set ags=generate -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l csharp -o samples\client\petstore\csharp\httpClient\SwaggerClient --additional-properties packageGuid={321C8C3F-0156-40C1-AE42-D59761FB9B6C} -c ./bin/csharp-petstore-httpClient.json"
+
+java %JAVA_OPTS% -jar %executable% %ags%
diff --git a/bin/windows/csharp-petstore-netcore-project-httpClient.bat b/bin/windows/csharp-petstore-netcore-project-httpClient.bat
new file mode 100644
index 00000000000..8c1827c347e
--- /dev/null
+++ b/bin/windows/csharp-petstore-netcore-project-httpClient.bat
@@ -0,0 +1,10 @@
+set executable=.\modules\swagger-codegen-cli\target\swagger-codegen-cli.jar
+
+If Not Exist %executable% (
+ mvn clean package
+)
+
+REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M
+set ags=generate -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l csharp -o samples\client\petstore\csharp\httpClient\SwaggerClientNetCoreProject --additional-properties targetFramework=v5.0,packageGuid={67035b31-f8e5-41a4-9673-954035084f7d},netCoreProjectFile=true -c ./bin/csharp-petstore-netcore-project-httpClient.json"
+
+java %JAVA_OPTS% -jar %executable% %ags%
diff --git a/bin/windows/csharp-petstore-netstandard-httpClient.bat b/bin/windows/csharp-petstore-netstandard-httpClient.bat
new file mode 100644
index 00000000000..a4cbc2a916b
--- /dev/null
+++ b/bin/windows/csharp-petstore-netstandard-httpClient.bat
@@ -0,0 +1,10 @@
+set executable=.\modules\swagger-codegen-cli\target\swagger-codegen-cli.jar
+
+If Not Exist %executable% (
+ mvn clean package
+)
+
+REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M
+set ags=generate -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l csharp -o samples\client\petstore\csharp\httpClient\SwaggerClientNetStandard --additional-properties targetFramework=v5.0,packageGuid={3AB1F259-1769-484B-9411-84505FCCBD55}
+
+java %JAVA_OPTS% -jar %executable% %ags%
diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java
index 34f4031557a..afdd5d9ed1a 100644
--- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java
+++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/CSharpClientCodegen.java
@@ -177,6 +177,17 @@ public CSharpClientCodegen() {
regexModifiers.put('m', "Multiline");
regexModifiers.put('s', "Singleline");
regexModifiers.put('x', "IgnorePatternWhitespace");
+
+ supportedLibraries.put("restSharp", "RestSharp client: RestSharp.RestClient");
+ supportedLibraries.put("httpClient", "HTTP client: System.Net.HttpClient");
+
+ CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use");
+ libraryOption.setEnum(supportedLibraries);
+ // set restSharp as the default
+ libraryOption.setDefault("restSharp");
+ cliOptions.add(libraryOption);
+
+ setLibrary("restSharp");
}
@Override
@@ -351,6 +362,7 @@ public void processOpts() {
clientPackageDir, "IApiAccessor.cs"));
supportingFiles.add(new SupportingFile("Configuration.mustache",
clientPackageDir, "Configuration.cs"));
+ LOGGER.info("apiClient {}", clientPackageDir);
supportingFiles.add(new SupportingFile("ApiClient.mustache",
clientPackageDir, "ApiClient.cs"));
supportingFiles.add(new SupportingFile("ApiException.mustache",
@@ -437,6 +449,11 @@ public void processOpts() {
}
}
}
+ if("httpClient".equals(getLibrary())) {
+ supportingFiles.add(new SupportingFile("RequestParameters.mustache", clientPackageDir, "RequestParameters.cs"));
+ supportingFiles.add(new SupportingFile("ResponseExtension.mustache", clientPackageDir, "ResponseExtension.cs"));
+ supportingFiles.add(new SupportingFile("InterceptResult.mustache", clientPackageDir, "InterceptResult.cs"));
+ }
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
diff --git a/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ApiClient.mustache
new file mode 100644
index 00000000000..be9bad5f9d9
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ApiClient.mustache
@@ -0,0 +1,472 @@
+{{>partial_header}}
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.IO;
+{{^netStandard}}
+{{^supportsUWP}}
+using System.Web;
+{{/supportsUWP}}
+{{/netStandard}}
+using System.Linq;
+using System.Text;
+using Newtonsoft.Json;
+{{#netStandard}}
+using System.Net.Http;
+{{/netStandard}}
+{{^netStandard}}
+using System.Net.Http;
+{{/netStandard}}
+
+namespace {{packageName}}.Client
+{
+ ///
+ /// API client is mainly responsible for making the HTTP call to the API backend.
+ ///
+ {{>visibility}} partial class ApiClient : IDisposable
+ {
+ private JsonSerializerSettings serializerSettings = new JsonSerializerSettings
+ {
+ ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
+ };
+
+ ///
+ /// Allows for extending request processing for generated code.
+ ///
+ /// The RestSharp request object
+ partial void InterceptRequest(HttpRequestMessage request);
+
+ ///
+ /// Allows for extending response processing for generated code.
+ ///
+ /// The RestSharp request object
+ /// The RestSharp response object
+ partial void InterceptResponse(HttpRequestMessage request, HttpResponseMessage response, InterceptResult res);
+
+ ///
+ /// Initializes a new instance of the class
+ /// with default configuration.
+ ///
+ public ApiClient()
+ : this((string)null)
+ {}
+
+ ///
+ /// Initializes a new instance of the class
+ /// with default base path ({{{basePath}}}).
+ ///
+ /// An instance of Configuration.
+ public ApiClient(Configuration config)
+ {
+ Configuration = config ?? {{packageName}}.Client.Configuration.Default;
+
+ RestClient = ClientFactory(Configuration);
+ {{#netStandard}}
+ //special http client adjustments
+ {{/netStandard}}
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with default configuration.
+ ///
+ /// The base path.
+ public ApiClient(String basePath = "{{{basePath}}}")
+ {
+ if (String.IsNullOrEmpty(basePath))
+ throw new ArgumentException("basePath cannot be empty");
+
+ RestClient = ClientFactory(Configuration);
+ {{#netStandard}}
+ //special http client adjustments
+ {{/netStandard}}
+ Configuration = Client.Configuration.Default;
+ }
+
+ ///
+ /// may be overriden to customize client initialization
+ ///
+ public static Func ClientFactory = ClientFactoryDefault;
+
+ static HttpClient ClientFactoryDefault(IReadableConfiguration config)
+ {
+ var res = new HttpClient
+ {
+ BaseAddress = new Uri(config.BasePath),
+ Timeout = TimeSpan.FromMilliseconds(config.Timeout),
+ };
+ res.DefaultRequestHeaders.Add("User-Agent", config.UserAgent);
+ return res;
+ }
+
+ ///
+ /// Gets or sets the default API client for making HTTP calls.
+ ///
+ /// The default API client.
+ [Obsolete("ApiClient.Default is deprecated, please use 'Configuration.Default.ApiClient' instead.")]
+ public static ApiClient Default;
+
+ private bool disposedValue;
+
+ ///
+ /// Gets or sets an instance of the IReadableConfiguration.
+ ///
+ /// An instance of the IReadableConfiguration.
+ ///
+ /// helps us to avoid modifying possibly global
+ /// configuration values from within a given client. It does not guarantee thread-safety
+ /// of the instance in any way.
+ ///
+ public IReadableConfiguration Configuration { get; set; }
+
+ ///
+ /// Gets or sets the RestClient.
+ ///
+ /// An instance of the RestClient
+ public HttpClient RestClient { get; set; }
+
+ // Creates and sets up a RestRequest prior to a call.
+ private HttpRequestMessage PrepareRequest(String path, HttpMethod method, RequestParameters parameters)
+ {
+ foreach (var pathParameter in parameters.pathParams)
+ path = path.Replace(string.Concat("{", pathParameter.Key, "}"), pathParameter.Value);
+
+ var builder = new UriBuilder($"{Configuration.BasePath}/");
+ builder.Path = builder.Path + path.TrimStart('/');
+ builder.Query = parameters.GetQuery();
+
+ var address = builder.ToString();
+
+ var request = new HttpRequestMessage(method, address);
+ {{#netStandard}}
+ //special http client adjustments
+ {{/netStandard}}
+
+ // add header parameter, if any
+ foreach(var param in parameters.headerParams)
+ request.Headers.Add(param.Key, param.Value);
+
+ // add form parameter, if any
+ foreach(var param in parameters.formParams)
+ request.Headers.Add(param.Key, param.Value);
+
+ long contentLength = 0;
+
+ if (parameters.postBody != null) // http body (model or byte[]) parameter
+ {
+ var stringBody = parameters.postBody as string;
+ var contentValue = stringBody != null
+ ? stringBody
+ : JsonConvert.SerializeObject(parameters.postBody);
+ var content = new StringContent(contentValue, Encoding.UTF8, parameters.contentType);
+ request.Content = content; //.(contentType, postBody, ParameterType.RequestBody);
+
+ contentLength = contentValue.Length;
+ }
+
+ return request;
+ }
+
+ ///
+ /// Makes the HTTP request (Sync).
+ ///
+ /// URL path.
+ /// HTTP method.
+ /// Object
+ public HttpResponseMessage CallApi(
+ String path, HttpMethod method, RequestParameters parameters)
+ {
+ var request = PrepareRequest(path, method, parameters);
+
+ InterceptRequest(request);
+ var res = new InterceptResult();
+ {{#netStandard}}
+ var response = RestClient.SendAsync(request).Result;
+ {{/netStandard}}
+ {{^netStandard}}
+ {{^supportsUWP}}
+ var response = RestClient.SendAsync(request).Result;
+ {{/supportsUWP}}
+ {{#supportsUWP}}
+ // Using async method to perform sync call (uwp-only)
+ var response = RestClient.SendAsync(request).Result;
+ {{/supportsUWP}}
+ {{/netStandard}}
+ InterceptResponse(request, response, res);
+ if (res.Retry)
+ {
+ request = PrepareRequest(path, method, parameters); //HttpClient requires to create new request message
+ response = RestClient.SendAsync(request).Result;
+ InterceptResponse(request, response, res);
+ }
+
+ return response;
+ }
+ {{#supportsAsync}}
+ ///
+ /// Makes the asynchronous HTTP request.
+ ///
+ /// URL path.
+ /// HTTP method.
+ /// The Task instance.
+ public async System.Threading.Tasks.Task CallApiAsync(
+ String path, HttpMethod method, RequestParameters parameters)
+ {
+ var request = PrepareRequest(path, method, parameters);
+ InterceptRequest(request);
+ var res = new InterceptResult();
+ var response = await RestClient.SendAsync(request);
+ InterceptResponse(request, response, res);
+ if (res.Retry)
+ {
+ request = PrepareRequest(path, method, parameters); //HttpClient requires to create new request message
+ response = await RestClient.SendAsync(request);
+ InterceptResponse(request, response, res);
+ }
+ return response;
+ }{{/supportsAsync}}
+
+ ///
+ /// Escape string (url-encoded).
+ ///
+ /// String to be escaped.
+ /// Escaped string.
+ public string EscapeString(string str)
+ {
+ return UrlEncode(str);
+ }
+
+ ///
+ /// Deserialize the JSON string into a proper object.
+ ///
+ ///
+ ///
+ ///
+ public T Deserialize(HttpResponseMessage response)
+ {
+ return (T)Deserialize(response, typeof(T));
+ }
+
+ ///
+ /// Deserialize the JSON string into a proper object.
+ ///
+ /// The HTTP response.
+ /// Object type.
+ /// Object representation of the JSON string.
+ public object Deserialize(HttpResponseMessage response, Type type)
+ {
+ var headers = response.Headers;
+ if (type == typeof(byte[])) // return byte array
+ {
+ return response.Content.ReadAsByteArrayAsync().Result;
+ }
+
+ // TODO: ? if (type.IsAssignableFrom(typeof(Stream)))
+ if (type == typeof(Stream))
+ {
+ if (headers != null)
+ {
+ var filePath = String.IsNullOrEmpty(Configuration.TempFolderPath)
+ ? Path.GetTempPath()
+ : Configuration.TempFolderPath;
+ var regex = new Regex(@"Content-Disposition=.*filename=['""]?([^'""\s]+)['""]?$");
+ foreach (var header in headers)
+ {
+ var match = regex.Match(header.Value.First());
+ if (match.Success)
+ {
+ string fileName = filePath + SanitizeFilename(match.Groups[1].Value.Replace("\"", "").Replace("'", ""));
+ File.WriteAllBytes(fileName, response.Content.ReadAsByteArrayAsync().Result);
+ return new FileStream(fileName, FileMode.Open);
+ }
+ }
+ }
+ var stream = new MemoryStream(response.Content.ReadAsByteArrayAsync().Result);
+ return stream;
+ }
+
+ if (type.Name.StartsWith("System.Nullable`1[[System.DateTime")) // return a datetime object
+ {
+ return DateTime.Parse(response.Content.ReadAsStringAsync().Result, null, System.Globalization.DateTimeStyles.RoundtripKind);
+ }
+
+ if (type == typeof(String) || type.Name.StartsWith("System.Nullable")) // return primitive type
+ {
+ return ConvertType(response.Content, type);
+ }
+
+ // at this point, it must be a model (json)
+ try
+ {
+ return JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result, type, serializerSettings);
+ }
+ catch (Exception e)
+ {
+ throw new ApiException(500, e.Message);
+ }
+ }
+
+ ///
+ /// Select the Accept header's value from the given accepts array:
+ /// if JSON exists in the given array, use it;
+ /// otherwise use all of them (joining into a string)
+ ///
+ /// The accepts array to select from.
+ /// The Accept header to use.
+ public String SelectHeaderAccept(String[] accepts)
+ {
+ if (accepts.Length == 0)
+ return null;
+
+ if (accepts.Contains("application/json", StringComparer.OrdinalIgnoreCase))
+ return "application/json";
+
+ return String.Join(",", accepts);
+ }
+
+ ///
+ /// Encode string in base64 format.
+ ///
+ /// String to be encoded.
+ /// Encoded string.
+ public static string Base64Encode(string text)
+ {
+ return System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(text));
+ }
+
+ ///
+ /// Dynamically cast the object into target type.
+ ///
+ /// Object to be casted
+ /// Target type
+ /// Casted object
+ {{#supportsAsync}}
+ public static dynamic ConvertType(dynamic fromObject, Type toObject)
+ {{/supportsAsync}}
+ {{^supportsAsync}}
+ public static object ConvertType(T fromObject, Type toObject) where T : class
+ {{/supportsAsync}}
+ {
+ return Convert.ChangeType(fromObject, toObject);
+ }
+
+ ///
+ /// Convert stream to byte array
+ ///
+ /// Input stream to be converted
+ /// Byte array
+ public static byte[] ReadAsBytes(Stream inputStream)
+ {
+ byte[] buf = new byte[16*1024];
+ using (MemoryStream ms = new MemoryStream())
+ {
+ int count;
+ while ((count = inputStream.Read(buf, 0, buf.Length)) > 0)
+ {
+ ms.Write(buf, 0, count);
+ }
+ return ms.ToArray();
+ }
+ }
+
+ ///
+ /// URL encode a string
+ /// Credit/Ref: https://github.com/restsharp/RestSharp/blob/master/RestSharp/Extensions/StringExtensions.cs#L50
+ ///
+ /// String to be URL encoded
+ /// Byte array
+ public static string UrlEncode(string input)
+ {
+ const int maxLength = 32766;
+
+ if (input == null)
+ {
+ throw new ArgumentNullException("input");
+ }
+
+ if (input.Length <= maxLength)
+ {
+ return Uri.EscapeDataString(input);
+ }
+
+ StringBuilder sb = new StringBuilder(input.Length * 2);
+ int index = 0;
+
+ while (index < input.Length)
+ {
+ int length = Math.Min(input.Length - index, maxLength);
+ string subString = input.Substring(index, length);
+
+ sb.Append(Uri.EscapeDataString(subString));
+ index += subString.Length;
+ }
+
+ return sb.ToString();
+ }
+
+ ///
+ /// Sanitize filename by removing the path
+ ///
+ /// Filename
+ /// Filename
+ public static string SanitizeFilename(string filename)
+ {
+ Match match = Regex.Match(filename, @".*[/\\](.*)$");
+
+ if (match.Success)
+ {
+ return match.Groups[1].Value;
+ }
+ else
+ {
+ return filename;
+ }
+ }
+ {{^netStandard}}
+ {{#supportsUWP}}
+ ///
+ /// Convert stream to byte array
+ ///
+ /// IO stream
+ /// Byte array
+ public static byte[] ToByteArray(Stream stream)
+ {
+ stream.Position = 0;
+ byte[] buffer = new byte[stream.Length];
+ for (int totalBytesCopied = 0; totalBytesCopied < stream.Length;)
+ totalBytesCopied += stream.Read(buffer, totalBytesCopied, Convert.ToInt32(stream.Length) - totalBytesCopied);
+ return buffer;
+ }
+ {{/supportsUWP}}
+ {{/netStandard}}
+
+ ///
+ /// disposing
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposedValue)
+ {
+ if (disposing)
+ {
+ RestClient.Dispose();
+ }
+
+ // TODO: free unmanaged resources (unmanaged objects) and override finalizer
+ // TODO: set large fields to null
+ disposedValue = true;
+ }
+ }
+
+ ///
+ /// IDisposable implementation
+ ///
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+ }
+}
diff --git a/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ApiException.mustache b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ApiException.mustache
new file mode 100644
index 00000000000..cc9108329a5
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ApiException.mustache
@@ -0,0 +1,53 @@
+{{>partial_header}}
+using System;
+
+namespace {{packageName}}.Client
+{
+ ///
+ /// API Exception
+ ///
+ {{>visibility}} class ApiException : Exception
+ {
+ ///
+ /// Gets or sets the error code (HTTP status code)
+ ///
+ /// The error code (HTTP status code).
+ public int ErrorCode { get; set; }
+
+ ///
+ /// Gets or sets the error content (body json object)
+ ///
+ /// The error content (Http response body).
+ public {{#supportsAsync}}dynamic{{/supportsAsync}}{{^supportsAsync}}object{{/supportsAsync}} ErrorContent { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ApiException() {}
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// HTTP status code.
+ /// Error message.
+ public ApiException(int errorCode, string message) : base($"message ({errorCode})")
+ {
+ this.ErrorCode = errorCode;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// HTTP status code.
+ /// Error message.
+ /// Error content.
+ public ApiException(int errorCode, string message, {{#supportsAsync}}dynamic{{/supportsAsync}}{{^supportsAsync}}object{{/supportsAsync}} errorContent = null) : base($"{message} ({errorCode})")
+ {
+ this.ErrorCode = errorCode;
+ this.ErrorContent = errorContent;
+ }
+
+ public string Path { get; set; }
+ }
+
+}
diff --git a/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/Configuration.mustache b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/Configuration.mustache
new file mode 100644
index 00000000000..e863cbe7670
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/Configuration.mustache
@@ -0,0 +1,452 @@
+{{>partial_header}}
+using System;
+using System.Reflection;
+{{^net35}}
+using System.Collections.Concurrent;
+{{/net35}}
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+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
+
+ private static readonly object GlobalConfigSync = new { };
+ private static Configuration _globalConfiguration;
+
+ ///
+ /// Default creation of exceptions for a given method name and response object
+ ///
+ public static readonly ExceptionFactory DefaultExceptionFactory = (methodName, response) =>
+ {
+ var status = (int)response.StatusCode;
+ var message = response.Content?.ReadAsStringAsync()?.Result;
+ if (status >= 400)
+ {
+ return new ApiException(status,
+ string.Format("Error calling {0}", methodName),
+ message)
+ { Path = response.RequestMessage.RequestUri.ToString() };
+ }
+ {{^netStandard}}if (status == 0)
+ {
+ return new ApiException(status,
+ string.Format("Error calling {0}: {1}", methodName, message), message)
+ { Path = response.RequestMessage.RequestUri.ToString() };
+ }{{/netStandard}}
+ return null;
+ };
+
+ ///
+ /// Gets or sets the default Configuration.
+ ///
+ /// Configuration.
+ public static Configuration Default
+ {
+ get { return _globalConfiguration; }
+ set
+ {
+ lock (GlobalConfigSync)
+ {
+ _globalConfiguration = value;
+ }
+ }
+ }
+
+ #endregion Static Members
+
+ #region Private Members
+
+ ///
+ /// Gets or sets the API key based on the authentication name.
+ ///
+ /// The API key.
+ private IDictionary _apiKey = null;
+
+ ///
+ /// 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 = null;
+
+ private string _dateTimeFormat = ISO8601_DATETIME_FORMAT;
+ private string _tempFolderPath = Path.GetTempPath();
+
+ #endregion Private Members
+
+ #region Constructors
+
+ static Configuration()
+ {
+ _globalConfiguration = new GlobalConfiguration();
+ }
+
+ const string userAgentDefault = "{{#httpUserAgent}}{{.}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{packageVersion}} csharp{{/httpUserAgent}}"; // space before csharp
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ public Configuration()
+ {
+ UserAgent = userAgentDefault;
+ BasePath = "{{{basePath}}}";
+ DefaultHeader = new {{^net35}}Concurrent{{/net35}}Dictionary();
+ ApiKey = new {{^net35}}Concurrent{{/net35}}Dictionary();
+ ApiKeyPrefix = new {{^net35}}Concurrent{{/net35}}Dictionary();
+
+ // Setting Timeout has side effects (forces ApiClient creation).
+ Timeout = 100000;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ public Configuration(
+ IDictionary defaultHeader,
+ 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 (defaultHeader == null)
+ throw new ArgumentNullException("defaultHeader");
+ if (apiKey == null)
+ throw new ArgumentNullException("apiKey");
+ if (apiKeyPrefix == null)
+ throw new ArgumentNullException("apiKeyPrefix");
+
+ BasePath = basePath;
+
+ foreach (var keyValuePair in defaultHeader)
+ {
+ DefaultHeader.Add(keyValuePair);
+ }
+
+ foreach (var keyValuePair in apiKey)
+ {
+ ApiKey.Add(keyValuePair);
+ }
+
+ foreach (var keyValuePair in apiKeyPrefix)
+ {
+ ApiKeyPrefix.Add(keyValuePair);
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class with different settings
+ ///
+ /// Api client
+ /// Dictionary of default HTTP header
+ /// Username
+ /// Password
+ /// accessToken
+ /// Dictionary of API key
+ /// Dictionary of API key prefix
+ /// Temp folder path
+ /// DateTime format string
+ /// HTTP connection timeout (in milliseconds)
+ /// HTTP user agent
+ [Obsolete("Use explicit object construction and setting of properties.", true)]
+ public Configuration(
+ // ReSharper disable UnusedParameter.Local
+ ApiClient apiClient = null,
+ IDictionary defaultHeader = null,
+ string username = null,
+ string password = null,
+ string accessToken = null,
+ IDictionary apiKey = null,
+ IDictionary apiKeyPrefix = null,
+ string tempFolderPath = null,
+ string dateTimeFormat = null,
+ int timeout = 100000,
+ string userAgent = userAgentDefault
+ // ReSharper restore UnusedParameter.Local
+ )
+ {
+
+ }
+
+ ///
+ /// Initializes a new instance of the Configuration class.
+ ///
+ /// Api client.
+ [Obsolete("This constructor caused unexpected sharing of static data. It is no longer supported.", true)]
+ // ReSharper disable once UnusedParameter.Local
+ public Configuration(ApiClient apiClient)
+ {
+
+ }
+
+ #endregion Constructors
+
+
+ #region Properties
+
+ private ApiClient _apiClient = null;
+ ///
+ /// Gets an instance of an ApiClient for this configuration
+ ///
+ public virtual ApiClient ApiClient
+ {
+ get
+ {
+ if (_apiClient == null) _apiClient = CreateApiClient();
+ return _apiClient;
+ }
+ }
+
+ ///
+ /// Gets or sets the base path for API access.
+ ///
+ public virtual string BasePath { get; set; }
+
+ ///
+ /// Gets or sets the default header.
+ ///
+ public virtual IDictionary DefaultHeader { get; set; }
+
+ int timeout;
+ ///
+ /// Gets or sets the HTTP timeout (milliseconds) of ApiClient. Default to 100000 milliseconds.
+ ///
+ public virtual int Timeout
+ {
+ get { return timeout; }
+ set
+ {
+ timeout = System.Convert.ToInt32(value);
+ if (_apiClient != null)
+ ApiClient.RestClient.Timeout = TimeSpan.FromMilliseconds(value);
+ }
+ }
+
+ ///
+ /// 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)
+ {
+ var apiKeyValue = "";
+ ApiKey.TryGetValue (apiKeyIdentifier, out apiKeyValue);
+ var apiKeyPrefix = "";
+ if (ApiKeyPrefix.TryGetValue (apiKeyIdentifier, out apiKeyPrefix))
+ return apiKeyPrefix + " " + apiKeyValue;
+ else
+ return apiKeyValue;
+ }
+
+ ///
+ /// Gets or sets the access token for OAuth2 authentication.
+ ///
+ /// The access token.
+ public virtual string AccessToken { get; set; }
+
+ ///
+ /// 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))
+ {
+ // Possible breaking change since swagger-codegen 2.2.1, enforce a valid temporary path on set.
+ _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.
+ ///
+ /// 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;
+ }
+ }
+
+ #endregion Properties
+
+ #region Methods
+
+ ///
+ /// Add default header.
+ ///
+ /// Header field name.
+ /// Header field value.
+ ///
+ public void AddDefaultHeader(string key, string value)
+ {
+ DefaultHeader[key] = value;
+ }
+
+ ///
+ /// Creates a new based on this instance.
+ ///
+ ///
+ public ApiClient CreateApiClient()
+ {
+ return new ApiClient(this);
+ }
+
+ ///
+ /// Returns a string with essential information for debugging.
+ ///
+ public static String ToDebugReport()
+ {
+ String report = "C# SDK ({{{packageName}}}) Debug Report:\n";
+ {{^netStandard}}
+ {{^supportsUWP}}
+ report += " OS: " + System.Environment.OSVersion + "\n";
+ report += " .NET Framework Version: " + System.Environment.Version + "\n";
+ {{/supportsUWP}}
+ {{/netStandard}}
+ {{#netStandard}}
+ report += " OS: " + System.Runtime.InteropServices.RuntimeInformation.OSDescription + "\n";
+ {{/netStandard}}
+ 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
+ }
+}
diff --git a/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ExceptionFactory.mustache b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ExceptionFactory.mustache
new file mode 100644
index 00000000000..bc9ac7b631d
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ExceptionFactory.mustache
@@ -0,0 +1,20 @@
+{{>partial_header}}
+
+using System;
+{{#netStandard}}
+using System.Net.Http;
+{{/netStandard}}
+{{^netStandard}}
+using System.Net.Http;
+{{/netStandard}}
+
+namespace {{packageName}}.Client
+{
+ ///
+ /// A delegate to ExceptionFactory method
+ ///
+ /// Method name
+ /// Response
+ /// Exceptions
+ {{>visibility}} delegate Exception ExceptionFactory(string methodName, HttpResponseMessage response);
+}
diff --git a/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/IApiAccessor.mustache b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/IApiAccessor.mustache
new file mode 100644
index 00000000000..e7be9db62ef
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/IApiAccessor.mustache
@@ -0,0 +1,32 @@
+{{>partial_header}}
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+
+namespace {{packageName}}.Client
+{
+ ///
+ /// Represents configuration aspects required to interact with the API endpoints.
+ ///
+ {{>visibility}} interface IApiAccessor
+ {
+ ///
+ /// Gets or sets the configuration object
+ ///
+ /// An instance of the Configuration
+ Configuration Configuration {get; set;}
+
+ ///
+ /// Gets the base path of the API client.
+ ///
+ /// The base path
+ String GetBasePath();
+
+ ///
+ /// Provides a factory method hook for the creation of exceptions.
+ ///
+ ExceptionFactory ExceptionFactory { get; set; }
+ }
+}
diff --git a/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/InterceptResult.mustache b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/InterceptResult.mustache
new file mode 100644
index 00000000000..610a68d8a50
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/InterceptResult.mustache
@@ -0,0 +1,16 @@
+{{>partial_header}}
+using System;
+
+namespace {{packageName}}.Client
+{
+ ///
+ /// allows interceptor to return some data to the
+ ///
+ class InterceptResult
+ {
+ ///
+ /// should it retry to send the request
+ ///
+ public bool Retry;
+ }
+}
diff --git a/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/Project.mustache b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/Project.mustache
new file mode 100644
index 00000000000..fdd45a2e76e
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/Project.mustache
@@ -0,0 +1,114 @@
+
+
+
+
+ {{#netStandard}}14.0{{/netStandard}}
+ Debug
+ AnyCPU
+ {{packageGuid}}
+ Library
+ Properties
+ {{packageName}}
+ {{packageName}}
+ {{#netStandard}}
+ {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {{targetFramework}}
+ {{/netStandard}}
+ {{^netStandard}}
+ {{^supportsUWP}}
+ {{targetFramework}}
+ {{/supportsUWP}}
+ {{#supportsUWP}}
+ UAP
+ 10.0.10240.0
+ 10.0.10240.0
+ 14
+ {{/supportsUWP}}
+ {{/netStandard}}
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ {{^netStandard}}
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\{{targetFrameworkNuget}}\Newtonsoft.Json.dll
+ ..\packages\Newtonsoft.Json.10.0.3\lib\{{targetFrameworkNuget}}\Newtonsoft.Json.dll
+ ..\..\packages\Newtonsoft.Json.10.0.3\lib\{{targetFrameworkNuget}}\Newtonsoft.Json.dll
+ {{binRelativePath}}\Newtonsoft.Json.10.0.3\lib\{{targetFrameworkNuget}}\Newtonsoft.Json.dll
+
+
+ $(SolutionDir)\packages\JsonSubTypes.1.2.0\lib\{{targetFrameworkNuget}}\JsonSubTypes.dll
+ ..\packages\JsonSubTypes.1.2.0\lib\{{targetFrameworkNuget}}\JsonSubTypes.dll
+ ..\..\packages\JsonSubTypes.1.2.0\lib\{{targetFrameworkNuget}}\JsonSubTypes.dll
+ {{binRelativePath}}\JsonSubTypes.1.2.0\lib\{{targetFrameworkNuget}}\JsonSubTypes.dll
+
+ {{#generatePropertyChanged}}
+
+ ..\..\packages\PropertyChanged.Fody.1.51.3\Lib\portable-net4+sl4+wp8+win8+wpa81+MonoAndroid16+MonoTouch40\PropertyChanged.dll
+
+ {{/generatePropertyChanged}}
+ {{/netStandard}}
+ {{#netStandard}}
+
+
+ {{/netStandard}}
+
+
+
+
+ {{^netStandard}}
+
+
+ {{#generatePropertyChanged}}
+
+ {{/generatePropertyChanged}}
+
+
+ {{#generatePropertyChanged}}
+
+ {{/generatePropertyChanged}}
+ {{/netStandard}}
+ {{#netStandard}}
+
+
+ {{/netStandard}}
+
+
diff --git a/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/RequestParameters.mustache b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/RequestParameters.mustache
new file mode 100644
index 00000000000..f401c7bda91
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/RequestParameters.mustache
@@ -0,0 +1,347 @@
+{{>partial_header}}
+
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+using System.Net.Http;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace {{packageName}}.Client
+{
+ ///
+ /// request parameters helper
+ ///
+ public class RequestParameters
+ {
+ private readonly IReadableConfiguration config;
+
+ public List> queryParams { get; }
+ public Object postBody { get; set; }
+ public Dictionary headerParams { get; }
+ public Dictionary formParams { get; }
+ //public Dictionary fileParams;
+ public Dictionary pathParams { get; }
+ public String contentType { get; set; }
+
+ /////
+ ///// Create FileParameter based on Stream.
+ /////
+ ///// Parameter name.
+ ///// Input stream.
+ ///// FileParameter.
+ //public FileParameter ParameterToFile(string name, Stream stream)
+ //{
+ // if (stream is FileStream)
+ // return FileParameter.Create(name, ReadAsBytes(stream), Path.GetFileName(((FileStream)stream).Name));
+ // else
+ // return FileParameter.Create(name, ReadAsBytes(stream), "no_file_name_provided");
+ //}
+
+ ///
+ /// initialized object instance
+ ///
+ /// configuration instance
+ /// allowed content types
+ /// accepted formats
+ public RequestParameters(IReadableConfiguration config, string[] contentTypes = null, string[] accepts = null)
+ {
+ this.pathParams = new Dictionary();
+ this.formParams = new Dictionary();
+ this.pathParams = new Dictionary();
+ this.headerParams = new Dictionary();
+ this.queryParams = new List>();
+ this.config = config;
+
+ // order matters
+ if (contentTypes != null)
+ this.contentType = SelectHeaderContentType(contentTypes);
+ if (accepts != null)
+ {
+ var localVarHttpHeaderAccept = SelectHeaderAccept(accepts);
+ if (localVarHttpHeaderAccept != null)
+
+ AddHeader("Accept", localVarHttpHeaderAccept);
+ }
+ }
+
+ ///
+ /// add path parameter value
+ ///
+ ///
+ ///
+ public void AddPath(string name, object value)
+ {
+ if (value != null)
+ pathParams.Add(name, ParameterToString(value));
+ }
+
+ ///
+ /// add header parameter value
+ ///
+ ///
+ ///
+ public void AddHeader(string name, object value)
+ {
+ if (value != null)
+ headerParams.Add(name, ParameterToString(value));
+ }
+
+ ///
+ /// add body parameter value
+ ///
+ ///
+ public void AddBody(object value)
+ {
+ if (value != null && value.GetType() != typeof(byte[]))
+ {
+ postBody = Serialize(value); // http body (model) parameter
+ }
+ else
+ {
+ postBody = value; // byte array
+ }
+
+ }
+
+ ///
+ /// add query parameter value
+ ///
+ ///
+ ///
+ ///
+ public void AddQuery(string format, string name, object value)
+ {
+ if (value != null)
+ queryParams.AddRange(ParameterToKeyValuePairs(format, name, value));
+ }
+
+ ///
+ /// add query parameter value
+ ///
+ ///
+ ///
+ public void AddQuery(string name, object value)
+ {
+ if (value != null)
+ queryParams.AddRange(ParameterToKeyValuePairs("", name, value));
+ }
+
+ ///
+ /// add form parameter value
+ ///
+ /// parameter name
+ /// parameter value
+ public void AddForm(string name, object value)
+ {
+ if (value != null)
+ formParams.Add(name, ParameterToString(value));
+ }
+
+ ///
+ /// Convert params to key/value pairs.
+ /// Use collectionFormat to properly format lists and collections.
+ ///
+ /// "multi" of causes collection from to be set multiple times
+ /// Key name.
+ /// Value object.
+ /// A list of KeyValuePairs both key and value are encoded
+ public IEnumerable> ParameterToKeyValuePairs(string collectionFormat, string name, object value)
+ {
+ var parameters = new List>();
+
+ if (IsCollection(value) && collectionFormat == "multi")
+ {
+ var valueCollection = value as System.Collections.IEnumerable;
+ parameters.AddRange(from object item in valueCollection select new KeyValuePair(name, ParameterToString(item)));
+ }
+ else
+ {
+ parameters.Add(new KeyValuePair(name, ParameterToString(value)));
+ }
+
+ return parameters;
+ }
+
+ ///
+ /// Check if generic object is a collection.
+ ///
+ ///
+ /// True if object is a collection type
+ private static bool IsCollection(object value)
+ {
+ return value is System.Collections.IList || value is System.Collections.ICollection;
+ }
+
+ ///
+ /// Serialize an input (model) into JSON string
+ ///
+ /// Object.
+ /// JSON string.
+ public String Serialize(object obj)
+ {
+ try
+ {
+ return obj != null ? JsonConvert.SerializeObject(obj) : null;
+ }
+ catch (Exception e)
+ {
+ throw new ApiException(500, e.Message);
+ }
+ }
+
+ ///
+ /// concatenates query parameters from
+ ///
+ /// query string having encoded names and values
+ public string GetQuery()
+ {
+ var separator = "?";
+ var sb = new StringBuilder(); // is it the best way on .Net Standard 1.6 ?
+
+ foreach (var q in queryParams)
+ {
+ var key = Encode(q.Key);
+ var value = Encode(q.Value);
+
+ sb.Append($"{separator}{key}={value}");
+ separator = "&";
+ }
+ return sb.ToString();
+ }
+
+ ///
+ /// Select the Accept header's value from the given accepts array:
+ /// if JSON exists in the given array, use it;
+ /// otherwise use all of them (joining into a string)
+ ///
+ /// The accepts array to select from.
+ /// The Accept header to use.
+ public String SelectHeaderAccept(String[] accepts)
+ {
+ if (accepts.Length == 0)
+ return null;
+
+ if (accepts.Contains("application/json", StringComparer.OrdinalIgnoreCase))
+ return "application/json";
+
+ return String.Join(",", accepts);
+ }
+
+ ///
+ ///Check if the given MIME is a JSON MIME.
+ ///JSON MIME examples:
+ /// application/json
+ /// application/json; charset=UTF8
+ /// APPLICATION/JSON
+ /// application/vnd.company+json
+ ///
+ /// MIME
+ /// Returns True if MIME type is json.
+ public bool IsJsonMime(String mime)
+ {
+ var jsonRegex = new Regex("(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$");
+ return mime != null && (jsonRegex.IsMatch(mime) || mime.Equals("application/json-patch+json"));
+ }
+
+ ///
+ /// Select the Content-Type header's value from the given content-type array:
+ /// if JSON type exists in the given array, use it;
+ /// otherwise use the first one defined in 'consumes'
+ ///
+ /// The Content-Type array to select from.
+ /// The Content-Type header to use.
+ public String SelectHeaderContentType(String[] contentTypes)
+ {
+ if (contentTypes.Length == 0)
+ return "application/json";
+
+ foreach (var contentType in contentTypes)
+ {
+ if (IsJsonMime(contentType.ToLower()))
+ return contentType;
+ }
+
+ return contentTypes[0]; // use the first content type specified in 'consumes'
+ }
+
+ ///
+ /// 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 ",".
+ /// Otherwise just return the string.
+ ///
+ /// The parameter (header, path, query, form).
+ /// Formatted and encoded string.
+ public string ParameterToString(object obj)
+ {
+ if (obj is DateTime)
+ // 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-15T13:45:30.0000000
+ return ((DateTime)obj).ToString(config.DateTimeFormat);
+ else if (obj is DateTimeOffset)
+ // 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-15T13:45:30.0000000
+ return ((DateTimeOffset)obj).ToString(config.DateTimeFormat);
+ else if (obj is System.Collections.IList)
+ {
+ var flattenedString = new StringBuilder();
+ foreach (var param in (System.Collections.IList)obj)
+ {
+ if (flattenedString.Length > 0)
+ flattenedString.Append(",");
+ flattenedString.Append(Convert.ToString(param, neutral));
+ }
+ return flattenedString.ToString();
+ }
+ else
+ return Convert.ToString(obj, neutral);
+ }
+
+ static IFormatProvider neutral = System.Globalization.CultureInfo.InvariantCulture;
+
+ string Encode(string value)
+ {
+ return System.Net.WebUtility.UrlEncode(value);
+ }
+
+ public void AddAuthKeyInHeader(string keyParamName)
+ {
+ if (!String.IsNullOrEmpty(config.GetApiKeyWithPrefix(keyParamName)))
+ {
+ AddHeader(keyParamName, config.GetApiKeyWithPrefix(keyParamName));
+ }
+ }
+
+ public void AddAuthKeyInQuery(string keyParamName)
+ {
+ if (!String.IsNullOrEmpty(config.GetApiKeyWithPrefix(keyParamName)))
+ {
+ AddQuery("", keyParamName, config.GetApiKeyWithPrefix(keyParamName));
+ }
+ }
+
+ public void AddAuthBasic()
+ {
+ // http basic authentication required
+ if (!String.IsNullOrEmpty(config.Username) || !String.IsNullOrEmpty(config.Password))
+ {
+ AddHeader("Authorization", "Basic " + ApiClient.Base64Encode(config.Username + ":" + config.Password));
+ }
+ }
+
+ public void AddAuthAccessToken()
+ {
+ // oauth required
+ if (!String.IsNullOrEmpty(config.AccessToken))
+ {
+ AddHeader("Authorization", "Bearer " + config.AccessToken);
+ }
+ }
+ }
+}
diff --git a/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ResponseExtension.mustache b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ResponseExtension.mustache
new file mode 100644
index 00000000000..c9b8fe06078
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/ResponseExtension.mustache
@@ -0,0 +1,24 @@
+{{>partial_header}}
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Text;
+
+namespace {{packageName}}.Client
+{
+ ///
+ /// HttpResponseMessage helper
+ ///
+ public static class ResponseExtension
+ {
+ ///
+ /// HttpResponseMessage headers to IDictionary convertion
+ ///
+ public static IDictionary ToHeaders(this HttpResponseMessage value)
+ {
+ return value.Headers.ToDictionary(x => x.Key, x => string.Join("", x.Value));
+ }
+ }
+}
diff --git a/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/api.mustache b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/api.mustache
new file mode 100644
index 00000000000..7b96febdb76
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/csharp/libraries/httpClient/api.mustache
@@ -0,0 +1,392 @@
+{{>partial_header}}
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+{{#netStandard}}
+using System.Net.Http;
+{{/netStandard}}
+{{^netStandard}}
+using System.Net.Http;
+{{/netStandard}}
+using {{packageName}}.Client;
+{{#hasImport}}using {{packageName}}.{{modelPackage}};
+{{/hasImport}}
+
+namespace {{packageName}}.{{apiPackage}}
+{
+ {{#operations}}
+ ///
+ /// Represents a collection of functions to interact with the API endpoints
+ ///
+ {{>visibility}} interface {{interfacePrefix}}{{classname}} : IApiAccessor
+ {
+ #region Synchronous Operations
+ {{#operation}}
+ ///
+ /// {{summary}}
+ ///
+ ///
+ /// {{notes}}
+ ///
+ /// Thrown when fails to make API call
+ {{#allParams}}/// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}
+ {{/allParams}}/// {{#returnType}}{{returnType}}{{/returnType}}
+ {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
+
+ ///
+ /// {{summary}}
+ ///
+ ///
+ /// {{notes}}
+ ///
+ /// Thrown when fails to make API call
+ {{#allParams}}/// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}
+ {{/allParams}}/// ApiResponse of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Object(void){{/returnType}}
+ ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
+ {{/operation}}
+ #endregion Synchronous Operations
+ {{#supportsAsync}}
+ #region Asynchronous Operations
+ {{#operation}}
+ ///
+ /// {{summary}}
+ ///
+ ///
+ /// {{notes}}
+ ///
+ /// Thrown when fails to make API call
+ {{#allParams}}/// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}
+ {{/allParams}}/// Task of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}
+ {{#returnType}}System.Threading.Tasks.Task<{{{returnType}}}>{{/returnType}}{{^returnType}}System.Threading.Tasks.Task{{/returnType}} {{operationId}}Async ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
+
+ ///
+ /// {{summary}}
+ ///
+ ///
+ /// {{notes}}
+ ///
+ /// Thrown when fails to make API call
+ {{#allParams}}/// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}
+ {{/allParams}}/// Task of ApiResponse{{#returnType}} ({{returnType}}){{/returnType}}
+ System.Threading.Tasks.Task> {{operationId}}AsyncWithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
+ {{/operation}}
+ #endregion Asynchronous Operations
+ {{/supportsAsync}}
+ }
+
+ ///
+ /// Represents a collection of functions to interact with the API endpoints
+ ///
+ {{>visibility}} partial class {{classname}} : {{interfacePrefix}}{{classname}}
+ {
+ private {{packageName}}.Client.ExceptionFactory _exceptionFactory = (name, response) => null;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ public {{classname}}(String basePath)
+ {
+ this.Configuration = new {{packageName}}.Client.Configuration { BasePath = basePath };
+
+ ExceptionFactory = {{packageName}}.Client.Configuration.DefaultExceptionFactory;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// using Configuration object
+ ///
+ /// An instance of Configuration
+ ///
+ public {{classname}}({{packageName}}.Client.Configuration configuration = null)
+ {
+ if (configuration == null) // use the default one in Configuration
+ this.Configuration = {{packageName}}.Client.Configuration.Default;
+ else
+ this.Configuration = configuration;
+
+ ExceptionFactory = {{packageName}}.Client.Configuration.DefaultExceptionFactory;
+ }
+
+ ///
+ /// Gets the base path of the API client.
+ ///
+ /// The base path
+ public String GetBasePath()
+ {
+ return this.Configuration.BasePath;
+ }
+
+ ///
+ /// Sets the base path of the API client.
+ ///
+ /// The base path
+ [Obsolete("SetBasePath is deprecated, please do 'Configuration.ApiClient = new ApiClient(\"http://new-path\")' instead.")]
+ public void SetBasePath(String basePath)
+ {
+ // do nothing
+ }
+
+ ///
+ /// Gets or sets the configuration object
+ ///
+ /// An instance of the Configuration
+ public {{packageName}}.Client.Configuration Configuration {get; set;}
+
+ ///
+ /// Provides a factory method hook for the creation of exceptions.
+ ///
+ public {{packageName}}.Client.ExceptionFactory ExceptionFactory
+ {
+ get
+ {
+ if (_exceptionFactory != null && _exceptionFactory.GetInvocationList().Length > 1)
+ {
+ throw new InvalidOperationException("Multicast delegate for ExceptionFactory is unsupported.");
+ }
+ return _exceptionFactory;
+ }
+ set { _exceptionFactory = value; }
+ }
+
+ ///
+ /// Gets the default header.
+ ///
+ /// Dictionary of HTTP header
+ [Obsolete("DefaultHeader is deprecated, please use Configuration.DefaultHeader instead.")]
+ public IDictionary DefaultHeader()
+ {
+ return new {{^net35}}ReadOnly{{/net35}}Dictionary(this.Configuration.DefaultHeader);
+ }
+
+ ///
+ /// Add default header.
+ ///
+ /// Header field name.
+ /// Header field value.
+ ///
+ [Obsolete("AddDefaultHeader is deprecated, please use Configuration.AddDefaultHeader instead.")]
+ public void AddDefaultHeader(string key, string value)
+ {
+ this.Configuration.AddDefaultHeader(key, value);
+ }
+
+ {{#operation}}
+ ///
+ /// {{summary}} {{notes}}
+ ///
+ /// Thrown when fails to make API call
+ {{#allParams}}/// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}
+ {{/allParams}}/// {{#returnType}}{{returnType}}{{/returnType}}
+ public {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
+ {
+ {{#returnType}}ApiResponse<{{{returnType}}}> localVarResponse = {{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
+ return localVarResponse.Data;{{/returnType}}{{^returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{/returnType}}
+ }
+
+ ///
+ /// {{summary}} {{notes}}
+ ///
+ /// Thrown when fails to make API call
+ {{#allParams}}/// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}
+ {{/allParams}}/// ApiResponse of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Object(void){{/returnType}}
+ public ApiResponse<{{#returnType}} {{{returnType}}} {{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}WithHttpInfo ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
+ {
+ {{#allParams}}
+ {{#required}}
+ // verify the required parameter '{{paramName}}' is set
+ if ({{paramName}} == null)
+ throw new ApiException(400, "Missing required parameter '{{paramName}}' when calling {{classname}}->{{operationId}}");
+ {{/required}}
+ {{/allParams}}
+
+ var localVarPath = "{{#netStandard}}.{{/netStandard}}{{{path}}}";
+
+ // to determine the Content-Type header
+ String[] localVarHttpContentTypes = new String[] {
+ {{#consumes}}
+ "{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}
+ {{/consumes}}
+ };
+
+ // to determine the Accept header
+ String[] localVarHttpHeaderAccepts = new String[] {
+ {{#produces}}
+ "{{{mediaType}}}"{{#hasMore}},{{/hasMore}}
+ {{/produces}}
+ };
+ var requestParameters = new RequestParameters(Configuration, contentTypes: localVarHttpContentTypes, accepts: localVarHttpHeaderAccepts);
+
+ {{#pathParams}}
+ requestParameters.AddPath("{{baseName}}", {{paramName}}); // path parameter
+ {{/pathParams}}
+ {{#queryParams}}
+ requestParameters.AddQuery("{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}", "{{baseName}}", {{paramName}}); // query parameter
+ {{/queryParams}}
+ {{#headerParams}}
+ requestParameters.AddHeader("{{baseName}}", {{paramName}}); // header parameter
+ {{/headerParams}}
+ {{#formParams}}
+ {{#isFile}}//if ({{paramName}} != null) localVarFileParams.Add("{{baseName}}", this.Configuration.ApiClient.ParameterToFile("{{baseName}}", {{paramName}}));{{/isFile}}{{^isFile}}requestParameters.AddForm("{{baseName}}", {{paramName}}); // form parameter{{/isFile}}
+ {{/formParams}}
+ {{#bodyParam}}
+ requestParameters.AddBody({{paramName}}); // body parameter
+ {{/bodyParam}}
+
+ {{#authMethods}}
+ // authentication ({{name}}) required
+ {{#isApiKey}}
+ {{#isKeyInHeader}}
+ requestParameters.AddAuthKeyInHeader("{{keyParamName}}");
+ {{/isKeyInHeader}}
+ {{#isKeyInQuery}}
+ requestParameters.AddAuthKeyInQuery("{{keyParamName}}");
+ {{/isKeyInQuery}}
+ {{/isApiKey}}
+ {{#isBasic}}
+ // http basic authentication required
+ requestParameters.AddAuthBasic();
+ {{/isBasic}}
+ {{#isOAuth}}
+ // oauth required
+ requestParameters.AddAuthAccessToken();
+ {{/isOAuth}}
+ {{/authMethods}}
+
+ // make the HTTP request
+ var localVarResponse = this.Configuration.ApiClient.CallApi(localVarPath,
+ new HttpMethod("{{httpMethod}}"), requestParameters);
+
+ int localVarStatusCode = (int) localVarResponse.StatusCode;
+
+ if (ExceptionFactory != null)
+ {
+ Exception exception = ExceptionFactory("{{operationId}}", localVarResponse);
+ if (exception != null) throw exception;
+ }
+
+ {{#returnType}}
+ return new ApiResponse<{{{returnType}}}>(localVarStatusCode,
+ localVarResponse.ToHeaders(),
+ this.Configuration.ApiClient.Deserialize<{{#returnContainer}}{{{returnContainer}}}{{/returnContainer}}{{^returnContainer}}{{{returnType}}}{{/returnContainer}}>(localVarResponse));
+ {{/returnType}}
+ {{^returnType}}
+ return new ApiResponse