feat(directory): add in-memory api caching

This commit is contained in:
Collin M. Barrett 2020-09-13 06:14:18 -05:00
parent 2a51819b43
commit 9cb9cc1cf6
9 changed files with 72 additions and 22 deletions

View file

@ -0,0 +1,34 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
namespace FilterLists.Directory.Api.Controllers
{
public abstract class BaseController : ControllerBase
{
private readonly IMemoryCache _cache;
protected BaseController(IMemoryCache cache)
{
_cache = cache;
}
/// <remarks>https://stackoverflow.com/a/52506210/2343739</remarks>
protected async Task<IActionResult> CacheGetOrCreateAsync<TResponse>(
Func<Task<TResponse>> actionAsync,
int? keySuffix = default,
TimeSpan? absoluteExpirationRelativeToNow = default,
[CallerMemberName] string key = default!)
{
var cacheKey = $"{GetType().Name}_{key}{(keySuffix is null ? string.Empty : $"_{keySuffix}")}";
var result = await _cache.GetOrCreateAsync(cacheKey, entry =>
{
entry.AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow;
return actionAsync();
});
return result is null ? NotFound() : (IActionResult)Ok(result);
}
}
}

View file

@ -5,25 +5,27 @@
using FilterLists.Directory.Application.Queries;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
namespace FilterLists.Directory.Api.Controllers
{
[ApiController]
[Route("[controller]")]
public class LanguagesController : ControllerBase
public class LanguagesController : BaseController
{
private readonly IMediator _mediator;
public LanguagesController(IMediator mediator)
public LanguagesController(IMemoryCache cache, IMediator mediator) : base(cache)
{
_mediator = mediator;
}
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<GetLanguages.LanguageVm>), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
return Ok(await _mediator.Send(new GetLanguages.Query(), cancellationToken));
return await CacheGetOrCreateAsync(() => _mediator.Send(new GetLanguages.Query(), cancellationToken));
}
}
}

View file

@ -5,25 +5,27 @@
using FilterLists.Directory.Application.Queries;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
namespace FilterLists.Directory.Api.Controllers
{
[ApiController]
[Route("[controller]")]
public class LicensesController : ControllerBase
public class LicensesController : BaseController
{
private readonly IMediator _mediator;
public LicensesController(IMediator mediator)
public LicensesController(IMemoryCache cache, IMediator mediator) : base(cache)
{
_mediator = mediator;
}
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<GetLicenses.LicenseVm>), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
return Ok(await _mediator.Send(new GetLicenses.Query(), cancellationToken));
return await CacheGetOrCreateAsync(() => _mediator.Send(new GetLicenses.Query(), cancellationToken));
}
}
}

View file

@ -6,32 +6,35 @@
using FilterLists.SharedKernel.Apis.Contracts.Directory;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
namespace FilterLists.Directory.Api.Controllers
{
[ApiController]
[Route("[controller]")]
public class ListsController : ControllerBase
public class ListsController : BaseController
{
private readonly IMediator _mediator;
public ListsController(IMediator mediator)
public ListsController(IMemoryCache cache, IMediator mediator) : base(cache)
{
_mediator = mediator;
}
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<GetLists.ListVm>), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
return Ok(await _mediator.Send(new GetLists.Query(), cancellationToken));
return await CacheGetOrCreateAsync(() => _mediator.Send(new GetLists.Query(), cancellationToken));
}
[HttpGet("{id}")]
[ProducesResponseType(typeof(ListDetailsVm), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> GetDetails(int id, CancellationToken cancellationToken)
{
return Ok(await _mediator.Send(new GetListDetails.Query(id), cancellationToken));
return await CacheGetOrCreateAsync(() => _mediator.Send(new GetListDetails.Query(id), cancellationToken), id);
}
}
}

View file

@ -5,25 +5,27 @@
using FilterLists.Directory.Application.Queries;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
namespace FilterLists.Directory.Api.Controllers
{
[ApiController]
[Route("[controller]")]
public class MaintainersController : ControllerBase
public class MaintainersController : BaseController
{
private readonly IMediator _mediator;
public MaintainersController(IMediator mediator)
public MaintainersController(IMemoryCache cache, IMediator mediator) : base(cache)
{
_mediator = mediator;
}
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<GetMaintainers.MaintainerVm>), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
return Ok(await _mediator.Send(new GetMaintainers.Query(), cancellationToken));
return await CacheGetOrCreateAsync(() => _mediator.Send(new GetMaintainers.Query(), cancellationToken));
}
}
}

View file

@ -5,25 +5,27 @@
using FilterLists.Directory.Application.Queries;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
namespace FilterLists.Directory.Api.Controllers
{
[ApiController]
[Route("[controller]")]
public class SoftwareController : ControllerBase
public class SoftwareController : BaseController
{
private readonly IMediator _mediator;
public SoftwareController(IMediator mediator)
public SoftwareController(IMemoryCache cache, IMediator mediator) : base(cache)
{
_mediator = mediator;
}
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<GetSoftware.SoftwareVm>), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
return Ok(await _mediator.Send(new GetSoftware.Query(), cancellationToken));
return await CacheGetOrCreateAsync(() => _mediator.Send(new GetSoftware.Query(), cancellationToken));
}
}
}

View file

@ -5,25 +5,27 @@
using FilterLists.Directory.Application.Queries;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
namespace FilterLists.Directory.Api.Controllers
{
[ApiController]
[Route("[controller]")]
public class SyntaxesController : ControllerBase
public class SyntaxesController : BaseController
{
private readonly IMediator _mediator;
public SyntaxesController(IMediator mediator)
public SyntaxesController(IMemoryCache cache, IMediator mediator) : base(cache)
{
_mediator = mediator;
}
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<GetSyntaxes.SyntaxVm>), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
return Ok(await _mediator.Send(new GetSyntaxes.Query(), cancellationToken));
return await CacheGetOrCreateAsync(() => _mediator.Send(new GetSyntaxes.Query(), cancellationToken));
}
}
}

View file

@ -5,25 +5,27 @@
using FilterLists.Directory.Application.Queries;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
namespace FilterLists.Directory.Api.Controllers
{
[ApiController]
[Route("[controller]")]
public class TagsController : ControllerBase
public class TagsController : BaseController
{
private readonly IMediator _mediator;
public TagsController(IMediator mediator)
public TagsController(IMemoryCache cache, IMediator mediator) : base(cache)
{
_mediator = mediator;
}
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<GetTags.TagVm>), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
return Ok(await _mediator.Send(new GetTags.Query(), cancellationToken));
return await CacheGetOrCreateAsync(() => _mediator.Send(new GetTags.Query(), cancellationToken));
}
}
}

View file

@ -18,6 +18,7 @@ public Startup(IConfiguration configuration)
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddRouting(o => o.LowercaseUrls = true);
services.AddControllers()
.AddJsonOptions(o => o.JsonSerializerOptions.IgnoreNullValues = true);