Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(csharp): add performances playground #2644

Merged
merged 19 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,65 +1,30 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace Algolia.Search.Models.Common;

/// <summary>
/// Abstract base class for oneOf, anyOf schemas in the API specification
/// </summary>
public abstract class AbstractSchema
namespace Algolia.Search.Models.Common
{
/// <summary>
/// Custom JSON serializer
/// Abstract base class for oneOf, anyOf schemas in the OpenAPI specification
/// </summary>
public static readonly JsonSerializerSettings SerializerSettings = new()
public abstract partial class AbstractSchema
{
// OpenAPI generated types generally hide default constructors.
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
MissingMemberHandling = MissingMemberHandling.Error,
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy
{
OverrideSpecifiedNames = false
}
}
};

/// <summary>
/// Custom JSON serializer for objects with additional properties
/// </summary>
public static readonly JsonSerializerSettings AdditionalPropertiesSerializerSettings = new JsonSerializerSettings
{
// OpenAPI generated types generally hide default constructors.
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
MissingMemberHandling = MissingMemberHandling.Ignore,
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy
{
OverrideSpecifiedNames = false
}
}
};

/// <summary>
/// Gets or Sets the actual instance
/// </summary>
public abstract object ActualInstance { get; set; }
/// <summary>
/// Gets or Sets the actual instance
/// </summary>
public abstract Object ActualInstance { get; set; }

/// <summary>
/// Gets or Sets IsNullable to indicate whether the instance is nullable
/// </summary>
public bool IsNullable { get; protected set; }
/// <summary>
/// Gets or Sets IsNullable to indicate whether the instance is nullable
/// </summary>
public bool IsNullable { get; protected set; }

/// <summary>
/// Gets or Sets the schema type, which can be either `oneOf` or `anyOf`
/// </summary>
public string SchemaType { get; protected set; }
/// <summary>
/// Gets or Sets the schema type, which can be either `oneOf` or `anyOf`
/// </summary>
public string SchemaType { get; protected set; }

/// <summary>
/// Converts the instance into JSON string.
/// </summary>
public abstract string ToJson();
/// <summary>
/// Converts the instance into JSON string.
/// </summary>
public abstract string ToJson();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Algolia.Search.Exceptions;
using Algolia.Search.Models.Common;
Expand All @@ -11,29 +10,28 @@ namespace Algolia.Search.Serializer;

