diff --git a/Clean.bat b/Clean.bat new file mode 100644 index 000000000..51b0409a4 --- /dev/null +++ b/Clean.bat @@ -0,0 +1,8 @@ +FOR /d /r . %%d in (bin,obj) do @if exist "%%d" rd /s/q "%%d" +FOR /F "tokens=*" %%G IN ('DIR /B /AD /S Packages') DO RMDIR /S /Q "%%G" +FOR /F "tokens=*" %%G IN ('DIR /B /AD /S .vs') DO RMDIR /S /Q "%%G" +FOR /F "tokens=*" %%G IN ('DIR /B /AD /S .vscode') DO RMDIR /S /Q "%%G" +FOR /F "tokens=*" %%G IN ('DIR /B /AD /S TestResults') DO RMDIR /S /Q "%%G" +FOR /F "tokens=*" %%G IN ('DIR /B /AD /S AppPackages') DO RMDIR /S /Q "%%G" +DEL /Q /F /S "*.csproj.user" +DEL /Q /F /S "*.sln.DotSettings.user" \ No newline at end of file diff --git a/docs/features/dependencyinjection.rst b/docs/features/dependencyinjection.rst index dbd3437f6..abf974de2 100644 --- a/docs/features/dependencyinjection.rst +++ b/docs/features/dependencyinjection.rst @@ -132,7 +132,14 @@ Current `implementation + { + op.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; + op.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString; + op.JsonSerializerOptions.WriteIndented = false; + op.JsonSerializerOptions.PropertyNameCaseInsensitive = true; + op.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); + }); } The method cannot be overridden. It is not virtual, and there is no way to override current behavior by inheritance. @@ -154,74 +161,6 @@ The next section shows you an example of designing custom Ocelot pipeline by cus .. _di-custom-builder: -Custom Builder --------------- - -**Goal**: Replace ``Newtonsoft.Json`` services with ``System.Text.Json`` services. - -Problem -^^^^^^^ - -The main `AddOcelot`_ method adds -`Newtonsoft JSON `_ services -by the ``AddNewtonsoftJson`` extension method in default builder (`AddDefaultAspNetServices`_ method). -The ``AddNewtonsoftJson`` method calling was introduced in old .NET and Ocelot releases which was necessary when Microsoft did not launch the ``System.Text.Json`` library, -but now it affects normal use, so we have an intention to solve the problem. - -Modern `JSON services `_ -out of `the box `_ -will help to configure JSON settings by the ``JsonSerializerOptions`` property for JSON formatters during (de)serialization. - -Solution -^^^^^^^^ - -We have the following methods in `ServiceCollectionExtensions`_ class: - -.. code-block:: csharp - - IOcelotBuilder AddOcelotUsingBuilder(this IServiceCollection services, Func customBuilder); - IOcelotBuilder AddOcelotUsingBuilder(this IServiceCollection services, IConfiguration configuration, Func customBuilder); - -These methods with custom builder allow you to use your any desired JSON library for (de)serialization. -But we are going to create custom ``MvcCoreBuilder`` with support of JSON services, such as ``System.Text.Json``. -To do that we need to call ``AddJsonOptions`` extension of the ``MvcCoreMvcCoreBuilderExtensions`` class -(NuGet package: `Microsoft.AspNetCore.Mvc.Core `_) in **Startup.cs**: - -.. code-block:: csharp - - using Microsoft.Extensions.DependencyInjection; - using Ocelot.DependencyInjection; - using System.Reflection; - - public class Startup - { - public void ConfigureServices(IServiceCollection services) - { - services - .AddLogging() - .AddMiddlewareAnalysis() - .AddWebEncoders() - // Add your custom builder - .AddOcelotUsingBuilder(MyCustomBuilder); - } - - private static IMvcCoreBuilder MyCustomBuilder(IMvcCoreBuilder builder, Assembly assembly) - { - return builder - .AddApplicationPart(assembly) - .AddControllersAsServices() - .AddAuthorization() - - // Replace AddNewtonsoftJson() by AddJsonOptions() - .AddJsonOptions(options => - { - options.JsonSerializerOptions.WriteIndented = true; // use System.Text.Json - }); - } - } - -The sample code provides settings to render JSON as indented text rather than compressed plain JSON text without spaces. -This is just one common use case, and you can add additional services to the builder. ------------------------------------------------------------------ diff --git a/src/Ocelot.Provider.Consul/ConsulFileConfigurationRepository.cs b/src/Ocelot.Provider.Consul/ConsulFileConfigurationRepository.cs index c95146f46..79937962f 100644 --- a/src/Ocelot.Provider.Consul/ConsulFileConfigurationRepository.cs +++ b/src/Ocelot.Provider.Consul/ConsulFileConfigurationRepository.cs @@ -1,13 +1,14 @@ using Microsoft.Extensions.Options; -using Newtonsoft.Json; using Ocelot.Cache; using Ocelot.Configuration; using Ocelot.Configuration.File; using Ocelot.Configuration.Repository; +using Ocelot.Infrastructure; using Ocelot.Logging; using Ocelot.Provider.Consul.Interfaces; using Ocelot.Responses; using System.Text; +using System.Text.Json; namespace Ocelot.Provider.Consul; @@ -53,14 +54,14 @@ public async Task> Get() var bytes = queryResult.Response.Value; var json = Encoding.UTF8.GetString(bytes); - var consulConfig = JsonConvert.DeserializeObject(json); + var consulConfig = JsonSerializer.Deserialize(json, JsonSerializerOptionsExtensions.Web); return new OkResponse(consulConfig); } public async Task Set(FileConfiguration ocelotConfiguration) { - var json = JsonConvert.SerializeObject(ocelotConfiguration, Formatting.Indented); + var json = JsonSerializer.Serialize(ocelotConfiguration, JsonSerializerOptionsExtensions.WebWriteIndented); var bytes = Encoding.UTF8.GetBytes(json); var kvPair = new KVPair(_configurationKey) { diff --git a/src/Ocelot/Configuration/Repository/DiskFileConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/DiskFileConfigurationRepository.cs index 023fbfafc..2d964b17a 100644 --- a/src/Ocelot/Configuration/Repository/DiskFileConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/DiskFileConfigurationRepository.cs @@ -1,9 +1,10 @@ using Microsoft.AspNetCore.Hosting; -using Newtonsoft.Json; using Ocelot.Configuration.ChangeTracking; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.Responses; +using System.Text.Json; using FileSys = System.IO.File; namespace Ocelot.Configuration.Repository @@ -49,14 +50,14 @@ public Task> Get() jsonConfiguration = FileSys.ReadAllText(_environmentFile.FullName); } - var fileConfiguration = JsonConvert.DeserializeObject(jsonConfiguration); + var fileConfiguration = JsonSerializer.Deserialize(jsonConfiguration, JsonSerializerOptionsExtensions.Web); return Task.FromResult>(new OkResponse(fileConfiguration)); } public Task Set(FileConfiguration fileConfiguration) { - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.WebWriteIndented); lock (_lock) { diff --git a/src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs b/src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs index 969a34161..e3f9232a0 100644 --- a/src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs +++ b/src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs @@ -1,8 +1,9 @@ using Microsoft.Extensions.Hosting; -using Newtonsoft.Json; using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; +using Ocelot.Infrastructure; using Ocelot.Logging; +using System.Text.Json; namespace Ocelot.Configuration.Repository { @@ -68,7 +69,7 @@ private async Task Poll() if (fileConfig.IsError) { - _logger.LogWarning(() =>$"error geting file config, errors are {string.Join(',', fileConfig.Errors.Select(x => x.Message))}"); + _logger.LogWarning(() => $"error geting file config, errors are {string.Join(',', fileConfig.Errors.Select(x => x.Message))}"); return; } @@ -95,7 +96,7 @@ private async Task Poll() /// hash of the config. private static string ToJson(FileConfiguration config) { - var currentHash = JsonConvert.SerializeObject(config); + var currentHash = JsonSerializer.Serialize(config, JsonSerializerOptionsExtensions.Web); return currentHash; } diff --git a/src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs b/src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs index 9101f5b52..c8f434fb3 100644 --- a/src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs +++ b/src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs @@ -1,9 +1,10 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Configuration.Memory; -using Newtonsoft.Json; +using Microsoft.Extensions.Configuration.Memory; using Ocelot.Configuration.File; - +using Ocelot.Infrastructure; +using System.Text.Json; + namespace Ocelot.DependencyInjection { /// @@ -98,8 +99,8 @@ public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder private static IConfigurationBuilder ApplyMergeOcelotJsonOption(IConfigurationBuilder builder, MergeOcelotJson mergeTo, string json, string primaryConfigFile, bool? optional, bool? reloadOnChange) { - return mergeTo == MergeOcelotJson.ToMemory ? - builder.AddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(json))) : + return mergeTo == MergeOcelotJson.ToMemory ? + builder.AddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(json))) : AddOcelotJsonFile(builder, json, primaryConfigFile, optional, reloadOnChange); } @@ -132,7 +133,7 @@ private static string GetMergedOcelotJson(string folder, IWebHostEnvironment env } var lines = File.ReadAllText(file.FullName); - var config = JsonConvert.DeserializeObject(lines); + var config = JsonSerializer.Deserialize(lines, JsonSerializerOptionsExtensions.Web); if (file.Name.Equals(globalFileInfo.Name, StringComparison.OrdinalIgnoreCase) && file.FullName.Equals(globalFileInfo.FullName, StringComparison.OrdinalIgnoreCase)) { @@ -143,7 +144,7 @@ private static string GetMergedOcelotJson(string folder, IWebHostEnvironment env fileConfiguration.Routes.AddRange(config.Routes); } - return JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented); + return JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.WebWriteIndented); } /// @@ -160,7 +161,7 @@ private static string GetMergedOcelotJson(string folder, IWebHostEnvironment env public static IConfigurationBuilder AddOcelot(this IConfigurationBuilder builder, FileConfiguration fileConfiguration, string primaryConfigFile = null, bool? optional = null, bool? reloadOnChange = null) // optional injections { - var json = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented); + var json = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.WebWriteIndented); return AddOcelotJsonFile(builder, json, primaryConfigFile, optional, reloadOnChange); } diff --git a/src/Ocelot/DependencyInjection/OcelotBuilder.cs b/src/Ocelot/DependencyInjection/OcelotBuilder.cs index 217280e37..4de79ff89 100644 --- a/src/Ocelot/DependencyInjection/OcelotBuilder.cs +++ b/src/Ocelot/DependencyInjection/OcelotBuilder.cs @@ -4,7 +4,6 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using Ocelot.Authorization; -using Ocelot.Cache; using Ocelot.Claims; using Ocelot.Configuration; using Ocelot.Configuration.ChangeTracking; @@ -27,7 +26,6 @@ using Ocelot.Multiplexer; using Ocelot.PathManipulation; using Ocelot.QueryStrings; -using Ocelot.RateLimiting; using Ocelot.Request.Creator; using Ocelot.Request.Mapper; using Ocelot.Requester; @@ -39,6 +37,9 @@ using Ocelot.ServiceDiscovery.Providers; using Ocelot.WebSockets; using System.Reflection; +using System.Text.Encodings.Web; +using System.Text.Json.Serialization; +using System.Text.Unicode; namespace Ocelot.DependencyInjection { @@ -111,7 +112,7 @@ public OcelotBuilder(IServiceCollection services, IConfiguration configurationRo Services.TryAddSingleton(); Services.TryAddSingleton(); Services.TryAddSingleton(); - + Services.TryAddSingleton(); Services.TryAddSingleton, OcelotConfigurationMonitor>(); @@ -157,7 +158,6 @@ public OcelotBuilder(IServiceCollection services, IConfiguration configurationRo /// /// Adds default ASP.NET services which are the minimal part of the gateway core. /// - /// Finally the builder adds Newtonsoft.Json services via the extension-method.
/// To remove these services, use custom builder in the extension-method. ///
///
@@ -171,8 +171,7 @@ public OcelotBuilder(IServiceCollection services, IConfiguration configurationRo /// Warning! The following extensions being called:
/// -
/// -
- /// -
- /// - , removable. + /// - /// /// /// The default builder being returned by extension-method. @@ -189,7 +188,14 @@ protected IMvcCoreBuilder AddDefaultAspNetServices(IMvcCoreBuilder builder, Asse .AddApplicationPart(assembly) .AddControllersAsServices() .AddAuthorization() - .AddNewtonsoftJson(); + .AddJsonOptions(op => + { + op.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; + op.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString; + op.JsonSerializerOptions.WriteIndented = false; + op.JsonSerializerOptions.PropertyNameCaseInsensitive = true; + op.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); + }); } public IOcelotBuilder AddSingletonDefinedAggregator() diff --git a/src/Ocelot/Infrastructure/JsonSerializerOptionsExtensions.cs b/src/Ocelot/Infrastructure/JsonSerializerOptionsExtensions.cs new file mode 100644 index 000000000..7417ceb21 --- /dev/null +++ b/src/Ocelot/Infrastructure/JsonSerializerOptionsExtensions.cs @@ -0,0 +1,29 @@ +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Unicode; + +namespace Ocelot.Infrastructure +{ + public static class JsonSerializerOptionsExtensions + { + public static readonly JsonSerializerOptions Web = new() + { + PropertyNameCaseInsensitive = true, + NumberHandling = JsonNumberHandling.AllowReadingFromString, + ReferenceHandler = ReferenceHandler.IgnoreCycles, + WriteIndented = false, + Encoder = JavaScriptEncoder.Create(UnicodeRanges.All), + + }; + + public static readonly JsonSerializerOptions WebWriteIndented = new() + { + PropertyNameCaseInsensitive = true, + NumberHandling = JsonNumberHandling.AllowReadingFromString, + ReferenceHandler = ReferenceHandler.IgnoreCycles, + WriteIndented = true, + Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) + }; + } +} diff --git a/src/Ocelot/Metadata/DownstreamRouteExtensions.cs b/src/Ocelot/Metadata/DownstreamRouteExtensions.cs index ca3ba25e6..b9c351f0c 100644 --- a/src/Ocelot/Metadata/DownstreamRouteExtensions.cs +++ b/src/Ocelot/Metadata/DownstreamRouteExtensions.cs @@ -1,6 +1,6 @@ using Ocelot.Configuration; +using Ocelot.Infrastructure; using System.Globalization; -using System.Reflection; using System.Text.Json; namespace Ocelot.Metadata; @@ -74,7 +74,7 @@ public static T GetMetadata(this DownstreamRoute downstreamRoute, string key, } return (T)ConvertTo(typeof(T), metadataValue, downstreamRoute.MetadataOptions, - jsonSerializerOptions ?? new JsonSerializerOptions(JsonSerializerDefaults.Web)); + jsonSerializerOptions ?? JsonSerializerOptionsExtensions.Web); } /// diff --git a/src/Ocelot/Multiplexer/MultiplexingMiddleware.cs b/src/Ocelot/Multiplexer/MultiplexingMiddleware.cs index 43a98fcd3..a25299ec5 100644 --- a/src/Ocelot/Multiplexer/MultiplexingMiddleware.cs +++ b/src/Ocelot/Multiplexer/MultiplexingMiddleware.cs @@ -1,12 +1,14 @@ +using Json.Path; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -using Newtonsoft.Json.Linq; using Ocelot.Configuration; using Ocelot.Configuration.File; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Logging; using Ocelot.Middleware; using System.Collections; +using System.Text.Json; +using System.Text.Json.Nodes; using Route = Ocelot.Configuration.Route; namespace Ocelot.Multiplexer; @@ -132,14 +134,15 @@ protected virtual async Task ProcessRoutesWithRouteKeysAsync(Http { var processing = new List>(); var content = await mainResponse.Items.DownstreamResponse().Content.ReadAsStringAsync(); - var jObject = JToken.Parse(content); + var jObject = JsonDocument.Parse(content); + var jNode = JsonNode.Parse(content); foreach (var downstreamRoute in routes.Skip(1)) { var matchAdvancedAgg = routeKeysConfigs.FirstOrDefault(q => q.RouteKey == downstreamRoute.Key); if (matchAdvancedAgg != null) { - processing.AddRange(ProcessRouteWithComplexAggregation(matchAdvancedAgg, jObject, context, downstreamRoute)); + processing.AddRange(ProcessRouteWithComplexAggregation(matchAdvancedAgg, jNode, jObject, context, downstreamRoute)); continue; } @@ -163,10 +166,16 @@ private Task MapResponsesAsync(HttpContext context, Route route, HttpContext mai /// Processing a route with aggregation. /// private IEnumerable> ProcessRouteWithComplexAggregation(AggregateRouteConfig matchAdvancedAgg, - JToken jObject, HttpContext httpContext, DownstreamRoute downstreamRoute) + JsonNode jNode, JsonDocument jObject, HttpContext httpContext, DownstreamRoute downstreamRoute) { - var processing = new List>(); - var values = jObject.SelectTokens(matchAdvancedAgg.JsonPath).Select(s => s.ToString()).Distinct(); + var processing = new List>(); + + var tokenPaths = JsonPath.Parse(matchAdvancedAgg.JsonPath); + var values = tokenPaths.Evaluate(jNode) + .Matches + .Select(s => s.Value?.ToString()) + .Distinct(); + foreach (var value in values) { var tPnv = httpContext.Items.TemplatePlaceholderNameAndValues(); diff --git a/src/Ocelot/Ocelot.csproj b/src/Ocelot/Ocelot.csproj index b876ca4b7..f2d3bd3ef 100644 --- a/src/Ocelot/Ocelot.csproj +++ b/src/Ocelot/Ocelot.csproj @@ -1,62 +1,65 @@  - - net6.0;net7.0;net8.0 - disable - disable - true - Ocelot is an API gateway based on .NET stack. - Ocelot - 0.0.0-dev - Ocelot - Ocelot - API Gateway;.NET core - https://github.com/ThreeMammals/Ocelot - https://raw.githubusercontent.com/ThreeMammals/Ocelot/develop/images/ocelot_logo.png - README.md - win-x64;osx-x64 - false - false - True - false - Tom Pallister - ..\..\codeanalysis.ruleset - True - 1591 - - - full - True - - - - - - - NU1701 - - - all - - - - - - - - - - - - - - - - - - - - - - - + + net6.0;net7.0;net8.0 + disable + disable + true + Ocelot is an API gateway based on .NET stack. + Ocelot + 0.0.0-dev + Ocelot + Ocelot + API Gateway;.NET core + https://github.com/ThreeMammals/Ocelot + https://raw.githubusercontent.com/ThreeMammals/Ocelot/develop/images/ocelot_logo.png + README.md + win-x64;osx-x64 + false + false + True + false + Tom Pallister + ..\..\codeanalysis.ruleset + True + 1591 + + + full + True + + + + + + + NU1701 + + + all + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ocelot/RateLimiting/DistributedCacheRateLimitStorage.cs b/src/Ocelot/RateLimiting/DistributedCacheRateLimitStorage.cs index b7fb79de3..6a6a3057d 100644 --- a/src/Ocelot/RateLimiting/DistributedCacheRateLimitStorage.cs +++ b/src/Ocelot/RateLimiting/DistributedCacheRateLimitStorage.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Caching.Distributed; -using Newtonsoft.Json; +using Ocelot.Infrastructure; +using System.Text.Json; namespace Ocelot.RateLimiting; @@ -16,7 +17,7 @@ public class DistributedCacheRateLimitStorage : IRateLimitStorage public DistributedCacheRateLimitStorage(IDistributedCache memoryCache) => _memoryCache = memoryCache; public void Set(string id, RateLimitCounter counter, TimeSpan expirationTime) - => _memoryCache.SetString(id, JsonConvert.SerializeObject(counter), new DistributedCacheEntryOptions().SetAbsoluteExpiration(expirationTime)); + => _memoryCache.SetString(id, JsonSerializer.Serialize(counter, JsonSerializerOptionsExtensions.Web), new DistributedCacheEntryOptions().SetAbsoluteExpiration(expirationTime)); public bool Exists(string id) => !string.IsNullOrEmpty(_memoryCache.GetString(id)); @@ -24,7 +25,7 @@ public void Set(string id, RateLimitCounter counter, TimeSpan expirationTime) { var stored = _memoryCache.GetString(id); return !string.IsNullOrEmpty(stored) - ? JsonConvert.DeserializeObject(stored) + ? JsonSerializer.Deserialize(stored, JsonSerializerOptionsExtensions.Web) : null; } diff --git a/src/Ocelot/RateLimiting/RateLimitCounter.cs b/src/Ocelot/RateLimiting/RateLimitCounter.cs index 2507a0433..850911dfb 100644 --- a/src/Ocelot/RateLimiting/RateLimitCounter.cs +++ b/src/Ocelot/RateLimiting/RateLimitCounter.cs @@ -1,4 +1,6 @@ -using Newtonsoft.Json; + + +using System.Text.Json.Serialization; namespace Ocelot.RateLimiting; diff --git a/src/Ocelot/Requester/MessageInvokerPool.cs b/src/Ocelot/Requester/MessageInvokerPool.cs index 130b4bccb..7e6340838 100644 --- a/src/Ocelot/Requester/MessageInvokerPool.cs +++ b/src/Ocelot/Requester/MessageInvokerPool.cs @@ -76,7 +76,7 @@ private HttpMessageHandler CreateHandler(DownstreamRoute downstreamRoute) UseCookies = downstreamRoute.HttpHandlerOptions.UseCookieContainer, UseProxy = downstreamRoute.HttpHandlerOptions.UseProxy, MaxConnectionsPerServer = downstreamRoute.HttpHandlerOptions.MaxConnectionsPerServer, - PooledConnectionLifetime = downstreamRoute.HttpHandlerOptions.PooledConnectionLifeTime, + PooledConnectionLifetime = downstreamRoute.HttpHandlerOptions.PooledConnectionLifeTime }; if (downstreamRoute.HttpHandlerOptions.UseCookieContainer) diff --git a/test/Ocelot.AcceptanceTests/BearerToken.cs b/test/Ocelot.AcceptanceTests/BearerToken.cs index 6c52ced10..f7e29b2d4 100644 --- a/test/Ocelot.AcceptanceTests/BearerToken.cs +++ b/test/Ocelot.AcceptanceTests/BearerToken.cs @@ -1,16 +1,16 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Ocelot.AcceptanceTests { internal class BearerToken { - [JsonProperty("access_token")] + [JsonPropertyName("access_token")] public string AccessToken { get; set; } - [JsonProperty("expires_in")] + [JsonPropertyName("expires_in")] public int ExpiresIn { get; set; } - [JsonProperty("token_type")] + [JsonPropertyName("token_type")] public string TokenType { get; set; } } } diff --git a/test/Ocelot.AcceptanceTests/Caching/CachingTests.cs b/test/Ocelot.AcceptanceTests/Caching/CachingTests.cs index c029ad56d..fa59a33a2 100644 --- a/test/Ocelot.AcceptanceTests/Caching/CachingTests.cs +++ b/test/Ocelot.AcceptanceTests/Caching/CachingTests.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Ocelot.Configuration.File; +using Ocelot.Infrastructure; using System.Text; using JsonSerializer = System.Text.Json.JsonSerializer; @@ -298,7 +299,7 @@ private void ThenTheCounterValueShouldBe(int expected) LastName = "Test", }; - var testBody1String = JsonSerializer.Serialize(testBody1); + var testBody1String = JsonSerializer.Serialize(testBody1, JsonSerializerOptionsExtensions.Web); var testBody2 = new TestBody { @@ -308,7 +309,7 @@ private void ThenTheCounterValueShouldBe(int expected) LastName = "Test", }; - var testBody2String = JsonSerializer.Serialize(testBody2); + var testBody2String = JsonSerializer.Serialize(testBody2, JsonSerializerOptionsExtensions.Web); return (testBody1String, testBody2String); } diff --git a/test/Ocelot.AcceptanceTests/Configuration/ConfigurationInConsulTests.cs b/test/Ocelot.AcceptanceTests/Configuration/ConfigurationInConsulTests.cs index ca2da9360..85ed28a38 100644 --- a/test/Ocelot.AcceptanceTests/Configuration/ConfigurationInConsulTests.cs +++ b/test/Ocelot.AcceptanceTests/Configuration/ConfigurationInConsulTests.cs @@ -4,179 +4,180 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; -using Newtonsoft.Json; using Ocelot.Configuration.File; +using Ocelot.Infrastructure; using System.Text; - -namespace Ocelot.AcceptanceTests.Configuration -{ - public class ConfigurationInConsulTests : IDisposable - { - private IHost _builder; - private readonly Steps _steps; - private IHost _fakeConsulBuilder; - private FileConfiguration _config; - private readonly List _consulServices; - - public ConfigurationInConsulTests() - { - _consulServices = new List(); - _steps = new Steps(); - } - - [Fact] - public void should_return_response_200_with_simple_url_when_using_jsonserialized_cache() - { - var consulPort = PortFinder.GetRandomPort(); - var servicePort = PortFinder.GetRandomPort(); - - var configuration = new FileConfiguration - { - Routes = new List - { - new() - { - DownstreamPathTemplate = "/", - DownstreamScheme = "http", - DownstreamHostAndPorts = new List - { - new() - { - Host = "localhost", - Port = servicePort, - }, - }, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - }, - }, - GlobalConfiguration = new FileGlobalConfiguration - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider - { - Scheme = "http", - Host = "localhost", - Port = consulPort, - }, - }, - }; - - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - - this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, string.Empty)) - .And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", string.Empty, 200, "Hello from Laura")) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - .BDDfy(); - } - - private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName) - { - _fakeConsulBuilder = Host.CreateDefaultBuilder() - .ConfigureWebHost(webBuilder => - { - webBuilder.UseUrls(url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(url) - .Configure(app => - { - app.Run(async context => - { - if (context.Request.Method.ToLower() == "get" && context.Request.Path.Value == "/v1/kv/InternalConfiguration") - { - var json = JsonConvert.SerializeObject(_config); - - var bytes = Encoding.UTF8.GetBytes(json); - - var base64 = Convert.ToBase64String(bytes); - - var kvp = new FakeConsulGetResponse(base64); - - await context.Response.WriteJsonAsync(new[] { kvp }); - } - else if (context.Request.Method.ToLower() == "put" && context.Request.Path.Value == "/v1/kv/InternalConfiguration") - { - try - { - var reader = new StreamReader(context.Request.Body); - - // Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead. - // var json = reader.ReadToEnd(); - var json = await reader.ReadToEndAsync(); - - _config = JsonConvert.DeserializeObject(json); - - var response = JsonConvert.SerializeObject(true); - - await context.Response.WriteAsync(response); - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - else if (context.Request.Path.Value == $"/v1/health/service/{serviceName}") - { - await context.Response.WriteJsonAsync(_consulServices); - } - }); - }); - }).Build(); - - _fakeConsulBuilder.Start(); - } - - public class FakeConsulGetResponse - { - public FakeConsulGetResponse(string value) - { - Value = value; - } - - public int CreateIndex => 100; - public int ModifyIndex => 200; - public int LockIndex => 200; - public string Key => "InternalConfiguration"; - public int Flags => 0; - public string Value { get; } - public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e"; - } - - private void GivenThereIsAServiceRunningOn(string url, string basePath, int statusCode, string responseBody) - { - _builder = Host.CreateDefaultBuilder() - .ConfigureWebHost(webBuilder => - { - webBuilder.UseUrls(url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(url) - .Configure(app => - { - app.UsePathBase(basePath); - app.Run(async context => - { - context.Response.StatusCode = statusCode; - await context.Response.WriteAsync(responseBody); - }); - }); - }) - .Build(); - - _builder.Start(); - } - - public void Dispose() - { - _builder?.Dispose(); - _steps.Dispose(); - } - } -} +using System.Text.Json; + +namespace Ocelot.AcceptanceTests.Configuration +{ + public class ConfigurationInConsulTests : IDisposable + { + private IHost _builder; + private readonly Steps _steps; + private IHost _fakeConsulBuilder; + private FileConfiguration _config; + private readonly List _consulServices; + + public ConfigurationInConsulTests() + { + _consulServices = new List(); + _steps = new Steps(); + } + + [Fact] + public void should_return_response_200_with_simple_url_when_using_jsonserialized_cache() + { + var consulPort = PortFinder.GetRandomPort(); + var servicePort = PortFinder.GetRandomPort(); + + var configuration = new FileConfiguration + { + Routes = new List + { + new() + { + DownstreamPathTemplate = "/", + DownstreamScheme = "http", + DownstreamHostAndPorts = new List + { + new() + { + Host = "localhost", + Port = servicePort, + }, + }, + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + }, + }, + GlobalConfiguration = new FileGlobalConfiguration + { + ServiceDiscoveryProvider = new FileServiceDiscoveryProvider + { + Scheme = "http", + Host = "localhost", + Port = consulPort, + }, + }, + }; + + var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; + + this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, string.Empty)) + .And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", string.Empty, 200, "Hello from Laura")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + + private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName) + { + _fakeConsulBuilder = Host.CreateDefaultBuilder() + .ConfigureWebHost(webBuilder => + { + webBuilder.UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .Configure(app => + { + app.Run(async context => + { + if (context.Request.Method.ToLower() == "get" && context.Request.Path.Value == "/v1/kv/InternalConfiguration") + { + var json = JsonSerializer.Serialize(_config, JsonSerializerOptionsExtensions.Web); + + var bytes = Encoding.UTF8.GetBytes(json); + + var base64 = Convert.ToBase64String(bytes); + + var kvp = new FakeConsulGetResponse(base64); + + await context.Response.WriteJsonAsync(new[] { kvp }); + } + else if (context.Request.Method.ToLower() == "put" && context.Request.Path.Value == "/v1/kv/InternalConfiguration") + { + try + { + var reader = new StreamReader(context.Request.Body); + + // Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead. + // var json = reader.ReadToEnd(); + var json = await reader.ReadToEndAsync(); + + _config = JsonSerializer.Deserialize(json, JsonSerializerOptionsExtensions.Web); + + var response = JsonSerializer.Serialize(true, JsonSerializerOptionsExtensions.Web); + + await context.Response.WriteAsync(response); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + else if (context.Request.Path.Value == $"/v1/health/service/{serviceName}") + { + await context.Response.WriteJsonAsync(_consulServices); + } + }); + }); + }).Build(); + + _fakeConsulBuilder.Start(); + } + + public class FakeConsulGetResponse + { + public FakeConsulGetResponse(string value) + { + Value = value; + } + + public int CreateIndex => 100; + public int ModifyIndex => 200; + public int LockIndex => 200; + public string Key => "InternalConfiguration"; + public int Flags => 0; + public string Value { get; } + public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e"; + } + + private void GivenThereIsAServiceRunningOn(string url, string basePath, int statusCode, string responseBody) + { + _builder = Host.CreateDefaultBuilder() + .ConfigureWebHost(webBuilder => + { + webBuilder.UseUrls(url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(url) + .Configure(app => + { + app.UsePathBase(basePath); + app.Run(async context => + { + context.Response.StatusCode = statusCode; + await context.Response.WriteAsync(responseBody); + }); + }); + }) + .Build(); + + _builder.Start(); + } + + public void Dispose() + { + _builder?.Dispose(); + _steps.Dispose(); + } + } +} diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulConfigurationInConsulTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulConfigurationInConsulTests.cs index d97d98c09..c3b8a23f7 100644 --- a/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulConfigurationInConsulTests.cs +++ b/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulConfigurationInConsulTests.cs @@ -2,10 +2,11 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; using Ocelot.Cache; using Ocelot.Configuration.File; +using Ocelot.Infrastructure; using System.Text; +using System.Text.Json; namespace Ocelot.AcceptanceTests.ServiceDiscovery { @@ -362,14 +363,14 @@ private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string { if (context.Request.Method.ToLower() == "get" && context.Request.Path.Value == "/v1/kv/InternalConfiguration") { - var json = JsonConvert.SerializeObject(_config); + var json = JsonSerializer.Serialize(_config, JsonSerializerOptionsExtensions.Web); var bytes = Encoding.UTF8.GetBytes(json); var base64 = Convert.ToBase64String(bytes); var kvp = new FakeConsulGetResponse(base64); - json = JsonConvert.SerializeObject(new[] { kvp }); + json = JsonSerializer.Serialize(new[] { kvp }, JsonSerializerOptionsExtensions.Web); context.Response.Headers.Append("Content-Type", "application/json"); await context.Response.WriteAsync(json); } @@ -383,9 +384,9 @@ private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string // var json = reader.ReadToEnd(); var json = await reader.ReadToEndAsync(); - _config = JsonConvert.DeserializeObject(json); + _config = JsonSerializer.Deserialize(json, JsonSerializerOptionsExtensions.Web); - var response = JsonConvert.SerializeObject(true); + var response = JsonSerializer.Serialize(true, JsonSerializerOptionsExtensions.Web); await context.Response.WriteAsync(response); } @@ -397,7 +398,7 @@ private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string } else if (context.Request.Path.Value == $"/v1/health/service/{serviceName}") { - var json = JsonConvert.SerializeObject(_consulServices); + var json = JsonSerializer.Serialize(_consulServices, JsonSerializerOptionsExtensions.Web); context.Response.Headers.Append("Content-Type", "application/json"); await context.Response.WriteAsync(json); } diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulServiceDiscoveryTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulServiceDiscoveryTests.cs index b98f93c0d..b4dfe7dc6 100644 --- a/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulServiceDiscoveryTests.cs +++ b/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulServiceDiscoveryTests.cs @@ -1,14 +1,15 @@ using Consul; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.Logging; using Ocelot.Provider.Consul; using Ocelot.Provider.Consul.Interfaces; using System.Runtime.CompilerServices; +using System.Text.Json; using System.Text.RegularExpressions; namespace Ocelot.AcceptanceTests.ServiceDiscovery; @@ -426,7 +427,8 @@ private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url) // Use the parsed service name to filter the registered Consul services var serviceName = pathMatch.Groups["serviceName"].Value; var services = _consulServices.Where(x => x.Service.Service == serviceName).ToList(); - var json = JsonConvert.SerializeObject(services); + var json = JsonSerializer.Serialize(services, JsonSerializerOptionsExtensions.Web); + json = json.Replace("\"Name\":", "\"Node\":"); context.Response.Headers.Append("Content-Type", "application/json"); await context.Response.WriteAsync(json); return; @@ -435,7 +437,7 @@ private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url) if (context.Request.Path.Value == "/v1/catalog/nodes") { _counterNodes++; - var json = JsonConvert.SerializeObject(_consulNodes); + var json = JsonSerializer.Serialize(_consulNodes, JsonSerializerOptionsExtensions.Web); context.Response.Headers.Append("Content-Type", "application/json"); await context.Response.WriteAsync(json); } diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulWebSocketTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulWebSocketTests.cs index 9afa1b154..11ac68c26 100644 --- a/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulWebSocketTests.cs +++ b/test/Ocelot.AcceptanceTests/ServiceDiscovery/ConsulWebSocketTests.cs @@ -1,10 +1,11 @@ using Consul; using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; using Ocelot.Configuration.File; +using Ocelot.Infrastructure; using Ocelot.WebSockets; using System.Net.WebSockets; using System.Text; +using System.Text.Json; namespace Ocelot.AcceptanceTests.ServiceDiscovery { @@ -125,7 +126,7 @@ private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string { if (context.Request.Path.Value == $"/v1/health/service/{serviceName}") { - var json = JsonConvert.SerializeObject(_serviceEntries); + var json = JsonSerializer.Serialize(_serviceEntries, JsonSerializerOptionsExtensions.Web); context.Response.Headers.Append("Content-Type", "application/json"); await context.Response.WriteAsync(json); } diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscovery/EurekaServiceDiscoveryTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscovery/EurekaServiceDiscoveryTests.cs index 5ec8f194b..9b74a2abe 100644 --- a/test/Ocelot.AcceptanceTests/ServiceDiscovery/EurekaServiceDiscoveryTests.cs +++ b/test/Ocelot.AcceptanceTests/ServiceDiscovery/EurekaServiceDiscoveryTests.cs @@ -1,8 +1,10 @@ using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; using Ocelot.Configuration.File; +using Ocelot.Infrastructure; using Ocelot.LoadBalancer.LoadBalancers; using Steeltoe.Common.Discovery; +using System.Text.Json; +using System.Text.Json.Serialization; namespace Ocelot.AcceptanceTests.ServiceDiscovery { @@ -141,7 +143,7 @@ private void GivenThereIsAFakeEurekaServiceDiscoveryProvider(string url, string }, }; - var json = JsonConvert.SerializeObject(applications); + var json = JsonSerializer.Serialize(applications, JsonSerializerOptionsExtensions.Web); context.Response.Headers.Append("Content-Type", "application/json"); await context.Response.WriteAsync(json); } @@ -193,25 +195,25 @@ public FakeEurekaService(string serviceId, string host, int port, bool isSecure, public class Port { - [JsonProperty("$")] + [JsonPropertyName("$")] public int value { get; set; } - [JsonProperty("@enabled")] + [JsonPropertyName("@enabled")] public string enabled { get; set; } } public class SecurePort { - [JsonProperty("$")] + [JsonPropertyName("$")] public int value { get; set; } - [JsonProperty("@enabled")] + [JsonPropertyName("@enabled")] public string enabled { get; set; } } public class DataCenterInfo { - [JsonProperty("@class")] + [JsonPropertyName("@class")] public string value { get; set; } public string name { get; set; } @@ -234,7 +236,7 @@ public class LeaseInfo public class ValueMetadata { - [JsonProperty("@class")] + [JsonPropertyName("@class")] public string value { get; set; } } diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscovery/KubernetesServiceDiscoveryTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscovery/KubernetesServiceDiscoveryTests.cs index 5ca22da6e..2c8a1e226 100644 --- a/test/Ocelot.AcceptanceTests/ServiceDiscovery/KubernetesServiceDiscoveryTests.cs +++ b/test/Ocelot.AcceptanceTests/ServiceDiscovery/KubernetesServiceDiscoveryTests.cs @@ -3,12 +3,13 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using Newtonsoft.Json; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.Provider.Kubernetes; using System.Runtime.CompilerServices; +using System.Text.Json; namespace Ocelot.AcceptanceTests.ServiceDiscovery; @@ -183,7 +184,7 @@ private void GivenThereIsAFakeKubernetesProvider(string serviceName, string name _receivedToken = values.First(); } - var json = JsonConvert.SerializeObject(endpoints); + var json = JsonSerializer.Serialize(endpoints, JsonSerializerOptionsExtensions.Web); context.Response.Headers.Append("Content-Type", "application/json"); await context.Response.WriteAsync(json); } diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index 4591e9b22..552e912ca 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Ocelot.AcceptanceTests.Caching; using Ocelot.Cache.CacheManager; using Ocelot.Configuration; @@ -16,6 +15,7 @@ using Ocelot.Configuration.File; using Ocelot.Configuration.Repository; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.Logging; using Ocelot.Middleware; @@ -29,8 +29,8 @@ using Serilog.Core; using System.IO.Compression; using System.Net.Http.Headers; -using System.Security.Policy; using System.Text; +using System.Text.Json; using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests; using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder; using CookieHeaderValue = Microsoft.Net.Http.Headers.CookieHeaderValue; @@ -58,7 +58,7 @@ public Steps() { _random = new Random(); _testId = Guid.NewGuid(); - _ocelotConfigFileName = $"{_testId:N}-{ConfigurationBuilderExtensions.PrimaryConfigFile}"; + _ocelotConfigFileName = $"{_testId:N}-{ConfigurationBuilderExtensions.PrimaryConfigFile}"; Files = new() { _ocelotConfigFileName }; Folders = new(); } @@ -171,13 +171,13 @@ public async Task StartFakeOcelotWithWebSocketsWithConsul() await _ocelotHost.StartAsync(); } - public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration) + public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration) => GivenThereIsAConfiguration(fileConfiguration, _ocelotConfigFileName); public void GivenThereIsAConfiguration(FileConfiguration from, string toFile) - { + { toFile ??= _ocelotConfigFileName; - var jsonConfiguration = JsonConvert.SerializeObject(from, Formatting.Indented); + var jsonConfiguration = JsonSerializer.Serialize(from, JsonSerializerOptionsExtensions.WebWriteIndented); File.WriteAllText(toFile, jsonConfiguration); Files.Add(toFile); // register for disposing } @@ -214,12 +214,12 @@ protected virtual void DeleteFolders() f.Delete(true); } } - catch (Exception e) - { - Console.WriteLine(e); - } + catch (Exception e) + { + Console.WriteLine(e); + } } - } + } public void ThenTheResponseBodyHeaderIs(string key, string value) { @@ -753,7 +753,7 @@ internal async Task GivenIHaveATokenWithForm(string url, IEnumerabl var response = await httpClient.PostAsync(tokenUrl, content); var responseContent = await response.Content.ReadAsStringAsync(); response.EnsureSuccessStatusCode(); - _token = JsonConvert.DeserializeObject(responseContent); + _token = JsonSerializer.Deserialize(responseContent, JsonSerializerOptionsExtensions.Web); return _token; } @@ -955,7 +955,7 @@ public void GivenThePostHasContentType(string postContent) public void GivenThePostHasGzipContent(object input) { - var json = JsonConvert.SerializeObject(input); + var json = JsonSerializer.Serialize(input, JsonSerializerOptionsExtensions.Web); var jsonBytes = Encoding.UTF8.GetBytes(json); var ms = new MemoryStream(); using (var gzip = new GZipStream(ms, CompressionMode.Compress, true)) diff --git a/test/Ocelot.AcceptanceTests/TwoDownstreamServicesTests.cs b/test/Ocelot.AcceptanceTests/TwoDownstreamServicesTests.cs index d0be68c64..b437738c3 100644 --- a/test/Ocelot.AcceptanceTests/TwoDownstreamServicesTests.cs +++ b/test/Ocelot.AcceptanceTests/TwoDownstreamServicesTests.cs @@ -1,7 +1,8 @@ using Consul; using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; -using Ocelot.Configuration.File; +using Ocelot.Configuration.File; +using Ocelot.Infrastructure; +using System.Text.Json; namespace Ocelot.AcceptanceTests { @@ -96,7 +97,7 @@ private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url) { if (context.Request.Path.Value == "/v1/health/service/product") { - var json = JsonConvert.SerializeObject(_serviceEntries); + var json = JsonSerializer.Serialize(_serviceEntries, JsonSerializerOptionsExtensions.Web); context.Response.Headers.Append("Content-Type", "application/json"); await context.Response.WriteAsync(json); } diff --git a/test/Ocelot.Benchmarks/AllTheThingsBenchmarks.cs b/test/Ocelot.Benchmarks/AllTheThingsBenchmarks.cs index a2ea96445..f9ccffe81 100644 --- a/test/Ocelot.Benchmarks/AllTheThingsBenchmarks.cs +++ b/test/Ocelot.Benchmarks/AllTheThingsBenchmarks.cs @@ -3,10 +3,11 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; -using Ocelot.Middleware; +using Ocelot.Infrastructure; +using Ocelot.Middleware; +using System.Text.Json; namespace Ocelot.Benchmarks { @@ -112,7 +113,7 @@ public static void GivenThereIsAConfiguration(FileConfiguration fileConfiguratio { var configurationPath = Path.Combine(AppContext.BaseDirectory, "ocelot.json"); - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.Web); if (File.Exists(configurationPath)) { diff --git a/test/Ocelot.Benchmarks/JsonSerializerBenchmark.cs b/test/Ocelot.Benchmarks/JsonSerializerBenchmark.cs new file mode 100644 index 000000000..35919a441 --- /dev/null +++ b/test/Ocelot.Benchmarks/JsonSerializerBenchmark.cs @@ -0,0 +1,94 @@ +using BenchmarkDotNet.Jobs; +using Bogus; +using Newtonsoft.Json; +using JsonSerializer = System.Text.Json.JsonSerializer; + +namespace Ocelot.Benchmarks +{ + [SimpleJob(RuntimeMoniker.Net80)] + [Config(typeof(JsonSerializerBenchmark))] + public class JsonSerializerBenchmark : ManualConfig + { + private string _serializedTestUsers; + + private List _testUsers = new(); + + [Params(1000)] + public int Count { get; set; } + + [GlobalSetup] + public void GlobalSetup() + { + Faker faker = new Faker().CustomInstantiator( + f => + new User + { + UserId = Guid.NewGuid(), + FirstName = f.Name.FirstName(), + LastName = f.Name.LastName(), + FullName = f.Name.FullName(), + Username = f.Internet.UserName(f.Name.FirstName(), f.Name.LastName()), + Email = f.Internet.Email(f.Name.FirstName(), f.Name.LastName()) + } + ); + + _testUsers = faker.Generate(Count); + + _serializedTestUsers = JsonSerializer.Serialize(_testUsers); + } + + [Benchmark] + [BenchmarkCategory("Serialize", "Newtonsoft")] + public void NewtonsoftSerializeBigData() + { + _ = JsonConvert.SerializeObject(_testUsers); + } + + [Benchmark] + [BenchmarkCategory("Serialize", "Microsoft")] + public void MicrosoftSerializeBigData() + { + _ = JsonSerializer.Serialize(_testUsers); + } + + [Benchmark] + [BenchmarkCategory("Deserialize", "Newtonsoft")] + public void NewtonsoftDeserializeBigData() + { + _ = JsonConvert.DeserializeObject>(_serializedTestUsers); + } + + [Benchmark] + [BenchmarkCategory("Deserialize", "Microsoft")] + public void MicrosoftDeserializeBigData() + { + _ = JsonSerializer.Deserialize>(_serializedTestUsers); + } + } + + //BenchmarkDotNet v0.13.11, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3) + //Intel Core i7-10870H CPU 2.20GHz, 1 CPU, 16 logical and 8 physical cores + // .NET SDK 8.0.303 + // [Host] : .NET 6.0.32 (6.0.3224.31407), X64 RyuJIT AVX2[AttachedDebugger] + // .NET 8.0 : .NET 8.0.7 (8.0.724.31311), X64 RyuJIT AVX2 + + // Job =.NET 8.0 Runtime=.NET 8.0 + + // | Method | Count | Mean | Error | StdDev | Median | Op/s | Gen0 | Gen1 | Gen2 | Allocated | + // |----------------------------- |------ |-----------:|---------:|----------:|-----------:|--------:|---------:|---------:|---------:|----------:| + // | MicrosoftDeserializeBigData | 1000 | 856.3 us | 53.98 us | 157.47 us | 797.1 us | 1,167.8 | 39.0625 | 13.6719 | - | 328.78 KB | + // | NewtonsoftDeserializeBigData | 1000 | 1,137.2 us | 18.74 us | 17.53 us | 1,132.8 us | 879.4 | 54.6875 | 17.5781 | - | 457.94 KB | + // |==============================================================================================================================================| + // | MicrosoftSerializeBigData | 1000 | 646.4 us | 12.72 us | 20.90 us | 645.7 us | 1,546.9 | 110.3516 | 110.3516 | 110.3516 | 350.02 KB | + // | NewtonsoftSerializeBigData | 1000 | 1,033.4 us | 19.37 us | 42.53 us | 1,022.8 us | 967.7 | 109.3750 | 109.3750 | 109.3750 | 837.82 KB | +} + +public class User +{ + public Guid UserId { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string FullName { get; set; } + public string Username { get; set; } + public string Email { get; set; } +} diff --git a/test/Ocelot.Benchmarks/MsLoggerBenchmarks.cs b/test/Ocelot.Benchmarks/MsLoggerBenchmarks.cs index c54693300..f6847810c 100644 --- a/test/Ocelot.Benchmarks/MsLoggerBenchmarks.cs +++ b/test/Ocelot.Benchmarks/MsLoggerBenchmarks.cs @@ -5,11 +5,12 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.Logging; using Ocelot.Middleware; +using System.Text.Json; namespace Ocelot.Benchmarks; @@ -162,7 +163,7 @@ public static void GivenThereIsAConfiguration(FileConfiguration fileConfiguratio { var configurationPath = Path.Combine(AppContext.BaseDirectory, "ocelot.json"); - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.Web); if (File.Exists(configurationPath)) { diff --git a/test/Ocelot.Benchmarks/Ocelot.Benchmarks.csproj b/test/Ocelot.Benchmarks/Ocelot.Benchmarks.csproj index 288d79019..a8b4273f1 100644 --- a/test/Ocelot.Benchmarks/Ocelot.Benchmarks.csproj +++ b/test/Ocelot.Benchmarks/Ocelot.Benchmarks.csproj @@ -22,9 +22,12 @@ + + all + diff --git a/test/Ocelot.Benchmarks/PayloadBenchmarks.cs b/test/Ocelot.Benchmarks/PayloadBenchmarks.cs index fe776f0ea..de8a9939b 100644 --- a/test/Ocelot.Benchmarks/PayloadBenchmarks.cs +++ b/test/Ocelot.Benchmarks/PayloadBenchmarks.cs @@ -4,14 +4,15 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.Middleware; using System.Diagnostics; using System.Net.Http.Headers; using System.Reflection; using System.Text; +using System.Text.Json; namespace Ocelot.Benchmarks; @@ -112,7 +113,7 @@ private static string GetBaseDirectory() private static object[] GeneratePayload(int size, string directory, string fileName, bool isJson) { var filePath = Path.Combine(directory, fileName); - var generateDummy = isJson ? (Func) GenerateDummyJsonFile : GenerateDummyDatFile; + var generateDummy = isJson ? (Func)GenerateDummyJsonFile : GenerateDummyDatFile; return new object[] { generateDummy(size, filePath), @@ -220,7 +221,7 @@ private void GivenOcelotIsRunning(string url) public static void GivenThereIsAConfiguration(FileConfiguration fileConfiguration) { var configurationPath = Path.Combine(AppContext.BaseDirectory, ConfigurationBuilderExtensions.PrimaryConfigFile); - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.Web); if (File.Exists(configurationPath)) { diff --git a/test/Ocelot.Benchmarks/Program.cs b/test/Ocelot.Benchmarks/Program.cs index bea66ff17..689d1fea6 100644 --- a/test/Ocelot.Benchmarks/Program.cs +++ b/test/Ocelot.Benchmarks/Program.cs @@ -17,7 +17,15 @@ public static void Main(string[] args) typeof(MsLoggerBenchmarks), typeof(PayloadBenchmarks), typeof(ResponseBenchmarks), + typeof(JsonSerializerBenchmark), }); - switcher.Run(args); + + var config = ManualConfig.Create(DefaultConfig.Instance) + .AddAnalyser(BenchmarkDotNet.Analysers.EnvironmentAnalyser.Default) + .AddExporter(BenchmarkDotNet.Exporters.MarkdownExporter.GitHub) + .AddDiagnoser(BenchmarkDotNet.Diagnosers.MemoryDiagnoser.Default) + .AddColumn(StatisticColumn.OperationsPerSecond); + + switcher.Run(args, config); } } diff --git a/test/Ocelot.Benchmarks/ResponseBenchmarks.cs b/test/Ocelot.Benchmarks/ResponseBenchmarks.cs index a7c1d85b7..1bc33f09f 100644 --- a/test/Ocelot.Benchmarks/ResponseBenchmarks.cs +++ b/test/Ocelot.Benchmarks/ResponseBenchmarks.cs @@ -4,15 +4,15 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.Middleware; using System.Diagnostics; using System.Net.Http.Headers; using System.Reflection; using System.Text; -using Ocelot.Responses; +using System.Text.Json; namespace Ocelot.Benchmarks; @@ -222,7 +222,7 @@ private void GivenOcelotIsRunning(string url) public static void GivenThereIsAConfiguration(FileConfiguration fileConfiguration) { var configurationPath = Path.Combine(AppContext.BaseDirectory, ConfigurationBuilderExtensions.PrimaryConfigFile); - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.Web); if (File.Exists(configurationPath)) { diff --git a/test/Ocelot.Benchmarks/SerilogBenchmarks.cs b/test/Ocelot.Benchmarks/SerilogBenchmarks.cs index f3af7e814..35ea904ab 100644 --- a/test/Ocelot.Benchmarks/SerilogBenchmarks.cs +++ b/test/Ocelot.Benchmarks/SerilogBenchmarks.cs @@ -5,13 +5,14 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.Logging; using Ocelot.Middleware; using Serilog; using Serilog.Core; +using System.Text.Json; namespace Ocelot.Benchmarks; @@ -193,7 +194,7 @@ public static void GivenThereIsAConfiguration(FileConfiguration fileConfiguratio { var configurationPath = Path.Combine(AppContext.BaseDirectory, "ocelot.json"); - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.Web); if (File.Exists(configurationPath)) { diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index 5ae8d0819..db1650af9 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -8,16 +8,17 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.IdentityModel.Tokens; -using Newtonsoft.Json; using Ocelot.Administration; using Ocelot.Cache; using Ocelot.Configuration.ChangeTracking; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.Middleware; using System.Net; using System.Net.Http.Headers; using System.Reflection; +using System.Text.Json; namespace Ocelot.IntegrationTests { @@ -346,12 +347,12 @@ private static void ThenTheConfigurationIsSavedCorrectly(FileConfiguration expec { var ocelotJsonPath = $"{AppContext.BaseDirectory}ocelot.json"; var resultText = File.ReadAllText(ocelotJsonPath); - var expectedText = JsonConvert.SerializeObject(expected, Formatting.Indented); + var expectedText = JsonSerializer.Serialize(expected, JsonSerializerOptionsExtensions.WebWriteIndented); resultText.ShouldBe(expectedText); var environmentSpecificPath = $"{AppContext.BaseDirectory}/ocelot.Production.json"; resultText = File.ReadAllText(environmentSpecificPath); - expectedText = JsonConvert.SerializeObject(expected, Formatting.Indented); + expectedText = JsonSerializer.Serialize(expected, JsonSerializerOptionsExtensions.WebWriteIndented); resultText.ShouldBe(expectedText); } @@ -532,7 +533,7 @@ private void GivenIHaveAToken(string url) var response = httpClient.PostAsync($"{url}/connect/token", content).Result; var responseContent = response.Content.ReadAsStringAsync().Result; response.EnsureSuccessStatusCode(); - _token = JsonConvert.DeserializeObject(responseContent); + _token = JsonSerializer.Deserialize(responseContent, JsonSerializerOptionsExtensions.Web); } private void GivenThereIsAnIdentityServerOn(string url, string apiName) @@ -649,7 +650,7 @@ private void WhenIGetUrlOnTheSecondOcelot(string url) private void WhenIPostOnTheApiGateway(string url, FileConfiguration updatedConfiguration) { - var json = JsonConvert.SerializeObject(updatedConfiguration); + var json = JsonSerializer.Serialize(updatedConfiguration, JsonSerializerOptionsExtensions.Web); var content = new StringContent(json); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); _response = _httpClient.PostAsync(url, content).Result; @@ -658,7 +659,7 @@ private void WhenIPostOnTheApiGateway(string url, FileConfiguration updatedConfi private void ThenTheResponseShouldBe(List expected) { var content = _response.Content.ReadAsStringAsync().Result; - var result = JsonConvert.DeserializeObject(content); + var result = JsonSerializer.Deserialize(content, JsonSerializerOptionsExtensions.Web); result.Value.ShouldBe(expected); } @@ -670,7 +671,7 @@ private void ThenTheResponseBodyShouldBe(string expected) private void ThenTheResponseShouldBe(FileConfiguration expecteds) { - var response = JsonConvert.DeserializeObject(_response.Content.ReadAsStringAsync().Result); + var response = JsonSerializer.Deserialize(_response.Content.ReadAsStringAsync().Result, JsonSerializerOptionsExtensions.Web); response.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey); response.GlobalConfiguration.ServiceDiscoveryProvider.Scheme.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Scheme); @@ -714,7 +715,7 @@ private void GivenIHaveAnOcelotToken(string adminPath) var response = _httpClient.PostAsync(tokenUrl, content).Result; var responseContent = response.Content.ReadAsStringAsync().Result; response.EnsureSuccessStatusCode(); - _token = JsonConvert.DeserializeObject(responseContent); + _token = JsonSerializer.Deserialize(responseContent, JsonSerializerOptionsExtensions.Web); var configPath = $"{adminPath}/.well-known/openid-configuration"; response = _httpClient.GetAsync(configPath).Result; response.EnsureSuccessStatusCode(); @@ -841,7 +842,7 @@ private static void GivenThereIsAConfiguration(FileConfiguration fileConfigurati { var configurationPath = $"{Directory.GetCurrentDirectory()}/ocelot.json"; - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.Web); if (File.Exists(configurationPath)) { diff --git a/test/Ocelot.IntegrationTests/BearerToken.cs b/test/Ocelot.IntegrationTests/BearerToken.cs index 836d72c7b..9b0a813ea 100644 --- a/test/Ocelot.IntegrationTests/BearerToken.cs +++ b/test/Ocelot.IntegrationTests/BearerToken.cs @@ -1,16 +1,18 @@ -using Newtonsoft.Json; + + +using System.Text.Json.Serialization; namespace Ocelot.IntegrationTests { internal class BearerToken { - [JsonProperty("access_token")] + [JsonPropertyName("access_token")] public string AccessToken { get; set; } - [JsonProperty("expires_in")] + [JsonPropertyName("expires_in")] public int ExpiresIn { get; set; } - [JsonProperty("token_type")] + [JsonPropertyName("token_type")] public string TokenType { get; set; } } } diff --git a/test/Ocelot.IntegrationTests/CacheManagerTests.cs b/test/Ocelot.IntegrationTests/CacheManagerTests.cs index 6af698854..dd1c33159 100644 --- a/test/Ocelot.IntegrationTests/CacheManagerTests.cs +++ b/test/Ocelot.IntegrationTests/CacheManagerTests.cs @@ -3,14 +3,15 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Newtonsoft.Json; using Ocelot.Administration; using Ocelot.Cache.CacheManager; using Ocelot.Configuration.File; -using Ocelot.DependencyInjection; +using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.Middleware; using System.Net; -using System.Net.Http.Headers; +using System.Net.Http.Headers; +using System.Text.Json; namespace Ocelot.IntegrationTests { @@ -112,7 +113,7 @@ private void GivenIHaveAnOcelotToken(string adminPath) var response = _httpClient.PostAsync(tokenUrl, content).Result; var responseContent = response.Content.ReadAsStringAsync().Result; response.EnsureSuccessStatusCode(); - _token = JsonConvert.DeserializeObject(responseContent); + _token = JsonSerializer.Deserialize(responseContent, JsonSerializerOptionsExtensions.Web); var configPath = $"{adminPath}/.well-known/openid-configuration"; response = _httpClient.GetAsync(configPath).Result; response.EnsureSuccessStatusCode(); @@ -165,7 +166,7 @@ private static void GivenThereIsAConfiguration(FileConfiguration fileConfigurati { var configurationPath = $"{Directory.GetCurrentDirectory()}/ocelot.json"; - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.Web); if (File.Exists(configurationPath)) { diff --git a/test/Ocelot.IntegrationTests/HeaderTests.cs b/test/Ocelot.IntegrationTests/HeaderTests.cs index 9072f3189..aa2704812 100644 --- a/test/Ocelot.IntegrationTests/HeaderTests.cs +++ b/test/Ocelot.IntegrationTests/HeaderTests.cs @@ -2,11 +2,12 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; -using Newtonsoft.Json; using Ocelot.Configuration.File; -using Ocelot.DependencyInjection; +using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.Middleware; -using System.Net; +using System.Net; +using System.Text.Json; [assembly: CollectionBehavior(DisableTestParallelization = true)] @@ -130,7 +131,7 @@ private static void GivenThereIsAConfiguration(FileConfiguration fileConfigurati { var configurationPath = $"{Directory.GetCurrentDirectory()}/ocelot.json"; - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.Web); if (File.Exists(configurationPath)) { diff --git a/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs b/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs index 48eac3686..a7b2bd849 100644 --- a/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs +++ b/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs @@ -2,11 +2,12 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; -using Newtonsoft.Json; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using Ocelot.Middleware; using System.Collections.Concurrent; +using System.Text.Json; namespace Ocelot.IntegrationTests { @@ -119,7 +120,7 @@ private static void GivenThereIsAConfiguration(FileConfiguration fileConfigurati { var configurationPath = $"{Directory.GetCurrentDirectory()}/ocelot.json"; - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.Web); if (File.Exists(configurationPath)) { diff --git a/test/Ocelot.IntegrationTests/ocelot.json b/test/Ocelot.IntegrationTests/ocelot.json index 39b71c1bb..fdfcbaeef 100644 --- a/test/Ocelot.IntegrationTests/ocelot.json +++ b/test/Ocelot.IntegrationTests/ocelot.json @@ -33,7 +33,7 @@ "ClientWhitelist": [], "EnableRateLimiting": false, "Period": null, - "PeriodTimespan": 0.0, + "PeriodTimespan": 0, "Limit": 0 } } diff --git a/test/Ocelot.ManualTest/CustomOcelotMiddleware.cs b/test/Ocelot.ManualTest/CustomOcelotMiddleware.cs index f3d251887..cf5f70163 100644 --- a/test/Ocelot.ManualTest/CustomOcelotMiddleware.cs +++ b/test/Ocelot.ManualTest/CustomOcelotMiddleware.cs @@ -1,4 +1,5 @@ -using Ocelot.Logging; +using Ocelot.Infrastructure; +using Ocelot.Logging; using Ocelot.Middleware; using System.Text.Json; using System.Threading.Tasks; @@ -16,7 +17,7 @@ public static Task Invoke(HttpContext context, Func next) { logger.LogInformation(() => { - var metadataInJson = JsonSerializer.Serialize(metadata); + var metadataInJson = JsonSerializer.Serialize(metadata, JsonSerializerOptionsExtensions.Web); var message = $"My custom middleware found some metadata: {metadataInJson}"; return message; }); diff --git a/test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs index eea4ee955..f0332ae01 100644 --- a/test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs @@ -1,10 +1,11 @@ using Microsoft.AspNetCore.Hosting; -using Newtonsoft.Json; using Ocelot.Configuration.ChangeTracking; using Ocelot.Configuration.File; using Ocelot.Configuration.Repository; -using Ocelot.DependencyInjection; -using System.Runtime.CompilerServices; +using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; +using System.Runtime.CompilerServices; +using System.Text.Json; namespace Ocelot.UnitTests.Configuration { @@ -155,14 +156,14 @@ private void ThenTheConfigurationIsStoredAs(FileConfiguration expecteds) private void ThenTheOcelotJsonIsStoredAs(FileInfo ocelotJson, FileConfiguration expecteds) { var actual = File.ReadAllText(ocelotJson.FullName); - var expectedText = JsonConvert.SerializeObject(expecteds, Formatting.Indented); + var expectedText = JsonSerializer.Serialize(expecteds, JsonSerializerOptionsExtensions.WebWriteIndented); actual.ShouldBe(expectedText); } private void GivenTheConfigurationIs(FileConfiguration fileConfiguration, [CallerMemberName] string environmentName = null) { var environmentSpecificPath = Path.Combine(TestID, string.Format(ConfigurationBuilderExtensions.EnvironmentConfigFile, environmentName)); - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented); + var jsonConfiguration = JsonSerializer.Serialize(fileConfiguration, JsonSerializerOptionsExtensions.WebWriteIndented); var environmentSpecific = new FileInfo(environmentSpecificPath); if (environmentSpecific.Exists) { @@ -177,7 +178,7 @@ private void ThenTheConfigurationJsonIsIndented(FileConfiguration expecteds, [Ca { var environmentSpecific = Path.Combine(TestID, string.Format(ConfigurationBuilderExtensions.EnvironmentConfigFile, environmentName)); var actual = File.ReadAllText(environmentSpecific); - var expectedText = JsonConvert.SerializeObject(expecteds, Formatting.Indented); + var expectedText = JsonSerializer.Serialize(expecteds, JsonSerializerOptionsExtensions.WebWriteIndented); actual.ShouldBe(expectedText); _files.Add(environmentSpecific); } diff --git a/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs index 0f8eaf192..1044ffcab 100644 --- a/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs @@ -1,13 +1,14 @@ using Consul; using Microsoft.Extensions.Options; -using Newtonsoft.Json; using Ocelot.Cache; -using Ocelot.Configuration.File; +using Ocelot.Configuration.File; +using Ocelot.Infrastructure; using Ocelot.Logging; using Ocelot.Provider.Consul; using Ocelot.Provider.Consul.Interfaces; using Ocelot.Responses; -using System.Text; +using System.Text; +using System.Text.Json; namespace Ocelot.UnitTests.Consul { @@ -139,8 +140,8 @@ private void ThenTheConfigurationIsNull() private void ThenTheConfigurationIs(FileConfiguration config) { - var expected = JsonConvert.SerializeObject(config, Formatting.Indented); - var result = JsonConvert.SerializeObject(_getResult.Data, Formatting.Indented); + var expected = JsonSerializer.Serialize(config, JsonSerializerOptionsExtensions.WebWriteIndented); + var result = JsonSerializer.Serialize(_getResult.Data, JsonSerializerOptionsExtensions.WebWriteIndented); result.ShouldBe(expected); } @@ -176,7 +177,7 @@ private void GivenFetchFromConsulReturnsNull() private void GivenFetchFromConsulSucceeds() { - var json = JsonConvert.SerializeObject(_fileConfiguration, Formatting.Indented); + var json = JsonSerializer.Serialize(_fileConfiguration, JsonSerializerOptionsExtensions.WebWriteIndented); var bytes = Encoding.UTF8.GetBytes(json); @@ -197,7 +198,7 @@ private void GivenFetchFromConsulSucceeds() private void ThenTheConfigurationIsStoredAs(FileConfiguration config) { - var json = JsonConvert.SerializeObject(config, Formatting.Indented); + var json = JsonSerializer.Serialize(config, JsonSerializerOptionsExtensions.WebWriteIndented); var bytes = Encoding.UTF8.GetBytes(json); diff --git a/test/Ocelot.UnitTests/Consul/ConsulTests.cs b/test/Ocelot.UnitTests/Consul/ConsulTests.cs index b9009d488..4afb29156 100644 --- a/test/Ocelot.UnitTests/Consul/ConsulTests.cs +++ b/test/Ocelot.UnitTests/Consul/ConsulTests.cs @@ -2,11 +2,12 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; +using Ocelot.Infrastructure; using Ocelot.Logging; using Ocelot.Provider.Consul; using Ocelot.Provider.Consul.Interfaces; using System.Runtime.CompilerServices; +using System.Text.Json; using ConsulProvider = Ocelot.Provider.Consul.Consul; namespace Ocelot.UnitTests.Consul; @@ -197,7 +198,7 @@ private void GivenThereIsAFakeConsulServiceDiscoveryProvider([CallerMemberName] _receivedToken = values.First(); } - var json = JsonConvert.SerializeObject(_consulServiceEntries); + var json = JsonSerializer.Serialize(_consulServiceEntries, JsonSerializerOptionsExtensions.Web); context.Response.Headers.Append("Content-Type", "application/json"); await context.Response.WriteAsync(json); } diff --git a/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs b/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs index caa8dfefd..578a7fe79 100644 --- a/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs +++ b/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs @@ -1,10 +1,11 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.VisualStudio.TestPlatform.ObjectModel; -using Newtonsoft.Json; using Ocelot.Configuration.File; using Ocelot.DependencyInjection; +using Ocelot.Infrastructure; using System.Runtime.CompilerServices; +using System.Text.Json; namespace Ocelot.UnitTests.DependencyInjection { @@ -188,7 +189,7 @@ private void GivenMultipleConfigurationFiles(string folder, bool withEnvironment foreach (var part in configParts) { var filename = Path.Combine(folder, string.Format(ConfigurationBuilderExtensions.EnvironmentConfigFile, part.Key)); - File.WriteAllText(filename, JsonConvert.SerializeObject(part.Value, Formatting.Indented)); + File.WriteAllText(filename, JsonSerializer.Serialize(part.Value, JsonSerializerOptionsExtensions.WebWriteIndented)); _files.Add(filename); } } diff --git a/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs b/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs index 262014927..f99214a36 100644 --- a/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs +++ b/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs @@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -259,16 +258,10 @@ private void CstorShouldUseDefaultBuilderToInitMvcCoreBuilder() .ShouldNotBeNull() .GetType().Name.ShouldBe("AuthorizationApplicationModelProvider"); - // .AddNewtonsoftJson() - _serviceProvider.GetServices>() - .FirstOrDefault(s => s.GetType().Name == "NewtonsoftJsonMvcOptionsSetup") + // use system text json + _serviceProvider.GetServices>() + .FirstOrDefault(s => s.GetType().Name == "SystemTextJsonResultExecutor") .ShouldNotBeNull(); - _serviceProvider.GetService>() - .ShouldNotBeNull() - .GetType().Name.ShouldBe("NewtonsoftJsonResultExecutor"); - _serviceProvider.GetService() - .ShouldNotBeNull() - .GetType().Name.ShouldBe("NewtonsoftJsonHelper"); } [Fact] diff --git a/test/Ocelot.UnitTests/Kubernetes/KubeTests.cs b/test/Ocelot.UnitTests/Kubernetes/KubeTests.cs index 213a25f65..23e663f84 100644 --- a/test/Ocelot.UnitTests/Kubernetes/KubeTests.cs +++ b/test/Ocelot.UnitTests/Kubernetes/KubeTests.cs @@ -3,11 +3,12 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; +using Ocelot.Infrastructure; using Ocelot.Logging; using Ocelot.Provider.Kubernetes; using Ocelot.Provider.Kubernetes.Interfaces; using Ocelot.Values; +using System.Text.Json; namespace Ocelot.UnitTests.Kubernetes { @@ -136,7 +137,7 @@ private void GivenThereIsAFakeKubeServiceDiscoveryProvider(string url, string se _receivedToken = values.First(); } - var json = JsonConvert.SerializeObject(_endpointEntries); + var json = JsonSerializer.Serialize(_endpointEntries, JsonSerializerOptionsExtensions.Web); context.Response.Headers.Append("Content-Type", "application/json"); await context.Response.WriteAsync(json); } diff --git a/test/Ocelot.UnitTests/Requester/MessageInvokerPoolTests.cs b/test/Ocelot.UnitTests/Requester/MessageInvokerPoolTests.cs index 57e3b803a..ce5b934cb 100644 --- a/test/Ocelot.UnitTests/Requester/MessageInvokerPoolTests.cs +++ b/test/Ocelot.UnitTests/Requester/MessageInvokerPoolTests.cs @@ -73,7 +73,7 @@ public void If_two_delegating_handlers_are_defined_then_these_should_be_call_in_ .And(x => GivenADownstreamRoute("/super-test")) .And(x => GivenAMessageInvokerPool()) .And(x => GivenARequest()) - .When(x => WhenICallTheClient("http://www.bbc.co.uk")) + .When(x => WhenICallTheClient("https://www.google.com")) .Then(x => ThenTheFakeAreHandledInOrder(fakeOne, fakeTwo)) .And(x => ThenSomethingIsReturned()) .BDDfy(); @@ -97,7 +97,7 @@ public void Should_log_if_ignoring_ssl_errors() this.Given(x => GivenTheFactoryReturns(new List>())) .And(x => GivenAMessageInvokerPool()) .And(x => GivenARequest(route)) - .When(x => WhenICallTheClient("http://www.bbc.co.uk")) + .When(x => WhenICallTheClient("https://www.google.com")) .Then(x => ThenTheDangerousAcceptAnyServerCertificateValidatorWarningIsLogged()) .BDDfy(); } @@ -259,7 +259,7 @@ private void GivenARequestWithAUrlAndMethod(DownstreamRoute downstream, string u _context = new DefaultHttpContext(); _context.Items.UpsertDownstreamRoute(downstream); _context.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage - { RequestUri = new Uri(url), Method = method })); + { RequestUri = new Uri(url), Method = method })); } private void ThenSomethingIsReturned() => _response.ShouldNotBeNull();