From 1bb2f67bc7a269085c8dc0a453cb0c59c57e4310 Mon Sep 17 00:00:00 2001 From: Chebotov Nikolay Date: Fri, 5 Jun 2020 15:39:58 +0300 Subject: [PATCH] Add feature: allows to get PerformanceMeter of concrete class using DI with `RegisterPerformanceMeterScope` option setted to true (by default is true) --- CHANGELOG.md | 4 ++ README.md | 60 +++++++++++++++++++ README_RU.md | 60 +++++++++++++++++++ .../PerformanceDiagnosticSourceExtensions.cs | 16 ++++- ...uentPerformanceMeter.AspNetCore.Mvc.csproj | 6 +- .../Controllers/PerformanceMeterController.cs | 41 +++++++++++++ .../Startup.cs | 4 ++ ...se.FluentPerformanceMeter.TestWebAPI31.xml | 9 +++ .../Builders/PerformanceMeterBuilder.cs | 8 +++ .../PerformanceMeter.cs | 7 +++ .../PerformanceMeterBaseOptions.cs | 6 ++ .../Unchase.FluentPerformanceMeter.csproj | 6 +- .../Unchase.FluentPerformanceMeter.xml | 6 ++ 13 files changed, 226 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b89ff4..336e9b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ These are the changes to each version that has been released on the official [NuGet Gallery (Common)](https://www.nuget.org/packages/Unchase.FluentPerformanceMeter) and [NuGet Gallery (MVC)](https://www.nuget.org/packages/Unchase.FluentPerformanceMeter.AspNetCore.Mvc). +## v2.1.2 `(2020-06-05)` + +- [x] Add feature: allows to get PerformanceMeter of concrete class using DI with `RegisterPerformanceMeterScope` option setted to true (by default is true) + ## v2.1.1 `(2020-05-02)` - [x] Add feature: allows to iterate executing Actions with `iterations` parameter in `Start` extension methods diff --git a/README.md b/README.md index 98641b6..fd4bd73 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ The data obtained as a result of the method’s performance measurement can be u * [Examples of usage](#SimpleSamples) * [Method's performance measurement](#SimpleSamples) * [Using DI to Get Performance measurement results (v2.1.0)](#UsingDISamples) + * [Using DI to Get Performance measurement instance (v2.1.2)](#UsingDIInstanceSamples) * [Method's performance measurement with `DiagnosticSource` (v1.1.0)](#DiagnosticSourceSample) * [Method's performance measurement with `WatchingPerformanceAttribute` attribute (v2.0.0)](#WatchingPerformanceSample) * [Measuring the performance of an external library method](#SampleExternal) @@ -220,6 +221,65 @@ public class PerformanceMeterController : ControllerBase } ``` +#### Using DI to Get Performance measurement instance + +Starting with [*v2.1.2*](https://github.com/unchase/Unchase.FluentPerformanceMeter/releases/tag/v2.1.2), it became possible to get the performance measurement of the class instance using the built-in **DI** in *ASP.NET Core* application. +To do this, add the following code to `Startap.cs`: + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + // ... + + services.AddPerformanceMeter(options => + { + // ... + + // adds a scope service of the PerformanceMeter of concrete class for DI + // use it with ".WithSettingData.CallerFrom(IHttpContextAccessor)" + options.RegisterPerformanceMeterScope = true; + } + + // ... +} +``` + +Then, using DI, you can get the performance measurement instance, for example, as follows: + +```csharp +[ApiController] +[Route("api/v1/[controller]")] +public class PerformanceMeterController : ControllerBase +{ + [HttpGet("WatchingMethodUsingDI")] + public IActionResult WatchingMethodUsingDI() + { + // method performance info will reach with HttpContextAccessor (required for DI) + using (PerformanceMeter + .WatchingMethod(nameof(WatchingMethodUsingDI)) + .WithSettingData + .CallerFrom(_httpContextAccessor) + .Start()) + { + GetPerformanceMeterUsingDI(); + + return Ok(); + } + } + + private void GetPerformanceMeterUsingDI() + { + // get instance of PerformanceMeter using DI + var pm = HttpContext.RequestServices.GetRequiredService(typeof(PerformanceMeter)) as PerformanceMeter; + + // we can use "pm" for adding steps or for other operations + // ... + } + + // ... +} +``` + ### Method's performance measurement with `DiagnosticSource` Starting with [*v1.1.0*](https://github.com/unchase/Unchase.FluentPerformanceMeter/releases/tag/v1.1.0), it became possible to measure the performance of methods in an *AspNetCore MVC* application using the `DiagnosticSource` and the special `WatchingWithDiagnosticSourceAttribute` attribute. To do this, add the *NuGet* package [`Unchase.FluentPerformanceMeter.AspNetCore.Mvc`](https://www.nuget.org/Unchase.FluentPerformanceMeter.AspNetCore.Mvc) to the project and add the following code to `Startap.cs`: diff --git a/README_RU.md b/README_RU.md index 169652c..12780bd 100644 --- a/README_RU.md +++ b/README_RU.md @@ -66,6 +66,7 @@ * [Примеры использования](#SimpleSamples) * [Измерение производительности метода](#SimpleSamples) * [Использование DI для получения результатов замера производительности (v2.1.0)](#UsingDISamples) + * [Использование DI для получения экземпляра текущего замера производительности (v2.1.2)](#UsingDIInstanceSamples) * [Измерение производительности метода с помощью `DiagnosticSource` (v1.1.0)](#DiagnosticSourceSample) * [Измерение производительности метода с помощью атрибута `WatchingPerformanceAttribute` (v2.0.0)](#WatchingPerformanceSample) * [Измерение производительности метода используемой библиотеки](#SampleExternal) @@ -224,6 +225,65 @@ public class PerformanceMeterController : ControllerBase } ``` +#### Использование DI для получения экземпляра текущего замера производительности + +Начиная с версии [*v2.1.2*](https://github.com/unchase/Unchase.FluentPerformanceMeter/releases/tag/v2.1.2) появилась возможность получать текущий экземпляр замера производительности методов класса, используя встроенный **DI** в *ASP.NET Core* приложении. +Для этого необходимо добавить в `Startap.cs` следующий код: + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + // ... + + services.AddPerformanceMeter(options => + { + // ... + + // adds a scope service of the PerformanceMeter of concrete class for DI + // use it with ".WithSettingData.CallerFrom(IHttpContextAccessor)" + options.RegisterPerformanceMeterScope = true; + } + + // ... +} +``` + +После чего, используя DI, можно получить текущий экземпляр замера производительности, например, следующим образом: + +```csharp +[ApiController] +[Route("api/v1/[controller]")] +public class PerformanceMeterController : ControllerBase +{ + [HttpGet("WatchingMethodUsingDI")] + public IActionResult WatchingMethodUsingDI() + { + // method performance info will reach with HttpContextAccessor (required for DI) + using (PerformanceMeter + .WatchingMethod(nameof(WatchingMethodUsingDI)) + .WithSettingData + .CallerFrom(_httpContextAccessor) + .Start()) + { + GetPerformanceMeterUsingDI(); + + return Ok(); + } + } + + private void GetPerformanceMeterUsingDI() + { + // get instance of PerformanceMeter using DI + var pm = HttpContext.RequestServices.GetRequiredService(typeof(PerformanceMeter)) as PerformanceMeter; + + // we can use "pm" for adding steps or for other operations + // ... + } + + // ... +} +``` + ### Измерение производительности метода с помощью `DiagnosticSource` Начиная с версии [*v1.1.0*](https://github.com/unchase/Unchase.FluentPerformanceMeter/releases/tag/v1.1.0) появилась возможность мерять производительность методов в *AspNetCore MVC* приложении с помощью `DiagnosticSource` и специального атрибута `WatchingWithDiagnosticSourceAttribute`. diff --git a/Unchase.FluentPerformanceMeter.AspNetCore.Mvc/Extensions/PerformanceDiagnosticSourceExtensions.cs b/Unchase.FluentPerformanceMeter.AspNetCore.Mvc/Extensions/PerformanceDiagnosticSourceExtensions.cs index e5615f2..a01f03c 100644 --- a/Unchase.FluentPerformanceMeter.AspNetCore.Mvc/Extensions/PerformanceDiagnosticSourceExtensions.cs +++ b/Unchase.FluentPerformanceMeter.AspNetCore.Mvc/Extensions/PerformanceDiagnosticSourceExtensions.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using System.Diagnostics; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Unchase.FluentPerformanceMeter.AspNetCore.Mvc.DiagnosticSource; @@ -62,11 +63,24 @@ public static IApplicationBuilder UsePerformanceDiagnosticObserver(this IApplica /// An to configure options for Unchase.FluentPerformanceMeter. public static IServiceCollection AddPerformanceMeter(this IServiceCollection services, Action> configureOptions = null) where TClass : ControllerBase { + // ensure that IHttpContextAccessor was added + services.AddHttpContextAccessor(); + if (configureOptions != null) { services.Configure(configureOptions); } - services.Configure>(o => PerformanceMeter.Configure(o)); + + services.Configure>(o => + { + PerformanceMeter.Configure(o); + }); + + services.AddScoped(typeof(PerformanceMeter), serviceProvider => + { + var httpContext = serviceProvider.GetRequiredService()?.HttpContext; + return httpContext?.Items[$"PerformanceMeter{httpContext.TraceIdentifier}"]; + }); return services; } diff --git a/Unchase.FluentPerformanceMeter.AspNetCore.Mvc/Unchase.FluentPerformanceMeter.AspNetCore.Mvc.csproj b/Unchase.FluentPerformanceMeter.AspNetCore.Mvc/Unchase.FluentPerformanceMeter.AspNetCore.Mvc.csproj index 47600d3..218d0e1 100644 --- a/Unchase.FluentPerformanceMeter.AspNetCore.Mvc/Unchase.FluentPerformanceMeter.AspNetCore.Mvc.csproj +++ b/Unchase.FluentPerformanceMeter.AspNetCore.Mvc/Unchase.FluentPerformanceMeter.AspNetCore.Mvc.csproj @@ -3,7 +3,7 @@ netstandard2.0 true - 2.1.1 + 2.1.2 Unchase Unchase Unchase Fluent Performance Meter is an open-source and cross-platform .Net Standart 2.0 library is designed for the method’s performance measurement. @@ -16,8 +16,8 @@ Github performance benchmark benchmarking csharp dot-net en - 2.1.1.0 - 2.1.1.0 + 2.1.2.0 + 2.1.2.0 Unchase.FluentPerformanceMeter.AspNetCore.Mvc.xml diff --git a/Unchase.FluentPerformanceMeter.TestWebAPI31/Controllers/PerformanceMeterController.cs b/Unchase.FluentPerformanceMeter.TestWebAPI31/Controllers/PerformanceMeterController.cs index 520f73f..ae9a46b 100644 --- a/Unchase.FluentPerformanceMeter.TestWebAPI31/Controllers/PerformanceMeterController.cs +++ b/Unchase.FluentPerformanceMeter.TestWebAPI31/Controllers/PerformanceMeterController.cs @@ -4,6 +4,7 @@ using System.Threading; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Filters; using Unchase.FluentPerformanceMeter.AspNetCore.Mvc.Attributes; @@ -476,6 +477,46 @@ public ActionResult WatchingMethodStartWithCorrelationIdAndFakeServiceStep #endregion + #region DI + + /// + /// Test GET method with using HttpContextAccessor and adding step with DI. + /// + /// Some value. + /// + /// Returns input value. + /// + [HttpGet("WatchingMethodUsingDI")] + public ActionResult WatchingMethodUsingDI(uint value) + { + // method performance info will reach with HttpContextAccessor (required for DI) + using (PerformanceMeter + .WatchingMethod(nameof(WatchingMethodUsingDI)) + .WithSettingData + .CallerFrom(_httpContextAccessor) + .Start()) + { + // adds step to PerformanceMeter using DI + AddStepWithDI(); + + return Ok($"{value}"); + } + } + + private void AddStepWithDI() + { + // get instance of PerformanceMeter using DI + var pm = HttpContext.RequestServices.GetRequiredService(typeof(PerformanceMeter)) as PerformanceMeter; + + // add "Step (DI)" + using (pm?.Step("Step (DI)")) + { + Thread.Sleep(1000); + } + } + + #endregion + #region With HttpContextAccessor, custom data and executed commands /// diff --git a/Unchase.FluentPerformanceMeter.TestWebAPI31/Startup.cs b/Unchase.FluentPerformanceMeter.TestWebAPI31/Startup.cs index afe80a6..45633bf 100644 --- a/Unchase.FluentPerformanceMeter.TestWebAPI31/Startup.cs +++ b/Unchase.FluentPerformanceMeter.TestWebAPI31/Startup.cs @@ -59,6 +59,10 @@ public void ConfigureServices(IServiceCollection services) // set default exception handler for the controller class //options.SetDefaultExceptionHandler((ex) => Debug.WriteLine(ex.Message)); + + // adds a scope service of the PerformanceMeter of concrete class for DI + // use it with ".WithSettingData.CallerFrom(IHttpContextAccessor)" + //options.RegisterPerformanceMeterScope = false; }); //services.AddPerformanceDiagnosticObserver(options => diff --git a/Unchase.FluentPerformanceMeter.TestWebAPI31/Unchase.FluentPerformanceMeter.TestWebAPI31.xml b/Unchase.FluentPerformanceMeter.TestWebAPI31/Unchase.FluentPerformanceMeter.TestWebAPI31.xml index b9f9461..51e7aeb 100644 --- a/Unchase.FluentPerformanceMeter.TestWebAPI31/Unchase.FluentPerformanceMeter.TestWebAPI31.xml +++ b/Unchase.FluentPerformanceMeter.TestWebAPI31/Unchase.FluentPerformanceMeter.TestWebAPI31.xml @@ -123,6 +123,15 @@ Return elapsed total milliseconds for all steps. + + + Test GET method with using HttpContextAccessor and adding step with DI. + + Some value. + + Returns input value. + + Test GET method with using HttpContextAccessor and adding custom data. diff --git a/Unchase.FluentPerformanceMeter/Builders/PerformanceMeterBuilder.cs b/Unchase.FluentPerformanceMeter/Builders/PerformanceMeterBuilder.cs index a5b999b..b7c1d80 100644 --- a/Unchase.FluentPerformanceMeter/Builders/PerformanceMeterBuilder.cs +++ b/Unchase.FluentPerformanceMeter/Builders/PerformanceMeterBuilder.cs @@ -70,6 +70,14 @@ internal PerformanceMeter Start() else throw; } + + if (PerformanceMeter.DefaultOptions?.RegisterPerformanceMeterScope == true) + { + var httpContext = this.PerformanceMeter.HttpContextAccessor?.HttpContext; + if (httpContext != null) + httpContext.Items[$"PerformanceMeter{httpContext.TraceIdentifier}"] = this.PerformanceMeter; + } + return this.PerformanceMeter; } diff --git a/Unchase.FluentPerformanceMeter/PerformanceMeter.cs b/Unchase.FluentPerformanceMeter/PerformanceMeter.cs index 70c09d3..1f4e80a 100644 --- a/Unchase.FluentPerformanceMeter/PerformanceMeter.cs +++ b/Unchase.FluentPerformanceMeter/PerformanceMeter.cs @@ -1335,6 +1335,13 @@ private void Dispose(bool disposing) foreach (var performanceAction in this.RegisteredActions) performanceAction(PerformanceInfo); + + if (DefaultOptions.RegisterPerformanceMeterScope) + { + var httpContext = this.HttpContextAccessor?.HttpContext; + if (httpContext != null && httpContext.Items.ContainsKey($"PerformanceMeter{httpContext.TraceIdentifier}")) + httpContext.Items.Remove($"PerformanceMeter{httpContext.TraceIdentifier}"); + } } } } diff --git a/Unchase.FluentPerformanceMeter/PerformanceMeterBaseOptions.cs b/Unchase.FluentPerformanceMeter/PerformanceMeterBaseOptions.cs index 869c08d..2a880db 100644 --- a/Unchase.FluentPerformanceMeter/PerformanceMeterBaseOptions.cs +++ b/Unchase.FluentPerformanceMeter/PerformanceMeterBaseOptions.cs @@ -43,6 +43,12 @@ public class PerformanceMeterBaseOptions /// public bool AddCustomDataFromCustomAttributes { get; set; } = true; + /// + /// Adds a scope service of the PerformanceMeter of Class. + /// Default value is true. + /// + public bool RegisterPerformanceMeterScope { get; set; } = true; + #endregion #region Methods diff --git a/Unchase.FluentPerformanceMeter/Unchase.FluentPerformanceMeter.csproj b/Unchase.FluentPerformanceMeter/Unchase.FluentPerformanceMeter.csproj index f481049..acaa582 100644 --- a/Unchase.FluentPerformanceMeter/Unchase.FluentPerformanceMeter.csproj +++ b/Unchase.FluentPerformanceMeter/Unchase.FluentPerformanceMeter.csproj @@ -14,9 +14,9 @@ icon.png Apache-2.0 - 2.1.1.0 - 2.1.1.0 - 2.1.1 + 2.1.2.0 + 2.1.2.0 + 2.1.2 Unchase.FluentPerformanceMeter.xml diff --git a/Unchase.FluentPerformanceMeter/Unchase.FluentPerformanceMeter.xml b/Unchase.FluentPerformanceMeter/Unchase.FluentPerformanceMeter.xml index 2a799ca..e89d6b7 100644 --- a/Unchase.FluentPerformanceMeter/Unchase.FluentPerformanceMeter.xml +++ b/Unchase.FluentPerformanceMeter/Unchase.FluentPerformanceMeter.xml @@ -1952,6 +1952,12 @@ Default value is true. + + + Adds a scope service of the PerformanceMeter of Class. + Default value is true. + + Called when passed to .