caching for banners and images

This commit is contained in:
Hamid Reza Mohammadi 2021-05-19 15:25:53 +04:30
parent afb21e566a
commit 36f54a0c95
6 changed files with 112 additions and 114 deletions

View File

@ -9,69 +9,5 @@
"AllowedHosts": "*",
"GoogleAnalyticsCode": "",
"APIRoot": "http://localhost:3439",
"GlobalAPIRoot": "https://ganjgah.ir",
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=museum;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"PictureFileService": {
"StoragePath": "C:\\museum",
"ResizedImageContentType": "image/jpeg",
"NormalImageMaxWidth": "800",
"NormalImageMaxHeight": "1350",
"ThumbnailImageWidth": "300",
"ThumbnailMaxHeight": "500"
},
"Security": {
"Secret": "k4Fy7pDsc0LgXQ8PCCfZtwmju5Ed8asc",
"DefaultTokenExpirationInSeconds": "3600"
},
"SmptConfig": {
"Server": "smtp.gmail.com",
"Port": "587",
"UseSsl": "true",
"UseTls": "true",
"Username": "test@gmail.com",
"Password": "password",
"From": "test@gmail.com"
},
"LocalSqliteImport": {
"FilePath": "C:\\Users\\moham\\AppData\\Local\\ganjoor\\ganjoor\\ganjoor.s3db"
},
"IIS": {
"UploadLimit": "52428800"
},
"AudioMySqlServer": {
"Server": "localhost",
"Username": "root",
"Password": "",
"Database": "adab",
"2ndDatabase": "audio",
"2ndUsername": "audio",
"2ndPassword": "",
"SongsDatabase": "golha",
"SongsUsername": "root",
"SongsPassword": "",
"ReportedCommentsDatabase": "rpcmnts",
"ReportedCommentsUsername": "root",
"ReportedCommentsPassword": "",
"PoetImagesImportPath": "C:\\Users\\moham\\source\\repos\\GanjooRazor\\wwwroot\\image\\poets"
},
"AudioSFPServer": {
"Host": "localhost",
"Port": "22",
"Username": "root",
"Password": "",
"RootPath": "/home"
},
"AudioUploadService": {
"Enabled": "True",
"TempUploadPath": "C:\\tempaudio",
"LocalAudioRepositoryPath": "D:\\My Documents\\My Web Design\\ganjoor\\www\\i",
"CurrentSoundFilesFolder": "a2"
},
"SignUp": {
"Enabled": "True",
"VerifyEmail": "True"
}
"GlobalAPIRoot": "http://localhost:3439"
}

View File

