diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Clients/AlgoliaConfig.cs b/clients/algoliasearch-client-csharp/algoliasearch/Clients/AlgoliaConfig.cs
index 5740c3504d..7a9a0854c4 100644
--- a/clients/algoliasearch-client-csharp/algoliasearch/Clients/AlgoliaConfig.cs
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Clients/AlgoliaConfig.cs
@@ -16,21 +16,25 @@ public abstract class AlgoliaConfig
private static readonly string ClientVersion =
typeof(AlgoliaConfig).GetTypeInfo().Assembly.GetName().Version.ToString();
+ // get the dotnet runtime version
+ private static readonly string DotnetVersion = Environment.Version.ToString();
+
///
/// Create a new Algolia's configuration for the given credentials
///
- /// Your application ID
+ /// Your application ID
/// Your API Key
- protected AlgoliaConfig(string applicationId, string apiKey)
+ /// The client name
+ protected AlgoliaConfig(string appId, string apiKey, string client)
{
- AppId = applicationId;
+ AppId = appId;
ApiKey = apiKey;
DefaultHeaders = new Dictionary
{
{ Defaults.AlgoliaApplicationHeader.ToLowerInvariant(), AppId },
{ Defaults.AlgoliaApiKeyHeader.ToLowerInvariant(), ApiKey },
- { Defaults.UserAgentHeader.ToLowerInvariant(), $"Algolia For Csharp {ClientVersion}" },
+ { Defaults.UserAgentHeader.ToLowerInvariant(), $"Algolia for Csharp ({ClientVersion}); {client} ({ClientVersion}); Dotnet ({DotnetVersion})" },
{ Defaults.Connection.ToLowerInvariant(), Defaults.KeepAlive },
{ Defaults.AcceptHeader.ToLowerInvariant(), JsonConfig.JsonContentType }
};
@@ -69,6 +73,11 @@ protected AlgoliaConfig(string applicationId, string apiKey)
///
public TimeSpan? WriteTimeout { get; set; }
+ ///
+ /// Set the connect timeout for all requests
+ ///
+ public TimeSpan? ConnectTimeout { get; set; }
+
///
/// Compression for outgoing http requests
///
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Http/AlgoliaHttpRequester.cs b/clients/algoliasearch-client-csharp/algoliasearch/Http/AlgoliaHttpRequester.cs
index c3ceea4457..4d8d28b7b2 100644
--- a/clients/algoliasearch-client-csharp/algoliasearch/Http/AlgoliaHttpRequester.cs
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Http/AlgoliaHttpRequester.cs
@@ -27,11 +27,12 @@ internal class AlgoliaHttpRequester : IHttpRequester
/// Send request to the REST API
///
/// Request
- /// Timeout
+ /// Request timeout
+ /// Connect timeout
/// Optional cancellation token
///
- public async Task SendRequestAsync(Request request, TimeSpan totalTimeout,
- CancellationToken ct = default)
+ public async Task SendRequestAsync(Request request, TimeSpan requestTimeout, TimeSpan connectTimeout,
+ CancellationToken ct = default)
{
if (request.Method == null)
{
@@ -57,7 +58,7 @@ public async Task SendRequestAsync(Request request, TimeSpa
}
httpRequestMessage.Headers.Fill(request.Headers);
- httpRequestMessage.SetTimeout(totalTimeout);
+ httpRequestMessage.SetTimeout(requestTimeout + connectTimeout);
try
{
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Http/EchoHttpRequester.cs b/clients/algoliasearch-client-csharp/algoliasearch/Http/EchoHttpRequester.cs
index 202c0b6b61..b98ef192b3 100644
--- a/clients/algoliasearch-client-csharp/algoliasearch/Http/EchoHttpRequester.cs
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Http/EchoHttpRequester.cs
@@ -21,16 +21,21 @@ private static Dictionary SplitQuery(string query)
return collection.AllKeys.ToDictionary(key => key, key => collection[key]);
}
- public async Task SendRequestAsync(Request request, TimeSpan totalTimeout,
+ public async Task SendRequestAsync(Request request, TimeSpan requestTimeout,
+ TimeSpan connectTimeout,
CancellationToken ct = default)
{
- EchoResponse echo = new EchoResponse();
- echo.Path = request.Uri.AbsolutePath;
- echo.Host = request.Uri.Host;
- echo.Method = request.Method;
- echo.Body = request.Body;
- echo.QueryParameters = SplitQuery(request.Uri.Query);
- echo.Headers = new Dictionary(request.Headers);
+ EchoResponse echo = new EchoResponse
+ {
+ Path = request.Uri.AbsolutePath,
+ Host = request.Uri.Host,
+ Method = request.Method,
+ Body = request.Body,
+ QueryParameters = SplitQuery(request.Uri.Query),
+ Headers = new Dictionary(request.Headers),
+ ConnectTimeout = connectTimeout,
+ ResponseTimeout = requestTimeout
+ };
LastResponse = echo;
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Http/EchoResponse.cs b/clients/algoliasearch-client-csharp/algoliasearch/Http/EchoResponse.cs
index df8160ea49..505c4af990 100644
--- a/clients/algoliasearch-client-csharp/algoliasearch/Http/EchoResponse.cs
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Http/EchoResponse.cs
@@ -13,7 +13,7 @@ public class EchoResponse
public String Body;
public Dictionary QueryParameters;
public Dictionary Headers;
- public int ConnectTimeout;
- public int ResponseTimeout;
+ public TimeSpan ConnectTimeout;
+ public TimeSpan ResponseTimeout;
}
}
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Http/IHttpRequester.cs b/clients/algoliasearch-client-csharp/algoliasearch/Http/IHttpRequester.cs
index ac0d8bca7e..5aaa1d8307 100644
--- a/clients/algoliasearch-client-csharp/algoliasearch/Http/IHttpRequester.cs
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Http/IHttpRequester.cs
@@ -14,10 +14,10 @@ public interface IHttpRequester
/// Sends the HTTP request
///
/// Request object
- /// Timeout
+ /// Request timeout
+ /// Connect timeout
/// Optional cancellation token
///
- Task SendRequestAsync(Request request, TimeSpan totalTimeout,
- CancellationToken ct = default);
+ Task SendRequestAsync(Request request, TimeSpan requestTimeout, TimeSpan connectTimeout, CancellationToken ct = default);
}
}
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Transport/HttpTransport.cs b/clients/algoliasearch-client-csharp/algoliasearch/Transport/HttpTransport.cs
index 60ef846c14..aec1978ebd 100644
--- a/clients/algoliasearch-client-csharp/algoliasearch/Transport/HttpTransport.cs
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Transport/HttpTransport.cs
@@ -121,7 +121,7 @@ private async Task ExecuteRequestAsync(HttpMethod metho
}
AlgoliaHttpResponse response = await _httpClient
- .SendRequestAsync(request, requestTimeout, ct)
+ .SendRequestAsync(request, requestTimeout, _algoliaConfig.ConnectTimeout ?? Defaults.ConnectTimeout, ct)
.ConfigureAwait(false);
_errorMessage = response.Error;
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Utils/Defaults.cs b/clients/algoliasearch-client-csharp/algoliasearch/Utils/Defaults.cs
index c955a58eec..247ecf6608 100644
--- a/clients/algoliasearch-client-csharp/algoliasearch/Utils/Defaults.cs
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Utils/Defaults.cs
@@ -17,6 +17,11 @@ internal class Defaults
///
public static TimeSpan WriteTimeout = TimeSpan.FromSeconds(30);
+ ///
+ /// Connect timeout
+ ///
+ public static TimeSpan ConnectTimeout = TimeSpan.FromSeconds(2);
+
public const string AcceptHeader = "Accept";
public const string AlgoliaApplicationHeader = "X-Algolia-Application-Id";
public const string AlgoliaApiKeyHeader = "X-Algolia-API-Key";
diff --git a/templates/csharp/Configuration.mustache b/templates/csharp/Configuration.mustache
index 3467783105..6b4e590872 100644
--- a/templates/csharp/Configuration.mustache
+++ b/templates/csharp/Configuration.mustache
@@ -18,10 +18,10 @@ namespace Algolia.Search.Clients
/// The configuration of the {{packageName}} client
/// A client should have it's own configuration ie on configuration per client instance
///
- /// Your application ID
+ /// Your application ID
/// Your API Key
/// Targeted region {{#fallbackToAliasHost}}(optional){{/fallbackToAliasHost}}
- public {{packageName}}Config(string applicationId, string apiKey, string region{{#fallbackToAliasHost}} = null{{/fallbackToAliasHost}}) : base(applicationId, apiKey)
+ public {{packageName}}Config(string appId, string apiKey, string region{{#fallbackToAliasHost}} = null{{/fallbackToAliasHost}}) : base(appId, apiKey, "{{packageName}}")
{
DefaultHosts = GetDefaultHosts(region);
Compression = CompressionType.NONE;
@@ -32,29 +32,29 @@ namespace Algolia.Search.Clients
/// The configuration of the {{packageName}} client
/// A client should have it's own configuration ie on configuration per client instance
///
- /// Your application ID
+ /// Your application ID
/// Your API Key
- public {{packageName}}Config(string applicationId, string apiKey) : base(applicationId, apiKey)
+ public {{packageName}}Config(string appId, string apiKey) : base(appId, apiKey, "{{packageName}}")
{
- DefaultHosts = GetDefaultHosts(applicationId);
+ DefaultHosts = GetDefaultHosts(appId);
Compression = CompressionType.NONE;
}
{{/hasRegionalHost}}
{{^hasRegionalHost}}
- private static List GetDefaultHosts(string applicationId)
+ private static List GetDefaultHosts(string appId)
{
List hosts = new List
{
new StatefulHost
{
- Url = $"{applicationId}-dsn.algolia.net",
+ Url = $"{appId}-dsn.algolia.net",
Up = true,
LastUse = DateTime.UtcNow,
Accept = CallType.Read
},
new StatefulHost
{
- Url = $"{applicationId}.algolia.net", Up = true, LastUse = DateTime.UtcNow, Accept = CallType.Write,
+ Url = $"{appId}.algolia.net", Up = true, LastUse = DateTime.UtcNow, Accept = CallType.Write,
}
};
@@ -62,21 +62,21 @@ namespace Algolia.Search.Clients
{
new StatefulHost
{
- Url = $"{applicationId}-1.algolianet.com",
+ Url = $"{appId}-1.algolianet.com",
Up = true,
LastUse = DateTime.UtcNow,
Accept = CallType.Read | CallType.Write,
},
new StatefulHost
{
- Url = $"{applicationId}-2.algolianet.com",
+ Url = $"{appId}-2.algolianet.com",
Up = true,
LastUse = DateTime.UtcNow,
Accept = CallType.Read | CallType.Write,
},
new StatefulHost
{
- Url = $"{applicationId}-3.algolianet.com",
+ Url = $"{appId}-3.algolianet.com",
Up = true,
LastUse = DateTime.UtcNow,
Accept = CallType.Read | CallType.Write,
@@ -91,10 +91,18 @@ namespace Algolia.Search.Clients
private static List GetDefaultHosts(string region)
{
var regions = new List { {{#allowedRegions}}"{{.}}"{{^-last}},{{/-last}}{{/allowedRegions}} };
- if (region != null && !regions.Contains(region))
+ {{^fallbackToAliasHost}}
+ if (region == null || !regions.Contains(region))
{
- throw new ArgumentException($"`region` must be one of the following {regions}");
+ throw new ArgumentException($"`region` is required and must be one of the following: {string.Join(", ", regions)}");
}
+ {{/fallbackToAliasHost}}
+ {{#fallbackToAliasHost}}
+ if(region != null && !regions.Contains(region))
+ {
+ throw new ArgumentException($"`region` must be one of the following: {string.Join(", ", regions)}");
+ }
+ {{/fallbackToAliasHost}}
var selectedRegion = {{#fallbackToAliasHost}}region == null ? "{{{hostWithFallback}}}" : {{/fallbackToAliasHost}} "{{{regionalHost}}}".Replace("{region}", region);
diff --git a/templates/csharp/libraries/httpclient/api.mustache b/templates/csharp/libraries/httpclient/api.mustache
index 8457d2ab99..4a06b26f1e 100644
--- a/templates/csharp/libraries/httpclient/api.mustache
+++ b/templates/csharp/libraries/httpclient/api.mustache
@@ -79,19 +79,19 @@ namespace Algolia.Search.Clients
{
if (httpRequester == null)
{
- throw new ArgumentNullException(nameof(httpRequester), "An httpRequester is required");
+ throw new ArgumentException("An httpRequester is required");
}
if (config == null)
{
- throw new ArgumentNullException(nameof(config), "A config is required");
+ throw new ArgumentException("A config is required");
}
if (string.IsNullOrWhiteSpace(config.AppId))
{
- throw new ArgumentNullException(nameof(config.AppId), "Application ID is required");
+ throw new ArgumentException("`AppId` is missing.");
}
if (string.IsNullOrWhiteSpace(config.ApiKey))
{
- throw new ArgumentNullException(nameof(config.ApiKey), "An API key is required");
+ throw new ArgumentException("`ApiKey` is missing.");
}
_config = config;
@@ -120,8 +120,7 @@ namespace Algolia.Search.Clients
{{#required}}
{{^vendorExtensions.x-csharp-value-type}}
if ({{paramName}} == null)
- throw new ApiException(400, "Missing required parameter '{{paramName}}' when calling {{classname}}->{{operationId}}");
-
+ throw new ApiException(400, "Parameter `{{paramName}}` is required when calling `{{operationId}}`.");
{{/vendorExtensions.x-csharp-value-type}}
{{/required}}
{{/allParams}}
diff --git a/templates/csharp/tests/client/createClient.mustache b/templates/csharp/tests/client/createClient.mustache
new file mode 100644
index 0000000000..f4037ac6cd
--- /dev/null
+++ b/templates/csharp/tests/client/createClient.mustache
@@ -0,0 +1 @@
+{{^autoCreateClient}}var client = {{/autoCreateClient}}new {{client}}(new {{clientPrefix}}Config("{{parametersWithDataTypeMap.appId.value}}","{{parametersWithDataTypeMap.apiKey.value}}"{{#hasRegionalHost}}{{#parametersWithDataTypeMap.region}},"{{parametersWithDataTypeMap.region.value}}"{{/parametersWithDataTypeMap.region}}{{/hasRegionalHost}}), _echo);
diff --git a/templates/csharp/tests/client/method.mustache b/templates/csharp/tests/client/method.mustache
new file mode 100644
index 0000000000..067eda92d3
--- /dev/null
+++ b/templates/csharp/tests/client/method.mustache
@@ -0,0 +1,9 @@
+await client.{{#lambda.pascalcase}}{{#path}}.{{.}}{{/path}}{{/lambda.pascalcase}}Async{{#isGeneric}}