Skip to content

Commit 832e86a

Browse files
authored
feat(csharp): add performances playground (#2644)
1 parent ec644ff commit 832e86a

File tree

21 files changed

+649
-247
lines changed

21 files changed

+649
-247
lines changed

clients/algoliasearch-client-csharp/algoliasearch/Models/AbstractSchema.cs

Lines changed: 0 additions & 70 deletions
This file was deleted.
Lines changed: 20 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,30 @@
11
using System;
2-
using Newtonsoft.Json;
3-
using Newtonsoft.Json.Serialization;
42

5-
namespace Algolia.Search.Models.Common;
6-
7-
/// <summary>
8-
/// Abstract base class for oneOf, anyOf schemas in the API specification
9-
/// </summary>
10-
public abstract class AbstractSchema
3+
namespace Algolia.Search.Models.Common
114
{
125
/// <summary>
13-
/// Custom JSON serializer
6+
/// Abstract base class for oneOf, anyOf schemas in the OpenAPI specification
147
/// </summary>
15-
public static readonly JsonSerializerSettings SerializerSettings = new()
8+
public abstract partial class AbstractSchema
169
{
17-
// OpenAPI generated types generally hide default constructors.
18-
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
19-
MissingMemberHandling = MissingMemberHandling.Error,
20-
ContractResolver = new DefaultContractResolver
21-
{
22-
NamingStrategy = new CamelCaseNamingStrategy
23-
{
24-
OverrideSpecifiedNames = false
25-
}
26-
}
27-
};
28-
29-
/// <summary>
30-
/// Custom JSON serializer for objects with additional properties
31-
/// </summary>
32-
public static readonly JsonSerializerSettings AdditionalPropertiesSerializerSettings = new JsonSerializerSettings
33-
{
34-
// OpenAPI generated types generally hide default constructors.
35-
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
36-
MissingMemberHandling = MissingMemberHandling.Ignore,
37-
ContractResolver = new DefaultContractResolver
38-
{
39-
NamingStrategy = new CamelCaseNamingStrategy
40-
{
41-
OverrideSpecifiedNames = false
42-
}
43-
}
44-
};
45-
46-
/// <summary>
47-
/// Gets or Sets the actual instance
48-
/// </summary>
49-
public abstract object ActualInstance { get; set; }
10+
/// <summary>
11+
/// Gets or Sets the actual instance
12+
/// </summary>
13+
public abstract Object ActualInstance { get; set; }
5014

51-
/// <summary>
52-
/// Gets or Sets IsNullable to indicate whether the instance is nullable
53-
/// </summary>
54-
public bool IsNullable { get; protected set; }
15+
/// <summary>
16+
/// Gets or Sets IsNullable to indicate whether the instance is nullable
17+
/// </summary>
18+
public bool IsNullable { get; protected set; }
5519

56-
/// <summary>
57-
/// Gets or Sets the schema type, which can be either `oneOf` or `anyOf`
58-
/// </summary>
59-
public string SchemaType { get; protected set; }
20+
/// <summary>
21+
/// Gets or Sets the schema type, which can be either `oneOf` or `anyOf`
22+
/// </summary>
23+
public string SchemaType { get; protected set; }
6024

61-
/// <summary>
62-
/// Converts the instance into JSON string.
63-
/// </summary>
64-
public abstract string ToJson();
25+
/// <summary>
26+
/// Converts the instance into JSON string.
27+
/// </summary>
28+
public abstract string ToJson();
29+
}
6530
}

clients/algoliasearch-client-csharp/algoliasearch/Serializer/DefaultSerializer.cs

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.IO;
3-
using System.Text;
43
using System.Threading.Tasks;
54
using Algolia.Search.Exceptions;
65
using Algolia.Search.Models.Common;
@@ -11,29 +10,28 @@ namespace Algolia.Search.Serializer;
1110