@ -1,8 +1,7 @@
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using RSecurityBackend.Services;
using RSecurityBackend.Controllers;
using Audit.WebApi;
using Microsoft.Extensions.Caching.Memory;
namespace RMuseum.Controllers
{
@ -13,12 +12,12 @@ namespace RMuseum.Controllers
[Route("api/rimages")]
public class RImageController : RImageControllerBase
{
/// <summary>
/// constructor
/// </summary>
/// <param name="pictureFileService">
/// </param>
public RImageController(IImageFileService pictureFileService) : base(pictureFileService)
/// <summary>
/// constructor
/// </summary>
/// <param name="pictureFileService"></param>
/// <param name="memoryCache"></param>
public RImageController(IImageFileService pictureFileService, IMemoryCache memoryCache) : base(pictureFileService, memoryCache)
{
}

View File

@ -1225,12 +1225,12 @@
Generic Image Provider
</summary>
</member>
<member name="M:RMuseum.Controllers.RImageController.#ctor(RSecurityBackend.Services.IImageFileService)">
<member name="M:RMuseum.Controllers.RImageController.#ctor(RSecurityBackend.Services.IImageFileService,Microsoft.Extensions.Caching.Memory.IMemoryCache)">
<summary>
constructor
</summary>
<param name="pictureFileService">
</param>
<param name="pictureFileService"></param>
<param name="memoryCache"></param>
</member>
<member name="T:RMuseum.Controllers.RLongRunningJobsController">
<summary>

View File

@ -38,7 +38,6 @@ namespace RMuseum.Services.Implementation
return new RServiceResult<GanjoorSiteBannerViewModel>(null, image.ExceptionString);
}
GanjoorSiteBanner banner = new GanjoorSiteBanner()
{
RImage = image.Result,
@ -50,6 +49,8 @@ namespace RMuseum.Services.Implementation
_context.GanjoorSiteBanners.Add(banner);
await _context.SaveChangesAsync();
await CleanBannersCache();
return new RServiceResult<GanjoorSiteBannerViewModel>
(
new GanjoorSiteBannerViewModel()
@ -93,6 +94,8 @@ namespace RMuseum.Services.Implementation
await _context.SaveChangesAsync();
await CleanBannersCache();
return new RServiceResult<bool>(true);
}
@ -119,6 +122,8 @@ namespace RMuseum.Services.Implementation
await _context.SaveChangesAsync();
await CleanBannersCache();
return new RServiceResult<bool>(true);
}
@ -154,6 +159,30 @@ namespace RMuseum.Services.Implementation
}
}
private const string _cacheKeyForIdSet = "SiteBannersService::GetARandomActiveSiteBanner::idSet";
private static string GetBannerCacheKey(int bannerId)
{
return $"SiteBannersService::BannerCacheKey::{bannerId}";
}
private async Task CleanBannersCache()
{
int[] idSet = await _context.GanjoorSiteBanners.Select(b => b.Id).ToArrayAsync();
foreach(int id in idSet)
{
var cacheKey = GetBannerCacheKey(id);
if(_memoryCache.TryGetValue(id, out GanjoorSiteBannerViewModel o))
{
_memoryCache.Remove(id);
}
}
if (_memoryCache.TryGetValue(_cacheKeyForIdSet, out idSet))
{
_memoryCache.Remove(_cacheKeyForIdSet);
}
}
/// <summary>
/// get a random site banner
/// </summary>
@ -162,30 +191,37 @@ namespace RMuseum.Services.Implementation
{
try
{
var cacheKeyForIdSet = $"GetARandomActiveSiteBanner::idSet";
if (!_memoryCache.TryGetValue(cacheKeyForIdSet, out int[] idSet))
if (!_memoryCache.TryGetValue(_cacheKeyForIdSet, out int[] idSet))
{
idSet = await _context.GanjoorSiteBanners.Where(b => b.Active == true).Select(b => b.Id).ToArrayAsync();
_memoryCache.Set(cacheKeyForIdSet, idSet);
_memoryCache.Set(_cacheKeyForIdSet, idSet);
}
if (idSet.Length == 0)
return new RServiceResult<GanjoorSiteBannerViewModel>(null);//not found
return new RServiceResult<GanjoorSiteBannerViewModel>(null);//no active banner
Random rnd = new Random(DateTime.Now.Millisecond);
int id = idSet[rnd.Next(0, idSet.Length)];
return new RServiceResult<GanjoorSiteBannerViewModel>(
await _context.GanjoorSiteBanners
.Where(b => b.Id == id)
.Select(b => new GanjoorSiteBannerViewModel()
{
Id = b.Id,
ImageUrl = $"api/rimages/{b.RImageId}.jpg",
AlternateText = b.AlternateText,
TargetUrl = b.TargetUrl,
Active = b.Active
}).AsNoTracking().SingleAsync()
);
var cachKey = GetBannerCacheKey(id);
if (!_memoryCache.TryGetValue(cachKey, out GanjoorSiteBannerViewModel banner))
{
banner =
await _context.GanjoorSiteBanners
.Where(b => b.Id == id)
.Select(b => new GanjoorSiteBannerViewModel()
{
Id = b.Id,
ImageUrl = $"api/rimages/{b.RImageId}.jpg",
AlternateText = b.AlternateText,
TargetUrl = b.TargetUrl,
Active = b.Active
})
.AsNoTracking()
.SingleAsync();
_memoryCache.Set(cachKey, banner);
}
return new RServiceResult<GanjoorSiteBannerViewModel>(banner);
}
catch (Exception exp)

View File

@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using RSecurityBackend.Models.Auth.Memory;
using RSecurityBackend.Models.Generic;
using RSecurityBackend.Models.Image;
@ -30,30 +31,45 @@ namespace RSecurityBackend.Controllers
[ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))]
public async Task<IActionResult> Get(Guid id)
{
RServiceResult<RImage> img =
await _pictureFileService.GetImage(id);
var cachKey = $"RImageControllerBase::RImage::{id}";
if(!_memoryCache.TryGetValue(cachKey, out RImage img))
{
RServiceResult<RImage> imgRes =
await _pictureFileService.GetImage(id);
if (!string.IsNullOrEmpty(img.ExceptionString))
return BadRequest(img.ExceptionString);
if (!string.IsNullOrEmpty(imgRes.ExceptionString))
return BadRequest(imgRes.ExceptionString);
if (img.Result == null)
return NotFound();
if (imgRes.Result == null)
return NotFound();
Response.GetTypedHeaders().LastModified = img.Result.LastModified;
img = imgRes.Result;
_memoryCache.Set(cachKey, img);
}
var cachKeyForPath = $"RImageControllerBase::Path::{id}";
if (!_memoryCache.TryGetValue(cachKeyForPath, out string imgPath))
{
RServiceResult<string> imgPathRes = _pictureFileService.GetImagePath(img);
if (!string.IsNullOrEmpty(imgPathRes.ExceptionString))
return BadRequest(imgPathRes.ExceptionString);
imgPath = imgPathRes.Result;
_memoryCache.Set(cachKeyForPath, imgPath);
}
Response.GetTypedHeaders().LastModified = img.LastModified;
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
requestHeaders.IfModifiedSince.Value >= img.Result.LastModified)
requestHeaders.IfModifiedSince.Value >= img.LastModified)
{
return StatusCode(StatusCodes.Status304NotModified);
}
RServiceResult<string> imgPath = _pictureFileService.GetImagePath(img.Result);
if (!string.IsNullOrEmpty(imgPath.ExceptionString))
return BadRequest(imgPath.ExceptionString);
return new FileStreamResult(new FileStream(imgPath.Result, FileMode.Open, FileAccess.Read), "image/jpeg");
return new FileStreamResult(new FileStream(imgPath, FileMode.Open, FileAccess.Read), "image/jpeg");
}
@ -105,11 +121,12 @@ namespace RSecurityBackend.Controllers
/// <summary>
/// constructor
/// </summary>
/// <param name="pictureFileService">
/// </param>
public RImageControllerBase(IImageFileService pictureFileService)
/// <param name="pictureFileService"></param>
/// <param name="memoryCache"></param>
public RImageControllerBase(IImageFileService pictureFileService, IMemoryCache memoryCache)
{
_pictureFileService = pictureFileService;
_memoryCache = memoryCache;
}
/// <summary>
@ -117,6 +134,11 @@ namespace RSecurityBackend.Controllers
/// </summary>
protected readonly IImageFileService _pictureFileService;
/// <summary>
/// IMemoryCache
/// </summary>
protected readonly IMemoryCache _memoryCache;
}
}

View File

@ -444,18 +444,23 @@
</summary>
<returns></returns>
</member>
<member name="M:RSecurityBackend.Controllers.RImageControllerBase.#ctor(RSecurityBackend.Services.IImageFileService)">
<member name="M:RSecurityBackend.Controllers.RImageControllerBase.#ctor(RSecurityBackend.Services.IImageFileService,Microsoft.Extensions.Caching.Memory.IMemoryCache)">
<summary>
constructor
</summary>
<param name="pictureFileService">
</param>
<param name="pictureFileService"></param>
<param name="memoryCache"></param>
</member>
<member name="F:RSecurityBackend.Controllers.RImageControllerBase._pictureFileService">
<summary>
Artifact Service
</summary>
</member>
<member name="F:RSecurityBackend.Controllers.RImageControllerBase._memoryCache">
<summary>
IMemoryCache
</summary>
</member>
<member name="T:RSecurityBackend.Controllers.RLongRunningJobsControllerBase">
<summary>
Long Running Jobs