diff --git a/3.1.png b/3.1.png new file mode 100644 index 0000000..938ac35 Binary files /dev/null and b/3.1.png differ diff --git a/3.2.png b/3.2.png new file mode 100644 index 0000000..107fbac Binary files /dev/null and b/3.2.png differ diff --git a/TaskHub/Api/Api.csproj b/TaskHub/Api/Api.csproj index a6946fa..c8bbecd 100644 --- a/TaskHub/Api/Api.csproj +++ b/TaskHub/Api/Api.csproj @@ -1,7 +1,7 @@ - + - net10.0 + net8.0 enable enable @@ -12,7 +12,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/TaskHub/Api/Controllers/Users/UsersController.cs b/TaskHub/Api/Controllers/Users/UsersController.cs index 10a433a..b139e87 100644 --- a/TaskHub/Api/Controllers/Users/UsersController.cs +++ b/TaskHub/Api/Controllers/Users/UsersController.cs @@ -1,3 +1,4 @@ +using Api.Filters; using Api.Controllers.Users.Request; using Api.Controllers.Users.Response; using Api.UseCases.Users.Interfaces; @@ -5,6 +6,9 @@ namespace Api.Controllers.Users; +[ResponseTimeHeader] +[StudentInfoHeaders] + /// /// Контроллер работы с пользователями /// @@ -29,6 +33,7 @@ public UsersController(IManageUserUseCase userUseCase) /// Токен отмены /// Созданный пользователь [HttpPost] + [SetName] public async Task> CreateUserAsync( [FromBody] CreateUserRequest? request, CancellationToken cancellationToken) diff --git a/TaskHub/Api/Filters/ResponseTimeHeaderAttribute.cs b/TaskHub/Api/Filters/ResponseTimeHeaderAttribute.cs new file mode 100644 index 0000000..79b610a --- /dev/null +++ b/TaskHub/Api/Filters/ResponseTimeHeaderAttribute.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Mvc.Filters; +using System.Diagnostics; + +namespace Api.Filters +{ + public class ResponseTimeHeaderAttribute : ActionFilterAttribute + { + private Stopwatch _stopwatch; + + public override void OnActionExecuting(ActionExecutingContext context) + { + _stopwatch = Stopwatch.StartNew(); + } + + public override void OnActionExecuted(ActionExecutedContext context) + { + _stopwatch.Stop(); + + context.HttpContext.Response.Headers["X-Response-Time-Ms"] = + _stopwatch.ElapsedMilliseconds.ToString(); + } + } +} diff --git a/TaskHub/Api/Filters/SetNameAttribute.cs b/TaskHub/Api/Filters/SetNameAttribute.cs new file mode 100644 index 0000000..523ccb1 --- /dev/null +++ b/TaskHub/Api/Filters/SetNameAttribute.cs @@ -0,0 +1,6 @@ +namespace Api.Filters +{ + public class SetNameAttribute : ValidateUserRequestAttribute + { + } +} diff --git a/TaskHub/Api/Filters/StudentInfoHeadersAttribute.cs b/TaskHub/Api/Filters/StudentInfoHeadersAttribute.cs new file mode 100644 index 0000000..35488c3 --- /dev/null +++ b/TaskHub/Api/Filters/StudentInfoHeadersAttribute.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Api.Filters +{ + public class StudentInfoHeadersAttribute : ActionFilterAttribute + { + public override void OnActionExecuted(ActionExecutedContext context) + { + var headers = context.HttpContext.Request.Headers; + + headers["X-Student-Name"] = "Tumashova Marina"; + headers["X-Student-Group"] = "RI-240912"; + } + } +} diff --git a/TaskHub/Api/Filters/ValidateUserRequestAttribute.cs b/TaskHub/Api/Filters/ValidateUserRequestAttribute.cs new file mode 100644 index 0000000..8d44de0 --- /dev/null +++ b/TaskHub/Api/Filters/ValidateUserRequestAttribute.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using System.Reflection; + +namespace Api.Filters +{ + public class ValidateUserRequestAttribute : ActionFilterAttribute + { + public override void OnActionExecuting(ActionExecutingContext context) + { + var request = context.ActionArguments.Values.FirstOrDefault(); + + if (request == null) + { + context.Result = new BadRequestObjectResult("нет тела запроса"); + return; + } + + var nameProperty = request.GetType().GetProperty("Name"); + + if (nameProperty == null) + { + return; + } + + var nameValue = nameProperty.GetValue(request)?.ToString(); + + if (string.IsNullOrWhiteSpace(nameValue)) + { + context.Result = new BadRequestObjectResult("нет имени"); + } + } + } +} diff --git a/TaskHub/Api/Middleware/ResponseTimeMiddleware.cs.cs b/TaskHub/Api/Middleware/ResponseTimeMiddleware.cs.cs new file mode 100644 index 0000000..1f1b9d1 --- /dev/null +++ b/TaskHub/Api/Middleware/ResponseTimeMiddleware.cs.cs @@ -0,0 +1,28 @@ +using System.Diagnostics; + +namespace Api.Middleware +{ + public class ResponseTimeMiddleware + { + private readonly RequestDelegate _next; + + public ResponseTimeMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task InvokeAsync(HttpContext context) + { + var stopwatch = Stopwatch.StartNew(); + + context.Response.OnStarting(() => + { + stopwatch.Stop(); + context.Response.Headers["X-Response-Time-Ms"] = stopwatch.ElapsedMilliseconds.ToString(); + return Task.CompletedTask; + }); + + await _next(context); + } + } +} diff --git a/TaskHub/Api/Middleware/StudentInfoMiddleware.cs b/TaskHub/Api/Middleware/StudentInfoMiddleware.cs new file mode 100644 index 0000000..23db0ab --- /dev/null +++ b/TaskHub/Api/Middleware/StudentInfoMiddleware.cs @@ -0,0 +1,24 @@ +namespace Api.Middleware +{ + public class StudentInfoMiddleware + { + private readonly RequestDelegate _next; + + public StudentInfoMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task InvokeAsync(HttpContext context) + { + context.Response.OnStarting(() => + { + context.Response.Headers["X-Student-Name"] = "Tumashova Marina"; + context.Response.Headers["X-Student-Group"] = "RI-240912"; + return Task.CompletedTask; + }); + + await _next(context); + } + } +} diff --git a/TaskHub/Api/Services/DisposedService.cs b/TaskHub/Api/Services/DisposedService.cs new file mode 100644 index 0000000..9a2ce8d --- /dev/null +++ b/TaskHub/Api/Services/DisposedService.cs @@ -0,0 +1,18 @@ +namespace Api.Services +{ + public abstract class DisposedService : IHasInstanceId, IDisposable + { + public Guid InstanceId { get; } = Guid.NewGuid(); + + protected DisposedService() + { + Console.WriteLine($"{GetType().Name} CREATED:{InstanceId}"); + } + + public void Dispose() + { + Console.WriteLine($"{GetType().Name} DISPOSED: {InstanceId}"); + } + } +} + diff --git a/TaskHub/Api/Services/IHasInstanceId.cs b/TaskHub/Api/Services/IHasInstanceId.cs new file mode 100644 index 0000000..d5abf99 --- /dev/null +++ b/TaskHub/Api/Services/IHasInstanceId.cs @@ -0,0 +1,7 @@ +namespace Api.Services +{ + public interface IHasInstanceId + { + Guid InstanceId { get; } + } +} diff --git a/TaskHub/Api/Services/ServiceProviderExtensions.cs b/TaskHub/Api/Services/ServiceProviderExtensions.cs new file mode 100644 index 0000000..9e0da57 --- /dev/null +++ b/TaskHub/Api/Services/ServiceProviderExtensions.cs @@ -0,0 +1,17 @@ +namespace Api.Services +{ + public static class ServiceProviderExtensions + { + public static void CompareServices(this IServiceProvider provider) + where T : IHasInstanceId + { + var first = provider.GetRequiredService(); + var second = provider.GetRequiredService(); + + Console.WriteLine($"Service: {typeof(T).Name}"); + Console.WriteLine($"First: {first.InstanceId}"); + Console.WriteLine($"Second: {second.InstanceId}"); + Console.WriteLine($"Same instance: {ReferenceEquals(first, second)}"); + } + } +} diff --git a/TaskHub/Api/Services/Services.cs b/TaskHub/Api/Services/Services.cs new file mode 100644 index 0000000..7a9a5eb --- /dev/null +++ b/TaskHub/Api/Services/Services.cs @@ -0,0 +1,20 @@ +namespace Api.Services +{ + public interface ISingletonService1 : IHasInstanceId { } + public interface ISingletonService2 : IHasInstanceId { } + + public interface IScopedService1 : IHasInstanceId { } + public interface IScopedService2 : IHasInstanceId { } + + public interface ITransientService1 : IHasInstanceId { } + public interface ITransientService2 : IHasInstanceId { } + + public class SingletonService1 : DisposedService, ISingletonService1 { } + public class SingletonService2 : DisposedService, ISingletonService2 { } + + public class ScopedService1 : DisposedService, IScopedService1 { } + public class ScopedService2 : DisposedService, IScopedService2 { } + + public class TransientService1 : DisposedService, ITransientService1 { } + public class TransientService2 : DisposedService, ITransientService2 { } +} diff --git a/TaskHub/Api/StartUp.cs b/TaskHub/Api/StartUp.cs index 9220ca4..7ee8fb3 100644 --- a/TaskHub/Api/StartUp.cs +++ b/TaskHub/Api/StartUp.cs @@ -1,3 +1,5 @@ +using Api.Middleware; +using Api.Services; using Api.UseCases.Users; using Api.UseCases.Users.Interfaces; using Dal; @@ -61,6 +63,15 @@ public void ConfigureServices(IServiceCollection services) Version = "v1" }); }); + + services.AddSingleton(); + services.AddSingleton(); + + services.AddScoped(); + services.AddScoped(); + + services.AddTransient(); + services.AddTransient(); } /// @@ -69,6 +80,38 @@ public void ConfigureServices(IServiceCollection services) /// Построитель приложения public void Configure(IApplicationBuilder app) { + using (var scope1 = app.ApplicationServices.CreateScope()) + { + var provider = scope1.ServiceProvider; + + Console.WriteLine("SCOPE 1"); + + provider.CompareServices(); + provider.CompareServices(); + + provider.CompareServices(); + provider.CompareServices(); + + provider.CompareServices(); + provider.CompareServices(); + } + + using (var scope2 = app.ApplicationServices.CreateScope()) + { + var provider = scope2.ServiceProvider; + + Console.WriteLine("SCOPE 2"); + + provider.CompareServices(); + provider.CompareServices(); + + provider.CompareServices(); + provider.CompareServices(); + + provider.CompareServices(); + provider.CompareServices(); + } + if (Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); @@ -81,6 +124,9 @@ public void Configure(IApplicationBuilder app) app.UseRouting(); + app.UseMiddleware(); + app.UseMiddleware(); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); diff --git a/TaskHub/Dal/Dal.csproj b/TaskHub/Dal/Dal.csproj index edb5ba8..1c690cf 100644 --- a/TaskHub/Dal/Dal.csproj +++ b/TaskHub/Dal/Dal.csproj @@ -1,14 +1,14 @@  - net10.0 + net8.0 enable enable - - + + diff --git a/TaskHub/Libs/DatabaseLibrary/DatabaseLibrary.csproj b/TaskHub/Libs/DatabaseLibrary/DatabaseLibrary.csproj index 0c323c8..012f0c1 100644 --- a/TaskHub/Libs/DatabaseLibrary/DatabaseLibrary.csproj +++ b/TaskHub/Libs/DatabaseLibrary/DatabaseLibrary.csproj @@ -1,14 +1,14 @@  - net10.0 + net8.0 enable enable - - + + diff --git a/TaskHub/Libs/LoggingLibrary/LoggingLibrary.csproj b/TaskHub/Libs/LoggingLibrary/LoggingLibrary.csproj index bf06657..ff7786d 100644 --- a/TaskHub/Libs/LoggingLibrary/LoggingLibrary.csproj +++ b/TaskHub/Libs/LoggingLibrary/LoggingLibrary.csproj @@ -1,15 +1,15 @@  - net10.0 + net8.0 enable enable - + - + diff --git a/TaskHub/Logic/Logic.csproj b/TaskHub/Logic/Logic.csproj index a38dfe4..2be5253 100644 --- a/TaskHub/Logic/Logic.csproj +++ b/TaskHub/Logic/Logic.csproj @@ -5,11 +5,11 @@ - + - net10.0 + net8.0 enable enable