feat: add cache control in response
All checks were successful
Build and Deploy Docker Container / build-and-deploy (push) Successful in 1m47s
.NET Test Pipeline / build-and-test (push) Successful in 2m43s

This commit is contained in:
Polianin Nikita 2024-08-12 21:54:05 +03:00
parent 80dc2e412c
commit 565252382c
4 changed files with 117 additions and 6 deletions

View File

@ -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;
}
}

View File

@ -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<GeneralConfig> config) : BaseController
{
[CacheMaxAge(1, 0)]
[HttpGet("StartTerm")]
public ActionResult<DateOnly> GetStartTerm() => config.Value.ScheduleSettings!.StartTerm;
[CacheMaxAge(1, 0)]
[HttpGet("PairPeriod")]
public ActionResult<Dictionary<int, PairPeriodTime>> GetPairPeriod() => config.Value.ScheduleSettings!.PairPeriod.ConvertToDto();
@ -105,7 +108,7 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot<GeneralConf
[FromQuery] int[]? professors = null,
[FromQuery] int[]? lectureHalls = null) =>
await Get(new ScheduleRequest
{
{
Disciplines = disciplines,
IsEven = isEven,
Groups = [id],
@ -133,7 +136,7 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot<GeneralConf
[FromQuery] int[]? groups = null,
[FromQuery] int[]? lectureHalls = null) =>
await Get(new ScheduleRequest
{
{
Disciplines = disciplines,
IsEven = isEven,
Groups = groups,
@ -161,7 +164,7 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot<GeneralConf
[FromQuery] int[]? groups = null,
[FromQuery] int[]? professors = null) =>
await Get(new ScheduleRequest
{
{
Disciplines = disciplines,
IsEven = isEven,
Groups = groups,
@ -189,11 +192,11 @@ public class ScheduleController(IMediator mediator, IOptionsSnapshot<GeneralConf
[FromQuery] int[]? professors = null,
[FromQuery] int[]? lectureHalls = null) =>
await Get(new ScheduleRequest
{
{
Disciplines = [id],
IsEven = isEven,
Groups = groups,
Professors = professors,
LectureHalls = lectureHalls
});
}
}

View File

@ -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<Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor>();
if (actionDescriptor == null)
{
await next(context);
return;
}
var controllerType = actionDescriptor.ControllerTypeInfo;
var methodInfo = actionDescriptor.MethodInfo;
var maxAgeAttribute = methodInfo.GetCustomAttribute<CacheMaxAgeAttribute>() ?? controllerType.GetCustomAttribute<CacheMaxAgeAttribute>();
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<IOptionsSnapshot<GeneralConfig>>().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);
}
}

View File

@ -125,9 +125,10 @@ public class Program
app.UseCustomSwagger(app.Services);
app.UseMiddleware<MaintenanceModeMiddleware>();
app.UseMiddleware<CustomExceptionHandlerMiddleware>();
app.UseMiddleware<MaintenanceModeMiddleware>();
app.UseMiddleware<JwtRevocationMiddleware>();
app.UseMiddleware<CacheMaxAgeMiddleware>();
app.UseHttpsRedirection();