From 565252382c10020c6899aaece6437758757e1bdc Mon Sep 17 00:00:00 2001 From: Polianin Nikita Date: Mon, 12 Aug 2024 21:54:05 +0300 Subject: [PATCH] feat: add cache control in response --- .../Common/Attributes/CacheMaxAgeAttribute.cs | 26 ++++++ Endpoint/Controllers/V1/ScheduleController.cs | 13 +-- Endpoint/Middleware/CacheMaxAgeMiddleware.cs | 81 +++++++++++++++++++ Endpoint/Program.cs | 3 +- 4 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 Endpoint/Common/Attributes/CacheMaxAgeAttribute.cs create mode 100644 Endpoint/Middleware/CacheMaxAgeMiddleware.cs diff --git a/Endpoint/Common/Attributes/CacheMaxAgeAttribute.cs b/Endpoint/Common/Attributes/CacheMaxAgeAttribute.cs new file mode 100644 index 0000000..f61778f --- /dev/null +++ b/Endpoint/Common/Attributes/CacheMaxAgeAttribute.cs @@ -0,0 +1,26 @@ +using System; + +namespace Mirea.Api.Endpoint.Common.Attributes; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = false)] +public class CacheMaxAgeAttribute : Attribute +{ + public int MaxAge { get; } + + public CacheMaxAgeAttribute(int days = 0, int hours = 0, int minutes = 0) + { + MaxAge = (int)new TimeSpan(days, hours, minutes, 0).TotalSeconds; + } + + public CacheMaxAgeAttribute(int minutes) : this(0, 0, minutes) + { + } + + public CacheMaxAgeAttribute(bool usingSetting = false) + { + if (usingSetting) + MaxAge = -1; + else + MaxAge = 0; + } +} \ No newline at end of file diff --git a/Endpoint/Controllers/V1/ScheduleController.cs b/Endpoint/Controllers/V1/ScheduleController.cs index 0b16686..c4a5941 100644 --- a/Endpoint/Controllers/V1/ScheduleController.cs +++ b/Endpoint/Controllers/V1/ScheduleController.cs @@ -17,11 +17,14 @@ using System.Threading.Tasks; namespace Mirea.Api.Endpoint.Controllers.V1; [ApiVersion("1.0")] +[CacheMaxAge(true)] public class ScheduleController(IMediator mediator, IOptionsSnapshot config) : BaseController { + [CacheMaxAge(1, 0)] [HttpGet("StartTerm")] public ActionResult GetStartTerm() => config.Value.ScheduleSettings!.StartTerm; + [CacheMaxAge(1, 0)] [HttpGet("PairPeriod")] public ActionResult> GetPairPeriod() => config.Value.ScheduleSettings!.PairPeriod.ConvertToDto(); @@ -105,7 +108,7 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot await Get(new ScheduleRequest - { + { Disciplines = disciplines, IsEven = isEven, Groups = [id], @@ -133,7 +136,7 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot await Get(new ScheduleRequest - { + { Disciplines = disciplines, IsEven = isEven, Groups = groups, @@ -161,7 +164,7 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot await Get(new ScheduleRequest - { + { Disciplines = disciplines, IsEven = isEven, Groups = groups, @@ -189,11 +192,11 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot await Get(new ScheduleRequest - { + { Disciplines = [id], IsEven = isEven, Groups = groups, Professors = professors, LectureHalls = lectureHalls }); - } \ No newline at end of file +} \ No newline at end of file diff --git a/Endpoint/Middleware/CacheMaxAgeMiddleware.cs b/Endpoint/Middleware/CacheMaxAgeMiddleware.cs new file mode 100644 index 0000000..0a8f788 --- /dev/null +++ b/Endpoint/Middleware/CacheMaxAgeMiddleware.cs @@ -0,0 +1,81 @@ +using Cronos; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Mirea.Api.Endpoint.Common.Attributes; +using Mirea.Api.Endpoint.Common.Settings; +using System; +using System.Reflection; +using System.Threading.Tasks; + +namespace Mirea.Api.Endpoint.Middleware; + +public class CacheMaxAgeMiddleware(RequestDelegate next, IServiceProvider serviceProvider) +{ + public async Task InvokeAsync(HttpContext context) + { + if (!context.Response.StatusCode.ToString().StartsWith('2')) + { + await next(context); + return; + } + + var endpoint = context.GetEndpoint(); + + var actionDescriptor = endpoint?.Metadata.GetMetadata(); + + if (actionDescriptor == null) + { + await next(context); + return; + } + + var controllerType = actionDescriptor.ControllerTypeInfo; + var methodInfo = actionDescriptor.MethodInfo; + + var maxAgeAttribute = methodInfo.GetCustomAttribute() ?? controllerType.GetCustomAttribute(); + + if (maxAgeAttribute == null) + { + await next(context); + return; + } + + switch (maxAgeAttribute.MaxAge) + { + case < 0: + { + DateTime? nextDate; + var now = DateTime.UtcNow; + + using (var scope = serviceProvider.CreateScope()) + { + var updateCronString = scope.ServiceProvider.GetRequiredService>().Value.ScheduleSettings?.CronUpdateSchedule; + + if (string.IsNullOrEmpty(updateCronString) || + !CronExpression.TryParse(updateCronString, CronFormat.Standard, out var updateCron)) + { + await next(context); + return; + } + + nextDate = updateCron.GetNextOccurrence(now); + } + + if (!nextDate.HasValue) + { + await next(context); + return; + } + + context.Response.Headers.CacheControl = "max-age=" + (int)(nextDate.Value - now).TotalSeconds; + break; + } + case > 0: + context.Response.Headers.CacheControl = "max-age=" + maxAgeAttribute.MaxAge; + break; + } + + await next(context); + } +} \ No newline at end of file diff --git a/Endpoint/Program.cs b/Endpoint/Program.cs index 9883828..1319332 100644 --- a/Endpoint/Program.cs +++ b/Endpoint/Program.cs @@ -125,9 +125,10 @@ public class Program app.UseCustomSwagger(app.Services); - app.UseMiddleware(); app.UseMiddleware(); + app.UseMiddleware(); app.UseMiddleware(); + app.UseMiddleware(); app.UseHttpsRedirection();