1211
internal class DefaultJsonSerializer : ISerializer
1312
{
14-
private readonly JsonSerializerSettings _serializerSettings;
1513
private readonly ILogger<DefaultJsonSerializer> _logger;
1614

17-
public DefaultJsonSerializer(JsonSerializerSettings serializerSettings, ILoggerFactory logger)
15+
public DefaultJsonSerializer(ILoggerFactory logger)
1816
{
19-
_serializerSettings = serializerSettings;
2017
_logger = logger.CreateLogger<DefaultJsonSerializer>();
2118
}
2219

2320
/// <summary>
2421
/// Serialize the object into a JSON string.
2522
/// </summary>
26-
/// <param name="obj">Object to be serialized.</param>
23+
/// <param name="data">Object to be serialized.</param>
2724
/// <returns>A JSON string.</returns>
28-
public string Serialize(object obj)
25+
public string Serialize(object data)
2926
{
30-
if (obj is AbstractSchema schema)
27+
if (data is AbstractSchema schema)
3128
{
3229
// the object to be serialized is an oneOf/anyOf schema
33-
return schema.ToJson();
30+
var serialize = schema.ToJson();
31+
return serialize;
3432
}
3533

36-
return JsonConvert.SerializeObject(obj, _serializerSettings);
34+
return JsonConvert.SerializeObject(data, JsonConfig.AlgoliaJsonSerializerSettings);
3735
}
3836

3937
public async Task<T> Deserialize<T>(Stream response)
@@ -50,37 +48,12 @@ public async Task<T> Deserialize<T>(Stream response)
5048
/// <returns>Object representation of the JSON string.</returns>
5149
private async Task<object> Deserialize(Stream response, Type type)
5250
{
53-
if (type == typeof(byte[])) // return a byte array
54-
{
55-
using var reader = new StreamReader(response);
56-
return Encoding.UTF8.GetBytes(await reader.ReadToEndAsync().ConfigureAwait(false));
57-
}
58-
59-
if (type == typeof(Stream))
60-
{
61-
return response;
62-
}
63-
64-
if (type.Name.StartsWith("System.Nullable`1[[System.DateTime")) // return a datetime object
65-
{
66-
using var reader = new StreamReader(response);
67-
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
68-
return DateTime.Parse(text, null, System.Globalization.DateTimeStyles.RoundtripKind);
69-
}
70-
71-
if (type == typeof(string) || type.Name.StartsWith("System.Nullable")) // return primitive type
72-
{
73-
using var reader = new StreamReader(response);
74-
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
75-
return Convert.ChangeType(text, type);
76-
}
77-
78-
// Json Model
7951
try
8052
{
8153
using var reader = new StreamReader(response);
82-
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
83-
return JsonConvert.DeserializeObject(text, type, _serializerSettings);
54+
var readToEndAsync = await reader.ReadToEndAsync().ConfigureAwait(false);
55+
return JsonConvert.DeserializeObject(readToEndAsync, type,
56+
JsonConfig.AlgoliaJsonSerializerSettings);
8457
}
8558
catch (Exception ex)
8659
{

clients/algoliasearch-client-csharp/algoliasearch/Serializer/JsonConfig.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,29 @@ internal static class JsonConfig
1010
{
1111
public const string JsonContentType = "application/json";
1212

13-
public static JsonSerializerSettings AlgoliaJsonSerializerSettings => new()
13+
private static readonly DefaultContractResolver Resolver = new() { NamingStrategy = new CamelCaseNamingStrategy() };
14+
15+
public static readonly JsonSerializerSettings AlgoliaJsonSerializerSettings = new()
1416
{
1517
Formatting = Formatting.None,
1618
NullValueHandling = NullValueHandling.Ignore,
17-
ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() },
19+
ContractResolver = Resolver,
1820
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
1921
DateParseHandling = DateParseHandling.DateTime,
2022
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
2123
MissingMemberHandling = MissingMemberHandling.Ignore,
2224
};
25+
26+
// When DeserializeOneOfSettings is used, we set MissingMemberHandling to Error to throw an exception if a property is missing
27+
public static readonly JsonSerializerSettings DeserializeOneOfSettings = new()
28+
{
29+
Formatting = Formatting.None,
30+
NullValueHandling = NullValueHandling.Ignore,
31+
ContractResolver = Resolver,
32+
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
33+
DateParseHandling = DateParseHandling.DateTime,
34+
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
35+
MissingMemberHandling = MissingMemberHandling.Error,
36+
};
2337
}
2438
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
3+
namespace Algolia.Search.Transport;
4+
5+
/// <summary>
6+
/// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types
7+
/// Binary enums beware when adding new values
8+
/// </summary>
9+
[Flags]
10+
public enum CallType
11+
{
12+
/// <summary>
13+
/// Read Call
14+
/// </summary>
15+
Read = 1,
16+
17+
/// <summary>
18+
/// Write Call
19+
/// </summary>
20+
Write = 2
21+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace Algolia.Search.Transport;
2+
3+
/// <summary>
4+
/// Http Scheme
5+
/// </summary>
6+
public enum HttpScheme
7+
{
8+
/// <summary>
9+
/// Http
10+
/// </summary>
11+
Http,
12+
/// <summary>
13+
/// Https
14+
/// </summary>
15+
Https
16+
}

clients/algoliasearch-client-csharp/algoliasearch/Transport/HttpTransport.cs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public HttpTransport(AlgoliaConfig config, IHttpRequester httpClient, ILoggerFac
4343
_algoliaConfig = config ?? throw new ArgumentNullException(nameof(config));
4444
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
4545
_retryStrategy = new RetryStrategy(config);
46-
_serializer = new DefaultJsonSerializer(JsonConfig.AlgoliaJsonSerializerSettings, loggerFactory);
46+
_serializer = new DefaultJsonSerializer(loggerFactory);
4747
_logger = loggerFactory.CreateLogger<HttpTransport>();
4848
}
4949

@@ -116,7 +116,7 @@ private async Task<TResult> ExecuteRequestAsync<TResult, TData>(HttpMethod metho
116116
foreach (var host in _retryStrategy.GetTryableHost(callType))
117117
{
118118
request.Body = CreateRequestContent(requestOptions?.Data, request.CanCompress, _logger);
119-
request.Uri = BuildUri(host.Url, uri, requestOptions?.CustomPathParameters, requestOptions?.PathParameters,
119+
request.Uri = BuildUri(host, uri, requestOptions?.CustomPathParameters, requestOptions?.PathParameters,
120120
requestOptions?.QueryParameters);
121121
var requestTimeout =
122122
TimeSpan.FromTicks((requestOptions?.Timeout ?? GetTimeOut(callType)).Ticks * (host.RetryCount + 1));
@@ -228,13 +228,14 @@ private IDictionary<string, string> GenerateHeaders(IDictionary<string, string>
228228
/// <summary>
229229
/// Build uri depending on the method
230230
/// </summary>
231-
/// <param name="url"></param>
231+
/// <param name="host"></param>
232232
/// <param name="baseUri"></param>
233233
/// <param name="customPathParameters"></param>
234234
/// <param name="pathParameters"></param>
235235
/// <param name="optionalQueryParameters"></param>
236236
/// <returns></returns>
237-
private static Uri BuildUri(string url, string baseUri, IDictionary<string, string> customPathParameters = null,
237+
private static Uri BuildUri(StatefulHost host, string baseUri,
238+
IDictionary<string, string> customPathParameters = null,
238239
IDictionary<string, string> pathParameters = null,
239240
IDictionary<string, string> optionalQueryParameters = null)
240241
{
@@ -255,13 +256,19 @@ private static Uri BuildUri(string url, string baseUri, IDictionary<string, stri
255256
}
256257
}
257258

258-
if (optionalQueryParameters != null)
259+
var builder = new UriBuilder { Scheme = host.Scheme.ToString(), Host = host.Url, Path = path };
260+
261+
if (optionalQueryParameters != null && optionalQueryParameters.Any())
262+
{
263+
builder.Query = optionalQueryParameters.ToQueryString();
264+
}
265+
266+
if (host.Port.HasValue)
259267
{
260-
var queryParams = optionalQueryParameters.ToQueryString();
261-
return new UriBuilder { Scheme = "https", Host = url, Path = path, Query = queryParams }.Uri;
268+
builder.Port = host.Port.Value;
262269
}
263270

264-
return new UriBuilder { Scheme = "https", Host = url, Path = path }.Uri;
271+
return builder.Uri;
265272
}
266273

267274
/// <summary>

0 commit comments

Comments
 (0)