diff --git a/.gitignore b/.gitignore index 7afb26c..1dcc8c4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.user *.userosscache *.sln.docstates +.vs/ # Ci things node_modules/ diff --git a/src/DotnetKubernetesClient/DotnetKubernetesClient.csproj b/src/DotnetKubernetesClient/DotnetKubernetesClient.csproj index eb5533d..bc7c0d8 100644 --- a/src/DotnetKubernetesClient/DotnetKubernetesClient.csproj +++ b/src/DotnetKubernetesClient/DotnetKubernetesClient.csproj @@ -26,4 +26,10 @@ + + + <_Parameter1>DotnetKubernetesClient.Test + + + diff --git a/src/DotnetKubernetesClient/KubernetesClient.cs b/src/DotnetKubernetesClient/KubernetesClient.cs index 658f919..2392936 100755 --- a/src/DotnetKubernetesClient/KubernetesClient.cs +++ b/src/DotnetKubernetesClient/KubernetesClient.cs @@ -89,7 +89,7 @@ public Task GetCurrentNamespace(string downwardApiEnvName = "POD_NAMESPA if (result is JsonElement element) { - return element.Deserialize(); + return Deserialize(element); } return null; @@ -122,7 +122,7 @@ public async Task> List( if (result is JsonElement element) { - var list = element.Deserialize>(); + var list = Deserialize>(element); return list?.Items ?? throw new ArgumentException("Could not parse result"); } @@ -172,7 +172,7 @@ public async Task Create(TResource resource) if (result is JsonElement element) { - return element.Deserialize() ?? throw new ArgumentException("Could not parse result"); + return Deserialize(element) ?? throw new ArgumentException("Could not parse result"); } throw new ArgumentException("Could not parse result"); @@ -200,7 +200,7 @@ public async Task Update(TResource resource) if (result is JsonElement element) { - return element.Deserialize() ?? throw new ArgumentException("Could not parse result"); + return Deserialize(element) ?? throw new ArgumentException("Could not parse result"); } throw new ArgumentException("Could not parse result"); @@ -228,7 +228,7 @@ public async Task UpdateStatus(TResource resource) if (result is JsonElement element) { - var parsed = element.Deserialize() ?? throw new ArgumentException("Could not parse result"); + var parsed = Deserialize(element) ?? throw new ArgumentException("Could not parse result"); resource.Metadata.ResourceVersion = parsed.Metadata.ResourceVersion; return; } @@ -333,4 +333,17 @@ public Task> Watch( onError, onClose)); } + + private static T Deserialize(JsonElement element) + { + // If we were able to get the default options used by KubernetesJson, + // deserialize directly, it's going to be faster. + if (KubernetesJsonOptions.DefaultOptions is { } options) + { + element.Deserialize(options); + } + + // Else, fallback to the slower but more reliable method. + return KubernetesJson.Deserialize(element.GetRawText()); + } } diff --git a/src/DotnetKubernetesClient/KubernetesJsonOptions.cs b/src/DotnetKubernetesClient/KubernetesJsonOptions.cs new file mode 100644 index 0000000..09a4ae4 --- /dev/null +++ b/src/DotnetKubernetesClient/KubernetesJsonOptions.cs @@ -0,0 +1,36 @@ +using System; +using System.Reflection; +using System.Text.Json; +using k8s; + +#nullable enable + +namespace DotnetKubernetesClient +{ + internal static class KubernetesJsonOptions + { + private static readonly Lazy Lazy = new(GetJsonSerializerOptions); + + public static JsonSerializerOptions? DefaultOptions => Lazy.Value; + + private static JsonSerializerOptions? GetJsonSerializerOptions() + { + try + { + // Get the default (and private) KubernetesJson options. + var fieldInfo = typeof(KubernetesJson).GetField("JsonSerializerOptions", BindingFlags.Static | BindingFlags.NonPublic); + if (fieldInfo != null + && fieldInfo.GetValue(null) is JsonSerializerOptions options) + { + return options; + } + } + catch + { + // Ignored + } + + return null; + } + } +} diff --git a/tests/DotnetKubernetesClient.Test/KubernetesJsonOptions.Test.cs b/tests/DotnetKubernetesClient.Test/KubernetesJsonOptions.Test.cs new file mode 100644 index 0000000..8df3f0f --- /dev/null +++ b/tests/DotnetKubernetesClient.Test/KubernetesJsonOptions.Test.cs @@ -0,0 +1,16 @@ +using FluentAssertions; +using Xunit; + +namespace DotnetKubernetesClient.Test +{ + public class KubernetesJsonOptionsTest + { + [Fact] + public void DefaultOptions_should_not_return_null() + { + var result = KubernetesJsonOptions.DefaultOptions; + + result.Should().NotBe(null); + } + } +}