[C#][NetCore] add multi-server support (#7433)

* multi server support in C# netcore clients

* switch to IReadOnlyDictionary

* minor fixes, add tests
This commit is contained in:
William Cheng 2020-09-19 15:07:12 +08:00 committed by GitHub
parent 92f7a306a1
commit ea559b5e20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 466 additions and 7 deletions

View File

@ -49,11 +49,13 @@ namespace {{packageName}}.Client
string.Format("Error calling {0}: {1}", methodName, response.RawContent),
response.RawContent, response.Headers);
}
{{^netStandard}}if (status == 0)
{{^netStandard}}
if (status == 0)
{
return new ApiException(status,
string.Format("Error calling {0}: {1}", methodName, response.ErrorText), response.ErrorText);
}{{/netStandard}}
}
{{/netStandard}}
return null;
};
@ -82,6 +84,14 @@ namespace {{packageName}}.Client
private string _dateTimeFormat = ISO8601_DATETIME_FORMAT;
private string _tempFolderPath = Path.GetTempPath();
{{#servers.0}}
/// <summary>
/// Gets or sets the servers defined in the OpenAPI spec.
/// </summary>
/// <value>The servers</value>
private IList<IReadOnlyDictionary<string, object>> _servers;
{{/servers.0}}
/// <summary>
/// HTTPSigning configuration
@ -102,6 +112,48 @@ namespace {{packageName}}.Client
DefaultHeaders = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
ApiKey = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
ApiKeyPrefix = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
{{#servers}}
{{#-first}}
Servers = new List<IReadOnlyDictionary<string, object>>()
{
{{/-first}}
{
new Dictionary<string, object> {
{"url", "{{{url}}}"},
{"description", "{{{description}}}{{^description}}No description provided{{/description}}"},
{{#variables}}
{{#-first}}
{
"variables", new Dictionary<string, object> {
{{/-first}}
{
"{{{name}}}", new Dictionary<string, object> {
{"description", "{{{description}}}{{^description}}No description provided{{/description}}"},
{"default_value", "{{{defaultValue}}}"},
{{#enumValues}}
{{#-first}}
{
"enum_values", new List<string>() {
{{/-first}}
"{{{.}}}"{{^-last}},{{/-last}}
{{#-last}}
}
}
{{/-last}}
{{/enumValues}}
}
}{{^-last}},{{/-last}}
{{#-last}}
}
}
{{/-last}}
{{/variables}}
}
}{{^-last}},{{/-last}}
{{#-last}}
};
{{/-last}}
{{/servers}}
// Setting Timeout has side effects (forces ApiClient creation).
Timeout = 100000;
@ -337,6 +389,84 @@ namespace {{packageName}}.Client
_apiKey = value;
}
}
{{#servers.0}}
/// <summary>
/// Gets or sets the servers.
/// </summary>
/// <value>The servers.</value>
public virtual IList<IReadOnlyDictionary<string, object>> Servers
{
get { return _servers; }
set
{
if (value == null)
{
throw new InvalidOperationException("Servers may not be null.");
}
_servers = value;
}
}
/// <summary>
/// Returns URL based on server settings without providing values
/// for the variables
/// </summary>
/// <param name="index">Array index of the server settings.</param>
/// <return>The server URL.</return>
public string GetServerUrl(int index)
{
return GetServerUrl(index, null);
}
/// <summary>
/// Returns URL based on server settings.
/// </summary>
/// <param name="index">Array index of the server settings.</param>
/// <param name="inputVariables">Dictionary of the variables and the corresponding values.</param>
/// <return>The server URL.</return>
public string GetServerUrl(int index, Dictionary<string, string> 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<string, string>();
}
IReadOnlyDictionary<string, object> server = Servers[index];
string url = (string)server["url"];
// go through variable and assign a value
foreach (KeyValuePair<string, object> variable in (IReadOnlyDictionary<string, object>)server["variables"])
{
IReadOnlyDictionary<string, object> serverVariables = (IReadOnlyDictionary<string, object>)(variable.Value);
if (inputVariables.ContainsKey(variable.Key))
{
if (((List<string>)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<string>)serverVariables["enum_values"]}");
}
}
else
{
// use defualt value
url = url.Replace("{" + variable.Key + "}", (string)serverVariables["default_value"]);
}
}
return url;
}
{{/servers.0}}
/// <summary>
/// Gets and Sets the HTTPSigningConfiuration

View File

@ -0,0 +1,46 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using RestSharp;
using Xunit;
using Org.OpenAPITools.Client;
using Org.OpenAPITools.Api;
using Org.OpenAPITools.Model;
namespace Org.OpenAPITools.Test
{
/// <summary>
/// Class for testing Configuration
/// </summary>
public class ConfigurationTests
{
public ConfigurationTests()
{
}
/// <summary>
/// Test GetServerUrl
/// </summary>
[Fact]
public void GetServerUrlTest()
{
Configuration c = new Configuration();
// no variable (null) provided
Assert.Equal("https://localhost:8080/v2", c.GetServerUrl(1, null));
// no variable (empty dictionary) provided
Assert.Equal("https://localhost:8080/v2", c.GetServerUrl(1, new Dictionary<string, string>()));
Assert.Equal("https://localhost:8080/v1", c.GetServerUrl(1, new Dictionary<string, string>() { { "version", "v1" } }));
Assert.Throws<InvalidOperationException>(() => c.GetServerUrl(1, new Dictionary<string, string>() { { "version", "v3" } }));
// test the first server (index 0)
Assert.Equal("http://petstore.swagger.io:80/v2", c.GetServerUrl(0));
}
}
}

View File

@ -55,7 +55,6 @@ namespace Org.OpenAPITools.Client
string.Format("Error calling {0}: {1}", methodName, response.RawContent),
response.RawContent, response.Headers);
}
return null;
};
@ -85,6 +84,12 @@ namespace Org.OpenAPITools.Client
private string _dateTimeFormat = ISO8601_DATETIME_FORMAT;
private string _tempFolderPath = Path.GetTempPath();
/// <summary>
/// Gets or sets the servers defined in the OpenAPI spec.
/// </summary>
/// <value>The servers</value>
private IList<IReadOnlyDictionary<string, object>> _servers;
/// <summary>
/// HTTPSigning configuration
/// </summary>
@ -104,6 +109,66 @@ namespace Org.OpenAPITools.Client
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
ApiKeyPrefix = new ConcurrentDictionary<string, string>();
Servers = new List<IReadOnlyDictionary<string, object>>()
{
{
new Dictionary<string, object> {
{"url", "http://{server}.swagger.io:{port}/v2"},
{"description", "petstore server"},
{
"variables", new Dictionary<string, object> {
{
"server", new Dictionary<string, object> {
{"description", "No description provided"},
{"default_value", "petstore"},
{
"enum_values", new List<string>() {
"petstore",
"qa-petstore",
"dev-petstore"
}
}
}
},
{
"port", new Dictionary<string, object> {
{"description", "No description provided"},
{"default_value", "80"},
{
"enum_values", new List<string>() {
"80",
"8080"
}
}
}
}
}
}
}
},
{
new Dictionary<string, object> {
{"url", "https://localhost:8080/{version}"},
{"description", "The local server"},
{
"variables", new Dictionary<string, object> {
{
"version", new Dictionary<string, object> {
{"description", "No description provided"},
{"default_value", "v2"},
{
"enum_values", new List<string>() {
"v1",
"v2"
}
}
}
}
}
}
}
}
};
// Setting Timeout has side effects (forces ApiClient creation).
Timeout = 100000;
@ -340,6 +405,82 @@ namespace Org.OpenAPITools.Client
}
}
/// <summary>
/// Gets or sets the servers.
/// </summary>
/// <value>The servers.</value>
public virtual IList<IReadOnlyDictionary<string, object>> Servers
{
get { return _servers; }
set
{
if (value == null)
{
throw new InvalidOperationException("Servers may not be null.");
}
_servers = value;
}
}
/// <summary>
/// Returns URL based on server settings without providing values
/// for the variables
/// </summary>
/// <param name="index">Array index of the server settings.</param>
/// <return>The server URL.</return>
public string GetServerUrl(int index)
{
return GetServerUrl(index, null);
}
/// <summary>
/// Returns URL based on server settings.
/// </summary>
/// <param name="index">Array index of the server settings.</param>
/// <param name="inputVariables">Dictionary of the variables and the corresponding values.</param>
/// <return>The server URL.</return>
public string GetServerUrl(int index, Dictionary<string, string> 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<string, string>();
}
IReadOnlyDictionary<string, object> server = Servers[index];
string url = (string)server["url"];
// go through variable and assign a value
foreach (KeyValuePair<string, object> variable in (IReadOnlyDictionary<string, object>)server["variables"])
{
IReadOnlyDictionary<string, object> serverVariables = (IReadOnlyDictionary<string, object>)(variable.Value);
if (inputVariables.ContainsKey(variable.Key))
{
if (((List<string>)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<string>)serverVariables["enum_values"]}");
}
}
else
{
// use defualt value
url = url.Replace("{" + variable.Key + "}", (string)serverVariables["default_value"]);
}
}
return url;
}
/// <summary>
/// Gets and Sets the HTTPSigningConfiuration
/// </summary>

View File

@ -89,6 +89,12 @@ namespace Org.OpenAPITools.Client
private string _dateTimeFormat = ISO8601_DATETIME_FORMAT;
private string _tempFolderPath = Path.GetTempPath();
/// <summary>
/// Gets or sets the servers defined in the OpenAPI spec.
/// </summary>
/// <value>The servers</value>
private IList<IReadOnlyDictionary<string, object>> _servers;
/// <summary>
/// HTTPSigning configuration
/// </summary>
@ -108,6 +114,66 @@ namespace Org.OpenAPITools.Client
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
ApiKeyPrefix = new ConcurrentDictionary<string, string>();
Servers = new List<IReadOnlyDictionary<string, object>>()
{
{
new Dictionary<string, object> {
{"url", "http://{server}.swagger.io:{port}/v2"},
{"description", "petstore server"},
{
"variables", new Dictionary<string, object> {
{
"server", new Dictionary<string, object> {
{"description", "No description provided"},
{"default_value", "petstore"},
{
"enum_values", new List<string>() {
"petstore",
"qa-petstore",
"dev-petstore"
}
}
}
},
{
"port", new Dictionary<string, object> {
{"description", "No description provided"},
{"default_value", "80"},
{
"enum_values", new List<string>() {
"80",
"8080"
}
}
}
}
}
}
}
},
{
new Dictionary<string, object> {
{"url", "https://localhost:8080/{version}"},
{"description", "The local server"},
{
"variables", new Dictionary<string, object> {
{
"version", new Dictionary<string, object> {
{"description", "No description provided"},
{"default_value", "v2"},
{
"enum_values", new List<string>() {
"v1",
"v2"
}
}
}
}
}
}
}
}
};
// Setting Timeout has side effects (forces ApiClient creation).
Timeout = 100000;
@ -344,6 +410,82 @@ namespace Org.OpenAPITools.Client
}
}
/// <summary>
/// Gets or sets the servers.
/// </summary>
/// <value>The servers.</value>
public virtual IList<IReadOnlyDictionary<string, object>> Servers
{
get { return _servers; }
set
{
if (value == null)
{
throw new InvalidOperationException("Servers may not be null.");
}
_servers = value;
}
}
/// <summary>
/// Returns URL based on server settings without providing values
/// for the variables
/// </summary>
/// <param name="index">Array index of the server settings.</param>
/// <return>The server URL.</return>
public string GetServerUrl(int index)
{
return GetServerUrl(index, null);
}
/// <summary>
/// Returns URL based on server settings.
/// </summary>
/// <param name="index">Array index of the server settings.</param>
/// <param name="inputVariables">Dictionary of the variables and the corresponding values.</param>
/// <return>The server URL.</return>
public string GetServerUrl(int index, Dictionary<string, string> 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<string, string>();
}
IReadOnlyDictionary<string, object> server = Servers[index];
string url = (string)server["url"];
// go through variable and assign a value
foreach (KeyValuePair<string, object> variable in (IReadOnlyDictionary<string, object>)server["variables"])
{
IReadOnlyDictionary<string, object> serverVariables = (IReadOnlyDictionary<string, object>)(variable.Value);
if (inputVariables.ContainsKey(variable.Key))
{
if (((List<string>)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<string>)serverVariables["enum_values"]}");
}
}
else
{
// use defualt value
url = url.Replace("{" + variable.Key + "}", (string)serverVariables["default_value"]);
}
}
return url;
}
/// <summary>
/// Gets and Sets the HTTPSigningConfiuration
/// </summary>