Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,34 @@ on:
- "*.*.*"

jobs:
aot-validate:
runs-on: ${{ matrix.os.runner }}
strategy:
fail-fast: false
matrix:
os:
- runner: ubuntu-latest
folder: linux-x64
binary: transport-aot-example
- runner: macos-latest
folder: osx-arm64
binary: transport-aot-example
- runner: windows-latest
folder: win-x64
binary: transport-aot-example.exe
steps:
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4
with:
global-json-file: ./global.json

- name: Publish AOT
run: dotnet publish examples/transport-aot-example

- name: Invoke AOT
run: ./examples/transport-aot-example/bin/Release/net8.0/${{ matrix.os.folder }}/${{ matrix.os.binary }}

build:
runs-on: ubuntu-latest
steps:
Expand Down
9 changes: 9 additions & 0 deletions Elastic.Transport.sln
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elastic.Elasticsearch.Integ
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.Transport.Tests.Shared", "tests\Elastic.Transport.Tests.Shared\Elastic.Transport.Tests.Shared.csproj", "{13A2597D-F50C-4D7F-ADA9-716991C8E9DE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{54C8CB5B-11E4-48CB-8055-D8ACE8EFF0AB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "transport-aot-example", "examples\transport-aot-example\transport-aot-example.csproj", "{29D5F68D-BABF-4738-9A9E-F2FE2DFFBEA8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -92,6 +96,10 @@ Global
{13A2597D-F50C-4D7F-ADA9-716991C8E9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13A2597D-F50C-4D7F-ADA9-716991C8E9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13A2597D-F50C-4D7F-ADA9-716991C8E9DE}.Release|Any CPU.Build.0 = Release|Any CPU
{29D5F68D-BABF-4738-9A9E-F2FE2DFFBEA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29D5F68D-BABF-4738-9A9E-F2FE2DFFBEA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29D5F68D-BABF-4738-9A9E-F2FE2DFFBEA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29D5F68D-BABF-4738-9A9E-F2FE2DFFBEA8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -107,6 +115,7 @@ Global
{5EE4DC72-B337-448B-802A-6158F4D90667} = {7610B796-BB3E-4CB2-8296-79BBFF6D23FC}
{317C118F-FA1E-499A-B7F2-DC932DE66CB8} = {3582B07D-C2B0-49CC-B676-EAF806EB010E}
{13A2597D-F50C-4D7F-ADA9-716991C8E9DE} = {3582B07D-C2B0-49CC-B676-EAF806EB010E}
{29D5F68D-BABF-4738-9A9E-F2FE2DFFBEA8} = {54C8CB5B-11E4-48CB-8055-D8ACE8EFF0AB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7F60C4BB-6216-4E50-B1E4-9C38EB484843}
Expand Down
31 changes: 31 additions & 0 deletions examples/transport-aot-example/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Text.Json.Serialization;
using Elastic.Transport;
using Elastic.Transport.Products.Elasticsearch;

var apiKey = Environment.GetEnvironmentVariable("ELASTIC_API_KEY");
var url = Environment.GetEnvironmentVariable("ELASTIC_URL");

var configuration = apiKey is not null && url is not null
? new ElasticsearchConfiguration(new Uri(url), new ApiKey(apiKey))
: new ElasticsearchConfiguration { DebugMode = true };

var transport = new DistributedTransport(configuration);

var rootResponse = transport.Get<DynamicResponse>("/");
if (rootResponse.ApiCallDetails.HasSuccessfulStatusCode)
Console.WriteLine(rootResponse.Get<string>("tagline"));
else
Console.WriteLine(rootResponse);

public class MyDocument
{
[JsonPropertyName("message")]
public string Message { init; get; } = null!;
}

[JsonSerializable(typeof(MyDocument))]
internal partial class ExampleJsonSerializerContext : JsonSerializerContext;
17 changes: 17 additions & 0 deletions examples/transport-aot-example/transport-aot-example.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>transport_aot_example</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Elastic.Transport\Elastic.Transport.csproj"/>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
Expand Down Expand Up @@ -31,6 +32,8 @@ public override DynamicDictionary Read(ref Utf8JsonReader reader, Type typeToCon
return DynamicDictionary.Create(dict);
}

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public override void Write(Utf8JsonWriter writer, DynamicDictionary dictionary, JsonSerializerOptions options)
{
writer.WriteStartObject();
Expand All @@ -42,9 +45,7 @@ public override void Write(Utf8JsonWriter writer, DynamicDictionary dictionary,
writer.WritePropertyName(kvp.Key);

// TODO: Test! We have to make sure all possible "Value" types are registered in the `ErrorSerializationContext`
#pragma warning disable IL2026, IL3050 // ErrorSerializerContext is registered.
JsonSerializer.Serialize(writer, kvp.Value.Value, kvp.Value.GetType(), options);
#pragma warning restore IL2026, IL3050
}

writer.WriteEndObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
using Elastic.Transport.Extensions;
Expand All @@ -19,12 +20,12 @@ public class ErrorCauseConverter : ErrorCauseConverter<ErrorCause> { }
public class ErrorConverter : ErrorCauseConverter<Error>
{
/// <inheritdoc cref="ErrorCauseConverter{T}.ReadMore"/>
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
protected override bool ReadMore(ref Utf8JsonReader reader, JsonSerializerOptions options, string propertyName, Error errorCause)
{
void ReadAssign<T>(ref Utf8JsonReader r, Action<Error, T> set) =>
#pragma warning disable IL2026, IL3050 // ErrorSerializerContext is registered.
set(errorCause, JsonSerializer.Deserialize<T>(ref r, options));
#pragma warning restore IL2026, IL3050
switch (propertyName)
{
case "headers":
Expand All @@ -45,6 +46,8 @@ void ReadAssign<T>(ref Utf8JsonReader r, Action<Error, T> set) =>
public abstract class ErrorCauseConverter<TErrorCause> : JsonConverter<TErrorCause> where TErrorCause : ErrorCause, new()
{
/// <inheritdoc cref="JsonConverter{T}.Read"/>
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public override TErrorCause Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
Expand All @@ -57,14 +60,10 @@ public override TErrorCause Read(ref Utf8JsonReader reader, Type typeToConvert,
errorCause.AdditionalProperties = additionalProperties;

void ReadAssign<T>(ref Utf8JsonReader r, Action<ErrorCause, T> set) =>
#pragma warning disable IL2026, IL3050 // ErrorSerializerContext is registered.
set(errorCause, JsonSerializer.Deserialize<T>(ref r, options));
#pragma warning restore IL2026, IL3050

void ReadAny(ref Utf8JsonReader r, string property, Action<ErrorCause, string, object> set) =>
#pragma warning disable IL2026, IL3050 // ErrorSerializerContext is registered.
set(errorCause, property, JsonSerializer.Deserialize<JsonElement>(ref r, options));
#pragma warning restore IL2026, IL3050

while (reader.Read())
{
Expand Down Expand Up @@ -151,6 +150,8 @@ void ReadAny(ref Utf8JsonReader r, string property, Action<ErrorCause, string, o
protected virtual bool ReadMore(ref Utf8JsonReader reader, JsonSerializerOptions options, string propertyName, TErrorCause errorCause) => false;

/// <inheritdoc cref="JsonConverter{T}.Read"/>
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public override void Write(Utf8JsonWriter writer, TErrorCause value, JsonSerializerOptions options)
{
writer.WriteStartObject();
Expand All @@ -160,19 +161,15 @@ static void Serialize<T>(Utf8JsonWriter writer, JsonSerializerOptions options, s
if (value is null) return;

writer.WritePropertyName(name);
#pragma warning disable IL2026, IL3050 // ErrorSerializerContext is registered.
JsonSerializer.Serialize(writer, value, options);
#pragma warning restore IL2026, IL3050
}

static void SerializeDynamic(Utf8JsonWriter writer, JsonSerializerOptions options, string name, object? value, Type inputType)
{
if (value is null) return;

writer.WritePropertyName(name);
#pragma warning disable IL2026, IL3050 // ErrorSerializerContext is registered.
JsonSerializer.Serialize(writer, value, inputType, options);
#pragma warning restore IL2026, IL3050
}

//Serialize(writer, options, "bytes_limit", value.BytesLimit);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
Expand All @@ -28,6 +29,11 @@ public LowLevelRequestResponseSerializer() : this(null) { }
/// <inheritdoc cref="LowLevelRequestResponseSerializer"/>>
/// </summary>
/// <param name="converters">Add more default converters onto <see cref="JsonSerializerOptions"/> being used</param>
//[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
//[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public LowLevelRequestResponseSerializer(IReadOnlyCollection<JsonConverter>? converters)
: base(new TransportSerializerOptionsProvider([
new ExceptionConverter(),
Expand All @@ -37,9 +43,6 @@ public LowLevelRequestResponseSerializer(IReadOnlyCollection<JsonConverter>? con
], converters, options =>
{
options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
#pragma warning disable IL2026, IL3050
options.TypeInfoResolver = JsonTypeInfoResolver.Combine(new DefaultJsonTypeInfoResolver(), ElasticsearchTransportSerializerContext.Default);
#pragma warning restore IL2026, IL3050
})) { }

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information

using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text.Json;
using System.Threading;
Expand Down Expand Up @@ -38,6 +39,8 @@ protected SystemTextJsonSerializer(IJsonSerializerOptionsProvider? provider = nu
#region Serializer

/// <inheritdoc />
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public override T Deserialize<T>(Stream stream)
{
if (TryReturnDefault(stream, out T deserialize))
Expand All @@ -56,6 +59,8 @@ public override T Deserialize<T>(Stream stream)
}

/// <inheritdoc />
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "We always provide a static JsonTypeInfoResolver")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "We always provide a static JsonTypeInfoResolver")]
public override ValueTask<T> DeserializeAsync<T>(Stream stream, CancellationToken cancellationToken = default)
{
if (TryReturnDefault(stream, out T deserialize))
Expand Down
7 changes: 3 additions & 4 deletions src/Elastic.Transport/Elastic.Transport.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,16 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="PolySharp" Version="1.15.0" PrivateAssets="all"
IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive"/>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' != 'net8.0'">
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageReference Include="PolySharp" Version="1.15.0" PrivateAssets="all"
IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive"/>
</ItemGroup>
</Project>
18 changes: 5 additions & 13 deletions src/Elastic.Transport/Requests/MetaData/ReflectionVersionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,7 @@ private static SemVersion DetermineVersionFromType(Type type)
// Try to read the full version in 'major.minor.patch[.build][-prerelease][+build]' format. This format is semver2 compliant
// except for the optional [.build] version number.

var version = type.Assembly?.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;

#pragma warning disable IL3000
if (string.IsNullOrEmpty(version) && !string.IsNullOrEmpty(type.Assembly?.Location))
{
var location = type.Assembly?.Location;
version = FileVersionInfo.GetVersionInfo(location)?.ProductVersion;
}
#pragma warning restore IL3000
var version = type.Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;

if (!string.IsNullOrEmpty(version))
{
Expand All @@ -76,10 +68,10 @@ private static SemVersion DetermineVersionFromType(Type type)
var prefix = GetVersionPrefixPart(version);

// Version prefix is not in a valid 'major.minor[.build[.revision]]' form
if (!System.Version.TryParse(prefix, out var prefixVersion))
if (!Version.TryParse(prefix, out var prefixVersion))
return Empty;

// Version prefix '[.revision]' part is not present, but initial semver parsing failed anyways.
// Version prefix '[.revision]' part is not present, but initial semver parsing failed anyway.
// Nothing we can do here...
if (prefixVersion.Revision < 0)
return Empty;
Expand Down Expand Up @@ -111,10 +103,10 @@ private static SemVersion DetermineVersionFromType(Type type)
{
// Try to read the assembly version in 'major.minor[.build[.revision]]' format.

var version = type.Assembly?.GetCustomAttribute<AssemblyVersionAttribute>()?.Version;
var version = type.Assembly.GetCustomAttribute<AssemblyVersionAttribute>()?.Version;

if (string.IsNullOrEmpty(version))
version = type.Assembly?.GetName()?.Version?.ToString();
version = type.Assembly.GetName().Version?.ToString();

if (!string.IsNullOrEmpty(version))
{
Expand Down
Loading
Loading