internal class DefaultJsonSerializer : ISerializer
{
private readonly JsonSerializerSettings _serializerSettings;
private readonly ILogger<DefaultJsonSerializer> _logger;

public DefaultJsonSerializer(JsonSerializerSettings serializerSettings, ILoggerFactory logger)
public DefaultJsonSerializer(ILoggerFactory logger)
{
_serializerSettings = serializerSettings;
_logger = logger.CreateLogger<DefaultJsonSerializer>();
}

/// <summary>
/// Serialize the object into a JSON string.
/// </summary>
/// <param name="obj">Object to be serialized.</param>
/// <param name="data">Object to be serialized.</param>
/// <returns>A JSON string.</returns>
public string Serialize(object obj)
public string Serialize(object data)
{
if (obj is AbstractSchema schema)
if (data is AbstractSchema schema)
{
// the object to be serialized is an oneOf/anyOf schema
return schema.ToJson();
var serialize = schema.ToJson();
return serialize;
}

return JsonConvert.SerializeObject(obj, _serializerSettings);
return JsonConvert.SerializeObject(data, JsonConfig.AlgoliaJsonSerializerSettings);
}

public async Task<T> Deserialize<T>(Stream response)
Expand All @@ -50,37 +48,12 @@ public async Task<T> Deserialize<T>(Stream response)
/// <returns>Object representation of the JSON string.</returns>
private async Task<object> Deserialize(Stream response, Type type)
{
if (type == typeof(byte[])) // return a byte array
{
using var reader = new StreamReader(response);
return Encoding.UTF8.GetBytes(await reader.ReadToEndAsync().ConfigureAwait(false));
}

if (type == typeof(Stream))
{
return response;
}

if (type.Name.StartsWith("System.Nullable`1[[System.DateTime")) // return a datetime object
{
using var reader = new StreamReader(response);
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
return DateTime.Parse(text, null, System.Globalization.DateTimeStyles.RoundtripKind);
}

if (type == typeof(string) || type.Name.StartsWith("System.Nullable")) // return primitive type
{
using var reader = new StreamReader(response);
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
return Convert.ChangeType(text, type);
}

// Json Model
try
{
using var reader = new StreamReader(response);
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject(text, type, _serializerSettings);
var readToEndAsync = await reader.ReadToEndAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject(readToEndAsync, type,
JsonConfig.AlgoliaJsonSerializerSettings);
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,29 @@ internal static class JsonConfig
{
public const string JsonContentType = "application/json";

public static JsonSerializerSettings AlgoliaJsonSerializerSettings => new()
private static readonly DefaultContractResolver Resolver = new() { NamingStrategy = new CamelCaseNamingStrategy() };

public static readonly JsonSerializerSettings AlgoliaJsonSerializerSettings = new()
{
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() },
ContractResolver = Resolver,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DateParseHandling = DateParseHandling.DateTime,
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
MissingMemberHandling = MissingMemberHandling.Ignore,
};

// When DeserializeOneOfSettings is used, we set MissingMemberHandling to Error to throw an exception if a property is missing
public static readonly JsonSerializerSettings DeserializeOneOfSettings = new()
{
Formatting = Formatting.None,
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = Resolver,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DateParseHandling = DateParseHandling.DateTime,
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
MissingMemberHandling = MissingMemberHandling.Error,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;

namespace Algolia.Search.Transport;

/// <summary>
/// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types
/// Binary enums beware when adding new values
/// </summary>
[Flags]
public enum CallType
{
/// <summary>
/// Read Call
/// </summary>
Read = 1,

/// <summary>
/// Write Call
/// </summary>
Write = 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Algolia.Search.Transport;

/// <summary>
/// Http Scheme
/// </summary>
public enum HttpScheme
{
/// <summary>
/// Http
/// </summary>
Http,
/// <summary>
/// Https
/// </summary>
Https
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public HttpTransport(AlgoliaConfig config, IHttpRequester httpClient, ILoggerFac
_algoliaConfig = config ?? throw new ArgumentNullException(nameof(config));
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_retryStrategy = new RetryStrategy(config);
_serializer = new DefaultJsonSerializer(JsonConfig.AlgoliaJsonSerializerSettings, loggerFactory);
_serializer = new DefaultJsonSerializer(loggerFactory);
_logger = loggerFactory.CreateLogger<HttpTransport>();
}

Expand Down Expand Up @@ -116,7 +116,7 @@ private async Task<TResult> ExecuteRequestAsync<TResult, TData>(HttpMethod metho
foreach (var host in _retryStrategy.GetTryableHost(callType))
{
request.Body = CreateRequestContent(requestOptions?.Data, request.CanCompress, _logger);
request.Uri = BuildUri(host.Url, uri, requestOptions?.CustomPathParameters, requestOptions?.PathParameters,
request.Uri = BuildUri(host, uri, requestOptions?.CustomPathParameters, requestOptions?.PathParameters,
requestOptions?.QueryParameters);
var requestTimeout =
TimeSpan.FromTicks((requestOptions?.Timeout ?? GetTimeOut(callType)).Ticks * (host.RetryCount + 1));
Expand Down Expand Up @@ -228,13 +228,14 @@ private IDictionary<string, string> GenerateHeaders(IDictionary<string, string>
/// <summary>
/// Build uri depending on the method
/// </summary>
/// <param name="url"></param>
/// <param name="host"></param>
/// <param name="baseUri"></param>
/// <param name="customPathParameters"></param>
/// <param name="pathParameters"></param>
/// <param name="optionalQueryParameters"></param>
/// <returns></returns>
private static Uri BuildUri(string url, string baseUri, IDictionary<string, string> customPathParameters = null,
private static Uri BuildUri(StatefulHost host, string baseUri,
IDictionary<string, string> customPathParameters = null,
IDictionary<string, string> pathParameters = null,
IDictionary<string, string> optionalQueryParameters = null)
{
Expand All @@ -258,10 +259,11 @@ private static Uri BuildUri(string url, string baseUri, IDictionary<string, stri
if (optionalQueryParameters != null)
{
var queryParams = optionalQueryParameters.ToQueryString();
return new UriBuilder { Scheme = "https", Host = url, Path = path, Query = queryParams }.Uri;
return new UriBuilder
{ Scheme = host.Scheme.ToString(), Host = host.Url, Port = host.Port, Path = path, Query = queryParams }.Uri;
}

return new UriBuilder { Scheme = "https", Host = url, Path = path }.Uri;
return new UriBuilder { Scheme = host.Scheme.ToString(), Host = host.Url, Port = host.Port, Path = path }.Uri;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the port always defined ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it's -1 maybe it shouldn't be passed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Done

}

/// <summary>
Expand Down
Loading
Loading