From b53cf08567f2f76359615b77e6a5dd935ed43701 Mon Sep 17 00:00:00 2001 From: Nick Craver Date: Wed, 2 Aug 2023 18:18:03 -0400 Subject: [PATCH] Project files: cleanup/normalization (#641) General project file cleanup and normalization. Also adding GitHub Actions enhanced logging for test results. --- .editorconfig | 7 ++- .github/workflows/main.yml | 10 ++++- .../Benchmarks/CustomTimingBenchmarks.cs | 2 +- .../Benchmarks/DictionaryBenchmarks.cs | 2 +- .../Benchmarks/JSONLibBenchmarks.cs | 44 +++++++++---------- .../Benchmarks/MiniProfilerBenchmarks.cs | 2 +- .../Benchmarks/SerializationBenchmarks.cs | 2 +- .../Benchmarks/StackTraceSnippetBenchmarks.cs | 2 +- .../MiniProfiler.Benchmarks.csproj | 14 +++--- samples/Misc/Misc.csproj | 2 +- samples/Samples.AspNet/Samples.AspNet.csproj | 6 ++- .../Samples.Console/Samples.Console.csproj | 16 ++++--- .../Samples.ConsoleCore.csproj | 4 +- .../Samples.Mvc5.EFCore.csproj | 43 ++++++------------ samples/Samples.Mvc5/Samples.Mvc5.csproj | 43 ++++++------------ .../MiniProfiler.AspNetCore.Mvc.csproj | 5 ++- .../MvcDiagnosticListener.cs | 2 +- .../MiniProfiler.AspNetCore.csproj | 5 ++- src/MiniProfiler.EF6/MiniProfiler.EF6.csproj | 4 +- .../MiniProfiler.EFC7.csproj | 4 +- .../MiniProfiler.EntityFrameworkCore.csproj | 4 +- .../RelationalDiagnosticListener.cs | 2 +- .../MiniProfiler.Minimal.csproj | 8 ++-- .../MiniProfiler.Mvc5.csproj | 7 ++- .../MiniProfiler.Providers.MongoDB.csproj | 4 +- .../MiniProfiler.Providers.MySql.csproj | 4 +- .../MiniProfiler.Providers.PostgreSql.csproj | 4 +- .../MiniProfiler.Providers.RavenDB.csproj | 4 +- .../MiniProfiler.Providers.Redis.csproj | 6 ++- .../MiniProfiler.Providers.SqlServer.csproj | 4 +- .../MiniProfiler.Providers.SqlServerCe.csproj | 4 +- .../MiniProfiler.Providers.Sqlite.csproj | 4 +- .../Data/ProfiledDbCommand.cs | 12 ++--- .../Data/ProfiledDbConnection.cs | 6 ++- .../Data/ProfiledDbDataAdapter.cs | 8 ++-- .../Data/ProfiledDbDataReader.cs | 6 +-- .../Data/ProfiledDbProviderFactory.cs | 25 +++++------ .../Data/SimpleProfiledCommand.cs | 7 +-- .../Data/SimpleProfiledConnection.cs | 2 + .../Data/SimpleProfiledDataReader.cs | 6 +-- .../Helpers/ProfilerSortedKey.cs | 6 +-- .../Helpers/StackTraceSnippet.cs | 24 +++++----- .../Internal/ExtensionMethods.cs | 44 +++++++++++++++++-- .../Internal/IDataParameterExtensions.cs | 2 +- .../IMiniProfilerDiagnosticListener.cs | 2 +- .../Internal/MiniProfilerBaseOptions.cs | 2 +- .../Internal/ResultRequest.cs | 18 ++++++-- src/MiniProfiler.Shared/JSONHacks.cs | 9 ++++ .../MiniProfiler.Shared.csproj | 20 +++++++-- src/MiniProfiler.Shared/MiniProfiler.cs | 11 +++-- .../VerboseSqlServerFormatter.cs | 10 ++--- src/MiniProfiler.Shared/SqlTimingParameter.cs | 2 +- src/MiniProfiler.Shared/Timing.cs | 12 ++++- src/MiniProfiler.Shared/TimingDebugInfo.cs | 4 +- src/MiniProfiler/MiniProfiler.csproj | 4 +- tests/Directory.Build.props | 1 + .../MiniProfiler.Tests.AspNet.csproj | 16 ++++--- .../MiniProfiler.Tests.AspNetCore.csproj | 4 +- .../MiniProfiler.Tests.csproj | 12 +++-- .../TimingInstrumentationTest.cs | 10 +++-- 60 files changed, 340 insertions(+), 219 deletions(-) create mode 100644 src/MiniProfiler.Shared/JSONHacks.cs diff --git a/.editorconfig b/.editorconfig index b28189639..b107d7a69 100644 --- a/.editorconfig +++ b/.editorconfig @@ -89,4 +89,9 @@ dotnet_diagnostic.IDE0079.severity = none dotnet_diagnostic.IDE0090.severity = silent # CA1822: Don't run for benchmarks and such -dotnet_code_quality.CA1822.api_surface = private, internal \ No newline at end of file +dotnet_code_quality.CA1822.api_surface = private, internal + +# IDE0056: Use index operator +csharp_style_prefer_index_operator = false +# IDE0057: Use range operator +csharp_style_prefer_range_operator = false diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f022aab9e..00996cc88 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -62,7 +62,7 @@ jobs: - name: .NET Build run: dotnet build Build.csproj -c Release /p:CI=true - name: .NET Test - run: dotnet test Build.csproj -c Release --no-build /p:CI=true + run: dotnet test Build.csproj -c Release --no-build --logger trx --logger GitHubActions --results-directory ./test-results/ /p:CI=true env: EnableTestLogging: true RedisConnectionString: localhost:${{ job.services.redis.ports[6379] }} @@ -72,5 +72,13 @@ jobs: RavenDbUrls: http://localhost:${{ job.services.ravendb.ports[8080] }} RavenDatabase: test SQLServerConnectionString: Server=tcp:127.0.0.1,${{ job.services.sqlserver.ports[1433] }};Database=tempdb;User Id=sa;Password=g0d4mm!tSQLServer; + - name: .NET Test Results + uses: dorny/test-reporter@v1 + continue-on-error: true + if: success() || failure() + with: + name: .NET Test Results + path: 'test-results/*.trx' + reporter: dotnet-trx - name: .NET Lib Pack run: dotnet pack Build.csproj --no-build -c Release /p:PackageOutputPath=%CD%\.nupkgs /p:CI=true diff --git a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/CustomTimingBenchmarks.cs b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/CustomTimingBenchmarks.cs index 698edf2b0..c8c035df9 100644 --- a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/CustomTimingBenchmarks.cs +++ b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/CustomTimingBenchmarks.cs @@ -5,7 +5,7 @@ namespace Benchmarks { [SimpleJob(RuntimeMoniker.Net472, invocationCount: 50_000)] - [SimpleJob(RuntimeMoniker.Net50, invocationCount: 50_000)] + [SimpleJob(RuntimeMoniker.Net60, invocationCount: 50_000)] [Config(typeof(Configs.Memory))] public class CustomTimingBenchmarks { diff --git a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/DictionaryBenchmarks.cs b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/DictionaryBenchmarks.cs index abb592a2c..a7a94b5f2 100644 --- a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/DictionaryBenchmarks.cs +++ b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/DictionaryBenchmarks.cs @@ -7,7 +7,7 @@ namespace Benchmarks.Benchmarks { [SimpleJob(RuntimeMoniker.Net472)] - [SimpleJob(RuntimeMoniker.Net50)] + [SimpleJob(RuntimeMoniker.Net60)] [Config(typeof(Configs.Memory))] public class DictionaryBenchmarks { diff --git a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/JSONLibBenchmarks.cs b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/JSONLibBenchmarks.cs index c15efa66a..db317aa39 100644 --- a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/JSONLibBenchmarks.cs +++ b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/JSONLibBenchmarks.cs @@ -9,7 +9,7 @@ namespace Benchmarks { [SimpleJob(RuntimeMoniker.Net472)] - [SimpleJob(RuntimeMoniker.Net50)] + [SimpleJob(RuntimeMoniker.Net60)] [Config(typeof(Configs.Memory))] public class JSONLibBenchmarks { @@ -29,38 +29,38 @@ static JSONLibBenchmarks() [Benchmark(Description = "Serialize: Simple MiniProfiler (Newtonsoft)")] public string SimpleSerializeNewtonsoft() => JsonConvert.SerializeObject(_simpleProfiler); - - [Benchmark(Description = "Serialize: Simple MiniProfiler (Jil)")] - public string SimpleSerializeJil() => JSON.Serialize(_simpleProfiler, JilOptions); - - [Benchmark(Description = "Serialize: Simple MiniProfiler (ServiceStack)")] - public string SimpleSerializeServiceStack() => ServiceStack.Text.JsonSerializer.SerializeToString(_simpleProfiler); - [Benchmark(Description = "Serialize: Complex MiniProfiler (Newtonsoft)")] public string ComplexSerializeNewtonsoft() => JsonConvert.SerializeObject(_complexProfiler); - - [Benchmark(Description = "Serialize: Complex MiniProfiler (Jil)")] - public string ComplexSerializeJil() => JSON.Serialize(_complexProfiler, JilOptions); - - [Benchmark(Description = "Serialize: Complex MiniProfiler (ServiceStack)")] - public string ComplexSerializeServiceStack() => ServiceStack.Text.JsonSerializer.SerializeToString(_complexProfiler); - [Benchmark(Description = "Deserialize: Simple MiniProfiler (Newtonsoft)")] public MiniProfiler? SimpleDeserializeNewtonsoft() => JsonConvert.DeserializeObject(_simpleProfilerJson); - - [Benchmark(Description = "Deserialize: Simple MiniProfiler (Jil)")] - public MiniProfiler SimpleDeserializeBuiltIn() => JSON.Deserialize(_simpleProfilerJson, JilOptions); - - [Benchmark(Description = "Deserialize: Simple MiniProfiler (ServiceStack)")] - public MiniProfiler SimpleDeserializeServiceStack() => ServiceStack.Text.JsonSerializer.DeserializeFromString(_simpleProfilerJson); - [Benchmark(Description = "Deserialize: Complex MiniProfiler (Newtonsoft)")] public MiniProfiler? ComplexDeserializeNewtonsoft() => JsonConvert.DeserializeObject(_complexProfilerJson); + [Benchmark(Description = "Serialize: Simple MiniProfiler (Jil)")] + public string SimpleSerializeJil() => JSON.Serialize(_simpleProfiler, JilOptions); + [Benchmark(Description = "Serialize: Complex MiniProfiler (Jil)")] + public string ComplexSerializeJil() => JSON.Serialize(_complexProfiler, JilOptions); + [Benchmark(Description = "Deserialize: Simple MiniProfiler (Jil)")] + public MiniProfiler SimpleDeserializeBuiltIn() => JSON.Deserialize(_simpleProfilerJson, JilOptions); [Benchmark(Description = "Deserialize: Complex MiniProfiler (Jil)")] public MiniProfiler ComplexDeserializeBuiltIn() => JSON.Deserialize(_complexProfilerJson, JilOptions); + [Benchmark(Description = "Serialize: Simple MiniProfiler (ServiceStack)")] + public string SimpleSerializeServiceStack() => ServiceStack.Text.JsonSerializer.SerializeToString(_simpleProfiler); + [Benchmark(Description = "Serialize: Complex MiniProfiler (ServiceStack)")] + public string ComplexSerializeServiceStack() => ServiceStack.Text.JsonSerializer.SerializeToString(_complexProfiler); + [Benchmark(Description = "Deserialize: Simple MiniProfiler (ServiceStack)")] + public MiniProfiler SimpleDeserializeServiceStack() => ServiceStack.Text.JsonSerializer.DeserializeFromString(_simpleProfilerJson); [Benchmark(Description = "Deserialize: Complex MiniProfiler (ServiceStack)")] public MiniProfiler ComplexDeserializeServiceStack() => ServiceStack.Text.JsonSerializer.DeserializeFromString(_complexProfilerJson); + + [Benchmark(Description = "Serialize: Simple MiniProfiler (System.Text.Json)")] + public string SimpleSerializeSystemTextJson() => System.Text.Json.JsonSerializer.Serialize(_simpleProfiler); + [Benchmark(Description = "Serialize: Complex MiniProfiler (System.Text.Json)")] + public string ComplexSerializeSystemTextJson() => System.Text.Json.JsonSerializer.Serialize(_complexProfiler); + [Benchmark(Description = "Deserialize: Simple MiniProfiler (System.Text.Json)")] + public MiniProfiler? SimpleDeserializeSystemTextJson() => System.Text.Json.JsonSerializer.Deserialize(_simpleProfilerJson); + [Benchmark(Description = "Deserialize: Complex MiniProfiler (System.Text.Json)")] + public MiniProfiler? ComplexDeserializeSystemTextJson() => System.Text.Json.JsonSerializer.Deserialize(_complexProfilerJson); } } diff --git a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/MiniProfilerBenchmarks.cs b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/MiniProfilerBenchmarks.cs index 8fbc80f8a..6892420ba 100644 --- a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/MiniProfilerBenchmarks.cs +++ b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/MiniProfilerBenchmarks.cs @@ -5,7 +5,7 @@ namespace Benchmarks { [SimpleJob(RuntimeMoniker.Net472)] - [SimpleJob(RuntimeMoniker.Net50)] + [SimpleJob(RuntimeMoniker.Net60)] [Config(typeof(Configs.Memory))] public class MiniProfilerBenchmarks { diff --git a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/SerializationBenchmarks.cs b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/SerializationBenchmarks.cs index 1bc4ae9d2..2cf779577 100644 --- a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/SerializationBenchmarks.cs +++ b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/SerializationBenchmarks.cs @@ -6,7 +6,7 @@ namespace Benchmarks { [SimpleJob(RuntimeMoniker.Net472)] - [SimpleJob(RuntimeMoniker.Net50)] + [SimpleJob(RuntimeMoniker.Net60)] [Config(typeof(Configs.Memory))] public class SerializationBenchmarks { diff --git a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/StackTraceSnippetBenchmarks.cs b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/StackTraceSnippetBenchmarks.cs index 49a9b15f2..c1dde6a3e 100644 --- a/benchmarks/MiniProfiler.Benchmarks/Benchmarks/StackTraceSnippetBenchmarks.cs +++ b/benchmarks/MiniProfiler.Benchmarks/Benchmarks/StackTraceSnippetBenchmarks.cs @@ -5,7 +5,7 @@ namespace Benchmarks { [SimpleJob(RuntimeMoniker.Net472)] - [SimpleJob(RuntimeMoniker.Net50)] + [SimpleJob(RuntimeMoniker.Net60)] [Config(typeof(Configs.Full))] public class StackTraceSnippetBenchmarks { diff --git a/benchmarks/MiniProfiler.Benchmarks/MiniProfiler.Benchmarks.csproj b/benchmarks/MiniProfiler.Benchmarks/MiniProfiler.Benchmarks.csproj index 94eeec210..e0d88fbcd 100644 --- a/benchmarks/MiniProfiler.Benchmarks/MiniProfiler.Benchmarks.csproj +++ b/benchmarks/MiniProfiler.Benchmarks/MiniProfiler.Benchmarks.csproj @@ -8,22 +8,20 @@ net472;net6.0 AnyCPU false - 9 + - - + + - + - - + - + - \ No newline at end of file diff --git a/samples/Misc/Misc.csproj b/samples/Misc/Misc.csproj index 99aa25c6a..faf4b634b 100644 --- a/samples/Misc/Misc.csproj +++ b/samples/Misc/Misc.csproj @@ -1,8 +1,8 @@  - netstandard2.0 + diff --git a/samples/Samples.AspNet/Samples.AspNet.csproj b/samples/Samples.AspNet/Samples.AspNet.csproj index 35c64e4cb..f4419a22f 100644 --- a/samples/Samples.AspNet/Samples.AspNet.csproj +++ b/samples/Samples.AspNet/Samples.AspNet.csproj @@ -4,12 +4,14 @@ net6.0 true + + + + - - \ No newline at end of file diff --git a/samples/Samples.Console/Samples.Console.csproj b/samples/Samples.Console/Samples.Console.csproj index 86a1f0906..11dc9a55f 100644 --- a/samples/Samples.Console/Samples.Console.csproj +++ b/samples/Samples.Console/Samples.Console.csproj @@ -6,17 +6,21 @@ bin\$(Configuration)\ win7-x64 + - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/samples/Samples.ConsoleCore/Samples.ConsoleCore.csproj b/samples/Samples.ConsoleCore/Samples.ConsoleCore.csproj index de6604e61..9c86a1227 100644 --- a/samples/Samples.ConsoleCore/Samples.ConsoleCore.csproj +++ b/samples/Samples.ConsoleCore/Samples.ConsoleCore.csproj @@ -4,9 +4,11 @@ Samples.Console Exe + - + + \ No newline at end of file diff --git a/samples/Samples.Mvc5.EFCore/Samples.Mvc5.EFCore.csproj b/samples/Samples.Mvc5.EFCore/Samples.Mvc5.EFCore.csproj index 97c62781f..dfbc47120 100644 --- a/samples/Samples.Mvc5.EFCore/Samples.Mvc5.EFCore.csproj +++ b/samples/Samples.Mvc5.EFCore/Samples.Mvc5.EFCore.csproj @@ -9,53 +9,36 @@ true bin\ false - - if not exist "roslyn" md "roslyn" - xcopy /s /y /q "$(CscToolPath)\*.*" "roslyn" - + - - - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/samples/Samples.Mvc5/Samples.Mvc5.csproj b/samples/Samples.Mvc5/Samples.Mvc5.csproj index e588de31d..08ecf99ac 100644 --- a/samples/Samples.Mvc5/Samples.Mvc5.csproj +++ b/samples/Samples.Mvc5/Samples.Mvc5.csproj @@ -9,44 +9,24 @@ true bin\ false - - if not exist "roslyn" md "roslyn" - xcopy /s /y /q "$(CscToolPath)\*.*" "roslyn" - + - - - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + @@ -57,9 +37,11 @@ + + if not exist "$(TargetDir)x86" md "$(TargetDir)x86" @@ -69,6 +51,7 @@ xcopy /s /y /q "$(NuGetPackageRoot)\sqlite\3.13.0\runtimes\win7-x64\native\*.*" "$(TargetDir)x64\.." + diff --git a/src/MiniProfiler.AspNetCore.Mvc/MiniProfiler.AspNetCore.Mvc.csproj b/src/MiniProfiler.AspNetCore.Mvc/MiniProfiler.AspNetCore.Mvc.csproj index 598dc417e..9db0c16fb 100644 --- a/src/MiniProfiler.AspNetCore.Mvc/MiniProfiler.AspNetCore.Mvc.csproj +++ b/src/MiniProfiler.AspNetCore.Mvc/MiniProfiler.AspNetCore.Mvc.csproj @@ -7,9 +7,10 @@ ASP.NET Core;MVC;MVC Core;$(PackageBaseTags) net6.0 + - - + + \ No newline at end of file diff --git a/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs b/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs index 0f4f83a77..b2a670630 100644 --- a/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs +++ b/src/MiniProfiler.AspNetCore.Mvc/MvcDiagnosticListener.cs @@ -161,7 +161,7 @@ public StackTiming(object state, Timing? timing, StackTiming? previous) => /// Provides the observer with new data. /// /// The current notification information. - public void OnNext(KeyValuePair kv) + public void OnNext(KeyValuePair kv) { try { diff --git a/src/MiniProfiler.AspNetCore/MiniProfiler.AspNetCore.csproj b/src/MiniProfiler.AspNetCore/MiniProfiler.AspNetCore.csproj index 204608b26..1e816e111 100644 --- a/src/MiniProfiler.AspNetCore/MiniProfiler.AspNetCore.csproj +++ b/src/MiniProfiler.AspNetCore/MiniProfiler.AspNetCore.csproj @@ -7,9 +7,10 @@ ASP.NET Core;$(PackageBaseTags) net6.0 + - - + + \ No newline at end of file diff --git a/src/MiniProfiler.EF6/MiniProfiler.EF6.csproj b/src/MiniProfiler.EF6/MiniProfiler.EF6.csproj index a4e3fc9fd..15de099d4 100644 --- a/src/MiniProfiler.EF6/MiniProfiler.EF6.csproj +++ b/src/MiniProfiler.EF6/MiniProfiler.EF6.csproj @@ -8,8 +8,10 @@ Entity Framework;Entity Framework 6;$(PackageBaseTags) net461;netstandard2.1 + - + + \ No newline at end of file diff --git a/src/MiniProfiler.EFC7/MiniProfiler.EFC7.csproj b/src/MiniProfiler.EFC7/MiniProfiler.EFC7.csproj index bdaeb91ca..1de4bc512 100644 --- a/src/MiniProfiler.EFC7/MiniProfiler.EFC7.csproj +++ b/src/MiniProfiler.EFC7/MiniProfiler.EFC7.csproj @@ -8,8 +8,10 @@ Entity Framework;Entity Framework Classic 7;$(PackageBaseTags) net461 + - + + \ No newline at end of file diff --git a/src/MiniProfiler.EntityFrameworkCore/MiniProfiler.EntityFrameworkCore.csproj b/src/MiniProfiler.EntityFrameworkCore/MiniProfiler.EntityFrameworkCore.csproj index 197c13525..8e127183e 100644 --- a/src/MiniProfiler.EntityFrameworkCore/MiniProfiler.EntityFrameworkCore.csproj +++ b/src/MiniProfiler.EntityFrameworkCore/MiniProfiler.EntityFrameworkCore.csproj @@ -8,8 +8,10 @@ Entity Framework;Entity Framework Core;$(PackageBaseTags) netstandard2.0 + - + + \ No newline at end of file diff --git a/src/MiniProfiler.EntityFrameworkCore/RelationalDiagnosticListener.cs b/src/MiniProfiler.EntityFrameworkCore/RelationalDiagnosticListener.cs index 3fe2171a6..d2baf7bfe 100644 --- a/src/MiniProfiler.EntityFrameworkCore/RelationalDiagnosticListener.cs +++ b/src/MiniProfiler.EntityFrameworkCore/RelationalDiagnosticListener.cs @@ -43,7 +43,7 @@ public void OnCompleted() { } /// Provides the observer with new data. /// /// The current notification information. - public void OnNext(KeyValuePair kv) + public void OnNext(KeyValuePair kv) { var key = kv.Key; var val = kv.Value; diff --git a/src/MiniProfiler.Minimal/MiniProfiler.Minimal.csproj b/src/MiniProfiler.Minimal/MiniProfiler.Minimal.csproj index 1565f7c43..a15a9910f 100644 --- a/src/MiniProfiler.Minimal/MiniProfiler.Minimal.csproj +++ b/src/MiniProfiler.Minimal/MiniProfiler.Minimal.csproj @@ -4,19 +4,19 @@ MiniProfiler.Minimal Nick Craver MiniProfiler's no-frills headless build for no-UI applications. - netstandard2.0 + netstandard2.0;net6.0 MINIMAL - + - + - + diff --git a/src/MiniProfiler.Mvc5/MiniProfiler.Mvc5.csproj b/src/MiniProfiler.Mvc5/MiniProfiler.Mvc5.csproj index 98c51472a..0718c4552 100644 --- a/src/MiniProfiler.Mvc5/MiniProfiler.Mvc5.csproj +++ b/src/MiniProfiler.Mvc5/MiniProfiler.Mvc5.csproj @@ -8,9 +8,12 @@ ASP.NET;MVC;MVC 5;$(PackageBaseTags) net461 + - - + + + + \ No newline at end of file diff --git a/src/MiniProfiler.Providers.MongoDB/MiniProfiler.Providers.MongoDB.csproj b/src/MiniProfiler.Providers.MongoDB/MiniProfiler.Providers.MongoDB.csproj index 0d9499595..1c6ba1408 100644 --- a/src/MiniProfiler.Providers.MongoDB/MiniProfiler.Providers.MongoDB.csproj +++ b/src/MiniProfiler.Providers.MongoDB/MiniProfiler.Providers.MongoDB.csproj @@ -9,8 +9,10 @@ ..\..\miniprofiler.snk false + - + + \ No newline at end of file diff --git a/src/MiniProfiler.Providers.MySql/MiniProfiler.Providers.MySql.csproj b/src/MiniProfiler.Providers.MySql/MiniProfiler.Providers.MySql.csproj index 97d3abc84..c0cf08802 100644 --- a/src/MiniProfiler.Providers.MySql/MiniProfiler.Providers.MySql.csproj +++ b/src/MiniProfiler.Providers.MySql/MiniProfiler.Providers.MySql.csproj @@ -7,9 +7,11 @@ SQL;MySQL;$(PackageBaseTags) net461;netstandard2.0 + - + + \ No newline at end of file diff --git a/src/MiniProfiler.Providers.PostgreSql/MiniProfiler.Providers.PostgreSql.csproj b/src/MiniProfiler.Providers.PostgreSql/MiniProfiler.Providers.PostgreSql.csproj index 1dbcdbb09..900ae30e4 100644 --- a/src/MiniProfiler.Providers.PostgreSql/MiniProfiler.Providers.PostgreSql.csproj +++ b/src/MiniProfiler.Providers.PostgreSql/MiniProfiler.Providers.PostgreSql.csproj @@ -7,9 +7,11 @@ SQL;Npgsql;PostgreSql;$(PackageBaseTags) net461;netstandard2.0 + - + + \ No newline at end of file diff --git a/src/MiniProfiler.Providers.RavenDB/MiniProfiler.Providers.RavenDB.csproj b/src/MiniProfiler.Providers.RavenDB/MiniProfiler.Providers.RavenDB.csproj index e8eb7a260..c60e8400c 100644 --- a/src/MiniProfiler.Providers.RavenDB/MiniProfiler.Providers.RavenDB.csproj +++ b/src/MiniProfiler.Providers.RavenDB/MiniProfiler.Providers.RavenDB.csproj @@ -7,9 +7,11 @@ Raven;RavenDB;$(PackageBaseTags) net461;netstandard2.0 + - + + \ No newline at end of file diff --git a/src/MiniProfiler.Providers.Redis/MiniProfiler.Providers.Redis.csproj b/src/MiniProfiler.Providers.Redis/MiniProfiler.Providers.Redis.csproj index 90465b152..2d2126bfe 100644 --- a/src/MiniProfiler.Providers.Redis/MiniProfiler.Providers.Redis.csproj +++ b/src/MiniProfiler.Providers.Redis/MiniProfiler.Providers.Redis.csproj @@ -7,9 +7,11 @@ Redis;$(PackageBaseTags) net461;netstandard2.0 + - - + + + diff --git a/src/MiniProfiler.Providers.SqlServer/MiniProfiler.Providers.SqlServer.csproj b/src/MiniProfiler.Providers.SqlServer/MiniProfiler.Providers.SqlServer.csproj index 2d2c43a96..788e700b9 100644 --- a/src/MiniProfiler.Providers.SqlServer/MiniProfiler.Providers.SqlServer.csproj +++ b/src/MiniProfiler.Providers.SqlServer/MiniProfiler.Providers.SqlServer.csproj @@ -7,8 +7,10 @@ SQL;SQL Server;$(PackageBaseTags) net461;netstandard2.0 + - + + \ No newline at end of file diff --git a/src/MiniProfiler.Providers.SqlServerCe/MiniProfiler.Providers.SqlServerCe.csproj b/src/MiniProfiler.Providers.SqlServerCe/MiniProfiler.Providers.SqlServerCe.csproj index 410ba8b41..f06bca989 100644 --- a/src/MiniProfiler.Providers.SqlServerCe/MiniProfiler.Providers.SqlServerCe.csproj +++ b/src/MiniProfiler.Providers.SqlServerCe/MiniProfiler.Providers.SqlServerCe.csproj @@ -7,9 +7,11 @@ SQL Server CE;$(PackageBaseTags) net461 + - + + \ No newline at end of file diff --git a/src/MiniProfiler.Providers.Sqlite/MiniProfiler.Providers.Sqlite.csproj b/src/MiniProfiler.Providers.Sqlite/MiniProfiler.Providers.Sqlite.csproj index 87ca5f927..bfec4af5e 100644 --- a/src/MiniProfiler.Providers.Sqlite/MiniProfiler.Providers.Sqlite.csproj +++ b/src/MiniProfiler.Providers.Sqlite/MiniProfiler.Providers.Sqlite.csproj @@ -7,9 +7,11 @@ SQL;SQLite;$(PackageBaseTags) net461;netstandard2.0 + - + + \ No newline at end of file diff --git a/src/MiniProfiler.Shared/Data/ProfiledDbCommand.cs b/src/MiniProfiler.Shared/Data/ProfiledDbCommand.cs index a1bb72da0..0b79c3be8 100644 --- a/src/MiniProfiler.Shared/Data/ProfiledDbCommand.cs +++ b/src/MiniProfiler.Shared/Data/ProfiledDbCommand.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Data; using System.Data.Common; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; #if !MINIMAL @@ -95,7 +96,7 @@ public ProfiledDbCommand(DbCommand command, DbConnection? connection, IDbProfile var prop = commandType.GetProperty("BindByName", BindingFlags.Public | BindingFlags.Instance); action = null; ParameterInfo[] indexers; - MethodInfo setter; + MethodInfo? setter; if (prop?.CanWrite == true && prop.PropertyType == typeof(bool) && ((indexers = prop.GetIndexParameters()) == null || indexers.Length == 0) && (setter = prop.GetSetMethod()) != null) @@ -117,6 +118,7 @@ public ProfiledDbCommand(DbCommand command, DbConnection? connection, IDbProfile #endif /// + [AllowNull] public override string CommandText { get => _command.CommandText; @@ -308,14 +310,14 @@ public override async Task ExecuteNonQueryAsync(CancellationToken cancellat } /// - public override object ExecuteScalar() + public override object? ExecuteScalar() { if (_profiler?.IsActive != true) { return _command.ExecuteScalar(); } - object result; + object? result; _profiler.ExecuteStart(this, SqlExecuteType.Scalar); try { @@ -335,14 +337,14 @@ public override object ExecuteScalar() } /// - public override async Task ExecuteScalarAsync(CancellationToken cancellationToken) + public override async Task ExecuteScalarAsync(CancellationToken cancellationToken) { if (_profiler?.IsActive != true) { return await _command.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false); } - object result; + object? result; _profiler.ExecuteStart(this, SqlExecuteType.Scalar); try { diff --git a/src/MiniProfiler.Shared/Data/ProfiledDbConnection.cs b/src/MiniProfiler.Shared/Data/ProfiledDbConnection.cs index d5cd69cda..28af54514 100644 --- a/src/MiniProfiler.Shared/Data/ProfiledDbConnection.cs +++ b/src/MiniProfiler.Shared/Data/ProfiledDbConnection.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; @@ -45,6 +46,7 @@ public ProfiledDbConnection(DbConnection connection, IDbProfiler? profiler) public DbConnection WrappedConnection => _connection; /// + [AllowNull] public override string ConnectionString { get => _connection.ConnectionString; @@ -165,7 +167,7 @@ private void StateChangeHandler(object sender, StateChangeEventArgs stateChangeE protected override bool CanRaiseEvents => true; /// - public override void EnlistTransaction(System.Transactions.Transaction transaction) => _connection.EnlistTransaction(transaction); + public override void EnlistTransaction(System.Transactions.Transaction? transaction) => _connection.EnlistTransaction(transaction); /// public override DataTable GetSchema() => _connection.GetSchema(); @@ -174,6 +176,6 @@ private void StateChangeHandler(object sender, StateChangeEventArgs stateChangeE public override DataTable GetSchema(string collectionName) => _connection.GetSchema(collectionName); /// - public override DataTable GetSchema(string collectionName, string[] restrictionValues) => _connection.GetSchema(collectionName, restrictionValues); + public override DataTable GetSchema(string collectionName, string?[] restrictionValues) => _connection.GetSchema(collectionName, restrictionValues); } } diff --git a/src/MiniProfiler.Shared/Data/ProfiledDbDataAdapter.cs b/src/MiniProfiler.Shared/Data/ProfiledDbDataAdapter.cs index ce62a7412..f4266fe38 100644 --- a/src/MiniProfiler.Shared/Data/ProfiledDbDataAdapter.cs +++ b/src/MiniProfiler.Shared/Data/ProfiledDbDataAdapter.cs @@ -155,7 +155,7 @@ private void InitCommands(IDbDataAdapter wrappedAdapter) set { _selectCommand = value; - InternalAdapter.SelectCommand = value is ProfiledDbCommand cmd ? cmd.InternalCommand : value; + InternalAdapter.SelectCommand = value is ProfiledDbCommand cmd ? cmd.WrappedCommand : value; } } @@ -166,7 +166,7 @@ private void InitCommands(IDbDataAdapter wrappedAdapter) set { _insertCommand = value; - InternalAdapter.InsertCommand = value is ProfiledDbCommand cmd ? cmd.InternalCommand : value; + InternalAdapter.InsertCommand = value is ProfiledDbCommand cmd ? cmd.WrappedCommand : value; } } @@ -177,7 +177,7 @@ private void InitCommands(IDbDataAdapter wrappedAdapter) set { _updateCommand = value; - InternalAdapter.UpdateCommand = value is ProfiledDbCommand cmd ? cmd.InternalCommand : value; + InternalAdapter.UpdateCommand = value is ProfiledDbCommand cmd ? cmd.WrappedCommand : value; } } @@ -188,7 +188,7 @@ private void InitCommands(IDbDataAdapter wrappedAdapter) set { _deleteCommand = value; - InternalAdapter.DeleteCommand = value is ProfiledDbCommand cmd ? cmd.InternalCommand : value; + InternalAdapter.DeleteCommand = value is ProfiledDbCommand cmd ? cmd.WrappedCommand : value; } } } diff --git a/src/MiniProfiler.Shared/Data/ProfiledDbDataReader.cs b/src/MiniProfiler.Shared/Data/ProfiledDbDataReader.cs index 53a2d67ed..8d225301b 100644 --- a/src/MiniProfiler.Shared/Data/ProfiledDbDataReader.cs +++ b/src/MiniProfiler.Shared/Data/ProfiledDbDataReader.cs @@ -69,14 +69,14 @@ public ProfiledDbDataReader(DbDataReader reader, CommandBehavior behavior, IDbPr public override byte GetByte(int ordinal) => WrappedReader.GetByte(ordinal); /// - public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) => + public override long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length) => WrappedReader.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); /// public override char GetChar(int ordinal) => WrappedReader.GetChar(ordinal); /// - public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) => + public override long GetChars(int ordinal, long dataOffset, char[]? buffer, int bufferOffset, int length) => WrappedReader.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); /// @@ -164,7 +164,7 @@ public override void Close() } /// - public override DataTable GetSchemaTable() => WrappedReader.GetSchemaTable(); + public override DataTable? GetSchemaTable() => WrappedReader.GetSchemaTable(); /// protected override void Dispose(bool disposing) diff --git a/src/MiniProfiler.Shared/Data/ProfiledDbProviderFactory.cs b/src/MiniProfiler.Shared/Data/ProfiledDbProviderFactory.cs index cc8bfbbc1..82df9a3f4 100644 --- a/src/MiniProfiler.Shared/Data/ProfiledDbProviderFactory.cs +++ b/src/MiniProfiler.Shared/Data/ProfiledDbProviderFactory.cs @@ -54,32 +54,32 @@ private ProfiledDbProviderFactory() { } #pragma warning restore CS8618 /// - public override DbCommand CreateCommand() + public override DbCommand? CreateCommand() { var command = _factory.CreateCommand(); var profiler = MiniProfiler.Current; - return profiler != null || _alwaysWrap + return command is not null && (profiler is not null || _alwaysWrap) ? new ProfiledDbCommand(command, null, profiler) : command; } /// - public override DbConnection CreateConnection() + public override DbConnection? CreateConnection() { var connection = _factory.CreateConnection(); var profiler = MiniProfiler.Current; - return profiler != null || _alwaysWrap + return connection is not null && (profiler is not null || _alwaysWrap) ? new ProfiledDbConnection(connection, profiler) : connection; } /// - public override DbConnectionStringBuilder CreateConnectionStringBuilder() => _factory.CreateConnectionStringBuilder(); + public override DbConnectionStringBuilder? CreateConnectionStringBuilder() => _factory.CreateConnectionStringBuilder(); /// - public override DbParameter CreateParameter() => _factory.CreateParameter(); + public override DbParameter? CreateParameter() => _factory.CreateParameter(); /// /// Allow to re-initialize the provider factory. @@ -91,24 +91,23 @@ public override DbConnection CreateConnection() public override bool CanCreateDataSourceEnumerator => _factory.CanCreateDataSourceEnumerator; /// - public override DbCommandBuilder CreateCommandBuilder() => _factory.CreateCommandBuilder(); + public override DbCommandBuilder? CreateCommandBuilder() => _factory.CreateCommandBuilder(); /// - public override DbDataAdapter CreateDataAdapter() + public override DbDataAdapter? CreateDataAdapter() { - var profiler = MiniProfiler.Current; - var dataAdapter = _factory.CreateDataAdapter(); + var profiler = MiniProfiler.Current; - return profiler != null || _alwaysWrap + return dataAdapter is not null && (profiler is not null || _alwaysWrap) ? new ProfiledDbDataAdapter(dataAdapter, profiler) : dataAdapter; } /// - public override DbDataSourceEnumerator CreateDataSourceEnumerator() => _factory.CreateDataSourceEnumerator(); + public override DbDataSourceEnumerator? CreateDataSourceEnumerator() => _factory.CreateDataSourceEnumerator(); -#if !NETSTANDARD2_0 +#if NET46_OR_GREATER /// public override CodeAccessPermission CreatePermission(PermissionState state) => _factory.CreatePermission(state); #endif diff --git a/src/MiniProfiler.Shared/Data/SimpleProfiledCommand.cs b/src/MiniProfiler.Shared/Data/SimpleProfiledCommand.cs index 5b3926cc0..9c6f78cb2 100644 --- a/src/MiniProfiler.Shared/Data/SimpleProfiledCommand.cs +++ b/src/MiniProfiler.Shared/Data/SimpleProfiledCommand.cs @@ -11,7 +11,7 @@ namespace StackExchange.Profiling.Data public class SimpleProfiledCommand : IDbCommand { private IDbCommand _command; - private IDbConnection _connection; + private IDbConnection? _connection; private IDbProfiler? _profiler; private IDbTransaction? _transaction; @@ -54,7 +54,7 @@ public IDataReader ExecuteReader(CommandBehavior behavior) => ProfileWith(SqlExecuteType.Reader, () => new SimpleProfiledDataReader(_command.ExecuteReader(behavior), _profiler)); /// - public object ExecuteScalar() => ProfileWith(SqlExecuteType.Scalar, () => _command.ExecuteScalar()); + public object? ExecuteScalar() => ProfileWith(SqlExecuteType.Scalar, () => _command.ExecuteScalar()); /// /// Profile with results. @@ -88,7 +88,7 @@ private TResult ProfileWith(SqlExecuteType type, Func func) } /// - public IDbConnection Connection + public IDbConnection? Connection { get => _connection; set @@ -116,6 +116,7 @@ public IDbTransaction? Transaction } /// + [AllowNull] [SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities", Justification = "Handled elsewhere.")] public string CommandText { diff --git a/src/MiniProfiler.Shared/Data/SimpleProfiledConnection.cs b/src/MiniProfiler.Shared/Data/SimpleProfiledConnection.cs index 2d56cbc6d..12a3403a4 100644 --- a/src/MiniProfiler.Shared/Data/SimpleProfiledConnection.cs +++ b/src/MiniProfiler.Shared/Data/SimpleProfiledConnection.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using System.Diagnostics.CodeAnalysis; namespace StackExchange.Profiling.Data { @@ -13,6 +14,7 @@ public class SimpleProfiledConnection : IDbConnection private IDbConnection _connection; /// + [AllowNull] public string ConnectionString { get => _connection.ConnectionString; diff --git a/src/MiniProfiler.Shared/Data/SimpleProfiledDataReader.cs b/src/MiniProfiler.Shared/Data/SimpleProfiledDataReader.cs index 732d1ff3d..3e5e3a48c 100644 --- a/src/MiniProfiler.Shared/Data/SimpleProfiledDataReader.cs +++ b/src/MiniProfiler.Shared/Data/SimpleProfiledDataReader.cs @@ -53,14 +53,14 @@ public SimpleProfiledDataReader(IDataReader reader, IDbProfiler? profiler) public byte GetByte(int ordinal) => _reader.GetByte(ordinal); /// - public long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) => + public long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length) => _reader.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); /// public char GetChar(int ordinal) => _reader.GetChar(ordinal); /// - public long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) => + public long GetChars(int ordinal, long dataOffset, char[]? buffer, int bufferOffset, int length) => _reader.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); /// @@ -124,7 +124,7 @@ public void Close() } /// - public DataTable GetSchemaTable() => _reader.GetSchemaTable(); + public DataTable? GetSchemaTable() => _reader.GetSchemaTable(); /// public bool NextResult() => _reader.NextResult(); diff --git a/src/MiniProfiler.Shared/Helpers/ProfilerSortedKey.cs b/src/MiniProfiler.Shared/Helpers/ProfilerSortedKey.cs index 2c63ef169..bf07a380e 100644 --- a/src/MiniProfiler.Shared/Helpers/ProfilerSortedKey.cs +++ b/src/MiniProfiler.Shared/Helpers/ProfilerSortedKey.cs @@ -33,10 +33,10 @@ public ProfilerSortedKey(MiniProfiler profiler) /// Compares this to another. /// /// The to compare - public int CompareTo(ProfilerSortedKey other) + public int CompareTo(ProfilerSortedKey? other) { - var comp = Started.CompareTo(other.Started); - if (comp == 0) comp = Id.CompareTo(other.Id); + var comp = Started.CompareTo(other?.Started); + if (comp == 0) comp = Id.CompareTo(other?.Id); return comp; } } diff --git a/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs b/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs index 38344dbba..654de5aec 100644 --- a/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs +++ b/src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs @@ -43,7 +43,7 @@ bool ShouldExcludeType(MethodBase method) return false; } - var frames = new StackTrace().GetFrames(); + StackFrame?[] frames = new StackTrace().GetFrames(); if (frames == null) { @@ -56,18 +56,22 @@ bool ShouldExcludeType(MethodBase method) for (int i = 0; i < frames.Length; i++) { - var method = frames[i].GetMethod(); + var method = frames[i]?.GetMethod(); + if (method is null) + { + continue; + } if (stackLength >= options.StackMaxLength // ASP.NET: no need to continue up the chain || method.Name == "System.Web.HttpApplication.IExecutionStep.Execute" - || (ModuleNames.GetOrAdd(method.Module, m => m.Name) == "Microsoft.AspNetCore.Mvc.Core.dll" && method.DeclaringType.Name == "ObjectMethodExecutor")) + || (ModuleNames.GetOrAdd(method.Module, m => m.Name) == "Microsoft.AspNetCore.Mvc.Core.dll" && method.DeclaringType?.Name == "ObjectMethodExecutor")) { frames[i] = null; startFrame = i < 0 ? 0 : i - 1; break; } else if (ShouldExcludeType(method) - || options.ExcludedAssemblies.Contains(AssemblyNames.GetOrAdd(method.Module.Assembly, a => a.GetName().Name)) + || options.ExcludedAssemblies.Contains(AssemblyNames.GetOrAdd(method.Module.Assembly, a => a.GetName().Name ?? "Unknown Assembly")) || options.ExcludedMethods.Contains(method.Name)) { frames[i] = null; @@ -83,7 +87,7 @@ bool ShouldExcludeType(MethodBase method) var f = frames[i]; if (f != null) { - var method = f.GetMethod(); + var method = f.GetMethod()!; if (sb.Length > 0) { sb.Append(" > "); @@ -494,7 +498,7 @@ internal static StringBuilder AppendGenericsHtml(this StringBuilder sb, string t { const string _dotSpan = "."; // Check the common framework list above - _commonGenerics.TryGetValue(typeOrMethod, out string[] args); + _commonGenerics.TryGetValue(typeOrMethod, out string[]? args); // Break each type down by namespace and class (remember, we *could* have nested generic classes) var classes = typeOrMethod.Split(_dot); @@ -543,11 +547,11 @@ void AppendArgs(string[] tArgs) if (tArgs.Length > 5) { sb.Append("").Append(tArgs[0]).Append("") - .Append(",") + .Append(',') .Append("").Append(tArgs[1]).Append("") - .Append(",") + .Append(',') .Append("").Append(tArgs[2]).Append("") - .Append("…") + .Append('…') .Append("").Append(tArgs[tArgs.Length - 1]).Append(""); } else @@ -556,7 +560,7 @@ void AppendArgs(string[] tArgs) { if (i > 0) { - sb.Append(","); + sb.Append(','); } sb.Append(""); sb.Append(tArgs[i]) diff --git a/src/MiniProfiler.Shared/Internal/ExtensionMethods.cs b/src/MiniProfiler.Shared/Internal/ExtensionMethods.cs index e3237c8ac..2b5a6b0df 100644 --- a/src/MiniProfiler.Shared/Internal/ExtensionMethods.cs +++ b/src/MiniProfiler.Shared/Internal/ExtensionMethods.cs @@ -3,9 +3,12 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -#if !MINIMAL +#if NEWTONSOFT using Newtonsoft.Json; using Newtonsoft.Json.Serialization; +#elif STJSON +using System.Text.Json; +using System.Text.Json.Serialization; #endif namespace StackExchange.Profiling.Internal @@ -79,7 +82,7 @@ public static string ToJson(this List? guids) return sb.ToString(); } -#if !MINIMAL +#if NEWTONSOFT private static readonly JsonSerializerSettings defaultSettings = new() { NullValueHandling = NullValueHandling.Ignore, @@ -127,6 +130,41 @@ public static string ToJson(this List? guids) /// The object resulting from the given string. public static T? FromJson(this string? s) where T : class => !string.IsNullOrEmpty(s) ? JsonConvert.DeserializeObject(s!, defaultSettings) : null; +#elif STJSON + private static readonly JsonSerializerOptions defaultSettings = new() + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + }; + + /// + /// Renders the parameter to JSON. + /// + /// The to serialize. + /// Whether to HTML escape the output. + [return: NotNullIfNotNull(nameof(profiler))] + [SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Compatibility across versions")] + public static string? ToJson(this MiniProfiler? profiler, bool htmlEscape = false) => + profiler != default + ? JsonSerializer.Serialize(profiler, defaultSettings) + : null; + + /// + /// Serializes to a JSON string. + /// + /// The instance to serialize. + /// The resulting JSON object as a string. + [return: NotNullIfNotNull(nameof(o))] + public static string? ToJson(this object? o) => + o != null ? JsonSerializer.Serialize(o, defaultSettings) : null; + + /// + /// Deserializes to an object of type . + /// + /// The type to deserialize to. + /// The string to deserialize. + /// The object resulting from the given string. + public static T? FromJson(this string? s) where T : class => + !string.IsNullOrEmpty(s) ? JsonSerializer.Deserialize(s!, defaultSettings) : null; #endif /// @@ -138,7 +176,7 @@ public static string ToJson(this List? guids) /// The key to attempt removal of. /// The value found (if it was found) from the dictionary. /// Whether the key was removed. - public static bool TryRemove(this Dictionary dict, TKey key, [NotNullWhen(true)] out TValue? value) + public static bool TryRemove(this Dictionary dict, TKey key, [NotNullWhen(true)] out TValue? value) where TKey : notnull { value = default; if (dict?.TryGetValue(key, out value) == true) diff --git a/src/MiniProfiler.Shared/Internal/IDataParameterExtensions.cs b/src/MiniProfiler.Shared/Internal/IDataParameterExtensions.cs index ce77e7124..fd3fd4d44 100644 --- a/src/MiniProfiler.Shared/Internal/IDataParameterExtensions.cs +++ b/src/MiniProfiler.Shared/Internal/IDataParameterExtensions.cs @@ -15,7 +15,7 @@ public static class IDataParameterExtensions /// The parameter to get a value for. public static string? GetStringValue(this IDataParameter parameter) { - object rawValue = parameter.Value; + object? rawValue = parameter.Value; if (rawValue == null || rawValue == DBNull.Value) { return null; diff --git a/src/MiniProfiler.Shared/Internal/IMiniProfilerDiagnosticListener.cs b/src/MiniProfiler.Shared/Internal/IMiniProfilerDiagnosticListener.cs index a0a022f48..85bee71c1 100644 --- a/src/MiniProfiler.Shared/Internal/IMiniProfilerDiagnosticListener.cs +++ b/src/MiniProfiler.Shared/Internal/IMiniProfilerDiagnosticListener.cs @@ -7,7 +7,7 @@ namespace StackExchange.Profiling.Internal /// Internal MiniProfiler interface for registering DiagnosticListeners, not meant for consumption. /// This can and probably will break without warning. Don't use the .Internal namespace directly. /// - public interface IMiniProfilerDiagnosticListener : IObserver> + public interface IMiniProfilerDiagnosticListener : IObserver> { /// /// Gets a value indicating which listener this instance should be subscribed to. diff --git a/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs b/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs index c798a546d..4a245c1fe 100644 --- a/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs +++ b/src/MiniProfiler.Shared/Internal/MiniProfilerBaseOptions.cs @@ -16,7 +16,7 @@ public class MiniProfilerBaseOptions /// /// Assembly version of this dank MiniProfiler. /// - public static Version Version { get; } = typeof(MiniProfilerBaseOptions).GetTypeInfo().Assembly.GetName().Version; + public static Version Version { get; } = typeof(MiniProfilerBaseOptions).GetTypeInfo().Assembly.GetName().Version!; /// /// The hash to use for file cache breaking, this is automatically calculated. diff --git a/src/MiniProfiler.Shared/Internal/ResultRequest.cs b/src/MiniProfiler.Shared/Internal/ResultRequest.cs index 31b541fcb..b9fbbb558 100644 --- a/src/MiniProfiler.Shared/Internal/ResultRequest.cs +++ b/src/MiniProfiler.Shared/Internal/ResultRequest.cs @@ -3,7 +3,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; -using Newtonsoft.Json; namespace StackExchange.Profiling.Internal { @@ -37,7 +36,9 @@ public class ResultRequest /// public int TimingCount => (Performance?.Count ?? 0) + (Probes?.Count ?? 0); - private static readonly JsonSerializer _serializer = new(); +#if NEWTONSOFT + private static readonly Newtonsoft.Json.JsonSerializer _serializer = new(); +#endif /// /// Returns a deserialize object from an input stream, like an HTTP request body. @@ -49,8 +50,9 @@ public static bool TryParse(Stream stream, [NotNullWhen(true)] out ResultRequest { try { - using (var sr = new StreamReader(stream)) - using (var jsonTextReader = new JsonTextReader(sr)) +#if NEWTONSOFT + using var sr = new StreamReader(stream); + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(sr)) { var tmp = _serializer.Deserialize(jsonTextReader); if (tmp?.Id.HasValue == true) @@ -59,6 +61,14 @@ public static bool TryParse(Stream stream, [NotNullWhen(true)] out ResultRequest return true; } } +#elif STJSON + var tmp = System.Text.Json.JsonSerializer.Deserialize(stream); + if (tmp?.Id.HasValue == true) + { + result = tmp; + return true; + } +#endif } catch (Exception e) { diff --git a/src/MiniProfiler.Shared/JSONHacks.cs b/src/MiniProfiler.Shared/JSONHacks.cs new file mode 100644 index 000000000..1be242e02 --- /dev/null +++ b/src/MiniProfiler.Shared/JSONHacks.cs @@ -0,0 +1,9 @@ +// Defining these attributes here so we don't have a ton of #if defs around every property + +#if !NET6_0_OR_GREATER +namespace System.Text.Json.Serialization +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] + internal sealed class JsonIgnore : Attribute { } +} +#endif diff --git a/src/MiniProfiler.Shared/MiniProfiler.Shared.csproj b/src/MiniProfiler.Shared/MiniProfiler.Shared.csproj index ba7ca4ef3..760e8d15f 100644 --- a/src/MiniProfiler.Shared/MiniProfiler.Shared.csproj +++ b/src/MiniProfiler.Shared/MiniProfiler.Shared.csproj @@ -4,18 +4,25 @@ MiniProfiler.Shared Marc Gravell, Jarrod Dixon, Yaakov Ellis, Nick Craver You shouldn't reference this - MiniProfiler's shared library for all frameworks - net461;netstandard2.0 + net461;netstandard2.0;net6.0 + + NEWTONSOFT + NEWTONSOFT + STJSON + - + + - - + + + @@ -23,10 +30,15 @@ + + + + + diff --git a/src/MiniProfiler.Shared/MiniProfiler.cs b/src/MiniProfiler.Shared/MiniProfiler.cs index c998426f1..f5468a8b7 100644 --- a/src/MiniProfiler.Shared/MiniProfiler.cs +++ b/src/MiniProfiler.Shared/MiniProfiler.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.Serialization; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using StackExchange.Profiling.Helpers; @@ -23,6 +24,7 @@ public partial class MiniProfiler /// The vast majority of use cases will be a single options instance, so this works pretty well. /// [IgnoreDataMember] + [JsonIgnore] public MiniProfilerBaseOptions Options { get; } = DefaultOptions; /// @@ -105,6 +107,7 @@ public MiniProfiler(string? name, MiniProfilerBaseOptions options) /// /// JSON used to store Custom Links. Do not touch. /// + [JsonIgnore] public string? CustomLinksJson { get => CustomLinks?.ToJson(); @@ -151,6 +154,7 @@ public Timing Root /// /// RedirectCount in ClientTimings. Used for sql storage. /// + [JsonIgnore] public int? ClientTimingsRedirectCount { get; set; } #endif @@ -183,6 +187,7 @@ public Timing Root /// /// Gets or sets points to the currently executing Timing. /// + [JsonIgnore] public Timing? Head { get => _head.Value ?? _lastSetHead; @@ -214,6 +219,7 @@ public Timing? Head /// /// Used to set custom storage for an individual request [IgnoreDataMember] + [JsonIgnore] public IAsyncStorage? Storage { get; set; } /// @@ -268,7 +274,6 @@ public async Task StopAsync(bool discardResults = false) /// /// Shared stop bits for and /// - /// private bool InnerStop() { if (!Stopwatch.IsRunning) @@ -307,7 +312,7 @@ private bool InnerStop() /// Returns true if Ids match. /// /// The to compare to. - public override bool Equals(object obj) => obj is MiniProfiler miniProfiler && Id.Equals(miniProfiler.Id); + public override bool Equals(object? obj) => obj is MiniProfiler miniProfiler && Id.Equals(miniProfiler.Id); /// /// Returns hash code of Id. @@ -352,7 +357,7 @@ public MiniProfiler Clone() { serializer.WriteObject(ms, this); ms.Position = 0; - return (MiniProfiler)serializer.ReadObject(ms); + return (MiniProfiler)serializer.ReadObject(ms)!; } } diff --git a/src/MiniProfiler.Shared/SqlFormatters/VerboseSqlServerFormatter.cs b/src/MiniProfiler.Shared/SqlFormatters/VerboseSqlServerFormatter.cs index 136153b2d..0714c5f13 100644 --- a/src/MiniProfiler.Shared/SqlFormatters/VerboseSqlServerFormatter.cs +++ b/src/MiniProfiler.Shared/SqlFormatters/VerboseSqlServerFormatter.cs @@ -35,20 +35,20 @@ public override string FormatSql(string commandText, List? p if (command != null && IncludeMetaData) { - buffer.Append("-- Command Type: ").Append(command.CommandType.ToString()).Append("\n"); - buffer.Append("-- Database: ").Append(command.Connection.Database).Append("\n"); + buffer.Append("-- Command Type: ").Append(command.CommandType.ToString()).Append('\n'); + buffer.Append("-- Database: ").Append(command.Connection?.Database).Append('\n'); if (command.Transaction != null) { - buffer.Append("-- Command Transaction Iso Level: ").Append(command.Transaction.IsolationLevel.ToString()).Append("\n"); + buffer.Append("-- Command Transaction Iso Level: ").Append(command.Transaction.IsolationLevel.ToString()).Append('\n'); } if (System.Transactions.Transaction.Current != null) { // transactions issued by TransactionScope are not bound to the database command but exists globally - buffer.Append("-- Transaction Scope Iso Level: ").Append(System.Transactions.Transaction.Current.IsolationLevel.ToString()).Append("\n"); + buffer.Append("-- Transaction Scope Iso Level: ").Append(System.Transactions.Transaction.Current.IsolationLevel.ToString()).Append('\n'); } - buffer.Append("\n"); + buffer.Append('\n'); } string baseOutput = base.FormatSql(commandText, parameters, command); diff --git a/src/MiniProfiler.Shared/SqlTimingParameter.cs b/src/MiniProfiler.Shared/SqlTimingParameter.cs index 4d76852ed..48cccaf0c 100644 --- a/src/MiniProfiler.Shared/SqlTimingParameter.cs +++ b/src/MiniProfiler.Shared/SqlTimingParameter.cs @@ -54,7 +54,7 @@ public class SqlTimingParameter /// and as . /// /// The to compare. - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is SqlTimingParameter other && string.Equals(Name, other.Name) diff --git a/src/MiniProfiler.Shared/Timing.cs b/src/MiniProfiler.Shared/Timing.cs index 9f80d2ecc..87404bb62 100644 --- a/src/MiniProfiler.Shared/Timing.cs +++ b/src/MiniProfiler.Shared/Timing.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.Serialization; +using System.Text.Json.Serialization; using StackExchange.Profiling.Internal; namespace StackExchange.Profiling @@ -165,18 +166,21 @@ public string? CustomTimingsJson { /// /// This will be null for the root (initial) Timing. [IgnoreDataMember] + [JsonIgnore] public Timing? ParentTiming { get; set; } /// /// The Unique Identifier identifying the parent timing of this Timing. Used for sql server storage. /// [IgnoreDataMember] + [JsonIgnore] public Guid ParentTimingId { get; set; } /// /// Gets the elapsed milliseconds in this step without any children's durations. /// [IgnoreDataMember] + [JsonIgnore] public decimal DurationWithoutChildrenMilliseconds { get @@ -203,12 +207,14 @@ public decimal DurationWithoutChildrenMilliseconds /// , by default 2.0 ms. /// [IgnoreDataMember] + [JsonIgnore] public bool IsTrivial => DurationMilliseconds <= Profiler?.Options.TrivialDurationThresholdMilliseconds; /// /// Gets a value indicating whether this Timing has inner Timing steps. /// [IgnoreDataMember] + [JsonIgnore] [MemberNotNullWhen(true, nameof(Children))] public bool HasChildren => Children?.Count > 0; @@ -216,12 +222,14 @@ public decimal DurationWithoutChildrenMilliseconds /// Gets a value indicating whether this Timing is the first one created in a MiniProfiler session. /// [IgnoreDataMember] + [JsonIgnore] public bool IsRoot => Equals(Profiler?.Root); /// /// Gets a value indicating whether how far away this Timing is from the Profiler's Root. /// [IgnoreDataMember] + [JsonIgnore] public short Depth { get @@ -242,12 +250,14 @@ public short Depth /// /// Gets a reference to the containing profiler, allowing this Timing to affect the Head and get Stopwatch readings. /// + [JsonIgnore] internal MiniProfiler? Profiler { get; set; } /// /// The unique identifier used to identify the Profiler with which this Timing is associated. Used for sql storage. /// [IgnoreDataMember] + [JsonIgnore] public Guid MiniProfilerId { get; set; } /// @@ -358,7 +368,7 @@ internal void RemoveCustomTiming(string category, CustomTiming customTiming) /// The kind of custom timings, e.g. "sql", "redis", "memcache" private List GetCustomTimingList(string category) { - List result; + List? result; if (CustomTimings == null) { lock (_syncRoot) diff --git a/src/MiniProfiler.Shared/TimingDebugInfo.cs b/src/MiniProfiler.Shared/TimingDebugInfo.cs index 16dac172b..91804e7e2 100644 --- a/src/MiniProfiler.Shared/TimingDebugInfo.cs +++ b/src/MiniProfiler.Shared/TimingDebugInfo.cs @@ -40,8 +40,8 @@ internal TimingDebugInfo(Timing parent, int debugStackShave = 0) myIndex >= 0 && parentIndex >= 0; myIndex--, parentIndex--) { - StackFrame myFrame = RawStack.GetFrame(myIndex), - parentFrame = parentStack.GetFrame(parentIndex); + StackFrame myFrame = RawStack.GetFrame(myIndex)!, + parentFrame = parentStack.GetFrame(parentIndex)!; if (myFrame.GetILOffset() == parentFrame.GetILOffset() && myFrame.GetMethod() == parentFrame.GetMethod()) { CommonStackStart = myIndex; diff --git a/src/MiniProfiler/MiniProfiler.csproj b/src/MiniProfiler/MiniProfiler.csproj index e8c75fb15..3660da054 100644 --- a/src/MiniProfiler/MiniProfiler.csproj +++ b/src/MiniProfiler/MiniProfiler.csproj @@ -7,10 +7,12 @@ ASP.NET;SQL;$(PackageBaseTags) net461 + - + + \ No newline at end of file diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 6c358306a..e63e320da 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -11,6 +11,7 @@ + diff --git a/tests/MiniProfiler.Tests.AspNet/MiniProfiler.Tests.AspNet.csproj b/tests/MiniProfiler.Tests.AspNet/MiniProfiler.Tests.AspNet.csproj index 6d17458b9..885206918 100644 --- a/tests/MiniProfiler.Tests.AspNet/MiniProfiler.Tests.AspNet.csproj +++ b/tests/MiniProfiler.Tests.AspNet/MiniProfiler.Tests.AspNet.csproj @@ -4,19 +4,23 @@ StackExchange.Profiling.Tests net462 + - - - - + + + - - + + + + + + if not exist "$(TargetDir)x86" md "$(TargetDir)x86" diff --git a/tests/MiniProfiler.Tests.AspNetCore/MiniProfiler.Tests.AspNetCore.csproj b/tests/MiniProfiler.Tests.AspNetCore/MiniProfiler.Tests.AspNetCore.csproj index dcf8b98fe..4364a95fc 100644 --- a/tests/MiniProfiler.Tests.AspNetCore/MiniProfiler.Tests.AspNetCore.csproj +++ b/tests/MiniProfiler.Tests.AspNetCore/MiniProfiler.Tests.AspNetCore.csproj @@ -4,9 +4,11 @@ StackExchange.Profiling.Tests net6.0 + + + - \ No newline at end of file diff --git a/tests/MiniProfiler.Tests/MiniProfiler.Tests.csproj b/tests/MiniProfiler.Tests/MiniProfiler.Tests.csproj index da7f6b1b2..5fea3c9bb 100644 --- a/tests/MiniProfiler.Tests/MiniProfiler.Tests.csproj +++ b/tests/MiniProfiler.Tests/MiniProfiler.Tests.csproj @@ -4,7 +4,12 @@ StackExchange.Profiling.Tests net462;net6.0 + + + + + @@ -12,14 +17,13 @@ - - - + - + + if not exist "$(TargetDir)x86" md "$(TargetDir)x86" diff --git a/tests/MiniProfiler.Tests/TimingInstrumentationTest.cs b/tests/MiniProfiler.Tests/TimingInstrumentationTest.cs index a8e1a2302..f50a97ad3 100644 --- a/tests/MiniProfiler.Tests/TimingInstrumentationTest.cs +++ b/tests/MiniProfiler.Tests/TimingInstrumentationTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using Xunit; using Xunit.Abstractions; @@ -13,14 +13,16 @@ private class TimingInstrumentation : IDisposable public Timing Timing { get; set; } public bool Disposed { get; set; } public void Dispose() => Disposed = true; + + public TimingInstrumentation(Timing timing) => Timing = timing; } [Fact] public void IsInstrumented() { - TimingInstrumentation instrumentation = null; - Timing timing = null; - Options.TimingInstrumentationProvider = t => instrumentation = new TimingInstrumentation { Timing = t }; + TimingInstrumentation? instrumentation = null; + Timing? timing = null; + Options.TimingInstrumentationProvider = t => instrumentation = new TimingInstrumentation(t); var mp = Options.StartProfiler(); using (timing = mp.Step("Test timing"))