caching for pages

This commit is contained in:
Hamid Reza Mohammadi 2021-05-15 14:35:08 +04:30
parent 348720fc55
commit de861ccd88
7 changed files with 274 additions and 93 deletions

View File

@ -6,6 +6,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RMuseum.Models.Ganjoor;
using RMuseum.Models.Ganjoor.ViewModels;
using RMuseum.Services;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
@ -14,6 +15,13 @@ namespace GanjooRazor.Areas.Admin.Pages
{
public class ModifyPageModel : PageModel
{
/// <summary>
/// ganjoor service
/// </summary>
private readonly IGanjoorService _ganjoorService;
/// <summary>
/// HttpClient instance
/// </summary>
@ -23,9 +31,11 @@ namespace GanjooRazor.Areas.Admin.Pages
/// constructor
/// </summary>
/// <param name="httpClient"></param>
public ModifyPageModel(HttpClient httpClient)
/// <param name="ganjoorService"></param>
public ModifyPageModel(HttpClient httpClient, IGanjoorService ganjoorService)
{
_httpClient = httpClient;
_ganjoorService = ganjoorService;
}
/// <summary>
@ -109,6 +119,7 @@ namespace GanjooRazor.Areas.Admin.Pages
}
else
{
await _ganjoorService.CacheCleanForPageById(int.Parse(Request.Query["id"]));
return Redirect($"/Admin/ModifyPage?id={Request.Query["id"]}&edit=true");
}
}

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RMuseum.Models.Ganjoor.ViewModels;
using RMuseum.Services;
using RSecurityBackend.Models.Generic;
namespace GanjooRazor.Areas.User.Pages
@ -19,6 +20,19 @@ namespace GanjooRazor.Areas.User.Pages
[IgnoreAntiforgeryToken(Order = 1001)]
public class MyCommentsModel : PageModel
{
/// <summary>
/// ganjoor service
/// </summary>
private readonly IGanjoorService _ganjoorService;
/// <summary>
/// constructor
/// </summary>
/// <param name="ganjoorService"></param>
public MyCommentsModel(IGanjoorService ganjoorService)
{
_ganjoorService = ganjoorService;
}
// <summary>
/// Last Error
/// </summary>
@ -143,6 +157,7 @@ namespace GanjooRazor.Areas.User.Pages
{
if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response))
{
await _ganjoorService.CacheCleanForComment(id);
var response = await secureClient.DeleteAsync($"{APIRoot.Url}/api/ganjoor/comment?id={id}");
if (response.StatusCode != HttpStatusCode.OK)
@ -161,6 +176,7 @@ namespace GanjooRazor.Areas.User.Pages
{
if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response))
{
await _ganjoorService.CacheCleanForComment(id);
var response = await secureClient.PutAsync($"{APIRoot.Url}/api/ganjoor/comment/{id}", new StringContent(JsonConvert.SerializeObject(comment), Encoding.UTF8, "application/json"));
if (response.StatusCode != HttpStatusCode.OK)
{

View File

@ -13,12 +13,27 @@ using Newtonsoft.Json.Linq;
using RMuseum.Models.Ganjoor.ViewModels;
using RSecurityBackend.Models.Generic;
using System.Text;
using RMuseum.Services;
namespace GanjooRazor.Areas.User.Pages
{
[IgnoreAntiforgeryToken(Order = 1001)]
public class ReportedCommentsModel : PageModel
{
/// <summary>
/// ganjoor service
/// </summary>
private readonly IGanjoorService _ganjoorService;
/// <summary>
/// constructor
/// </summary>
/// <param name="ganjoorService"></param>
public ReportedCommentsModel(IGanjoorService ganjoorService)
{
_ganjoorService = ganjoorService;
}
/// <summary>
/// Last Error
/// </summary>
@ -156,6 +171,8 @@ namespace GanjooRazor.Areas.User.Pages
reason = reasonText;
break;
}
await _ganjoorService.CacheCleanForComment(id);
var response = await secureClient.PostAsync($"{APIRoot.Url}/api/ganjoor/comment/moderate/{id}", new StringContent(JsonConvert.SerializeObject(reason), Encoding.UTF8, "application/json"));
if (response.StatusCode != HttpStatusCode.OK)
@ -174,6 +191,7 @@ namespace GanjooRazor.Areas.User.Pages
{
if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response))
{
await _ganjoorService.CacheCleanForComment(id);
var response = await secureClient.DeleteAsync($"{APIRoot.Url}/api/ganjoor/comment/report/{id}");
if (response.StatusCode != HttpStatusCode.OK)

View File

@ -222,6 +222,7 @@ namespace GanjooRazor.Pages
}
),
Encoding.UTF8, "application/json");
await _ganjoorService.CacheCleanForPageById(poemId);
var response = await secureClient.PostAsync($"{APIRoot.Url}/api/ganjoor/comment", stringContent);
if (response.StatusCode == HttpStatusCode.OK)
{
@ -289,6 +290,7 @@ namespace GanjooRazor.Pages
{
if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response))
{
await _ganjoorService.CacheCleanForComment(id);
var response = await secureClient.DeleteAsync($"{APIRoot.Url}/api/ganjoor/comment?id={id}");
if (response.StatusCode != HttpStatusCode.OK)
@ -313,6 +315,7 @@ namespace GanjooRazor.Pages
{
if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response))
{
await _ganjoorService.CacheCleanForComment(id);
var response = await secureClient.PutAsync($"{APIRoot.Url}/api/ganjoor/comment/{id}", new StringContent(JsonConvert.SerializeObject(comment), Encoding.UTF8, "application/json"));
if (response.StatusCode != HttpStatusCode.OK)
{

View File

@ -6841,6 +6841,26 @@
</summary>
<returns></returns>
</member>
<member name="M:RMuseum.Services.IGanjoorService.CacheCleanForPageById(System.Int32)">
<summary>
clean cache for paeg by id
</summary>
<param name="id"></param>
<returns></returns>
</member>
<member name="M:RMuseum.Services.IGanjoorService.CacheCleanForPageByUrl(System.String)">
<summary>
clean cache for page by url
</summary>
<param name="url"></param>
</member>
<member name="M:RMuseum.Services.IGanjoorService.CacheCleanForComment(System.Int32)">
<summary>
clean cache for page by comment
</summary>
<param name="commentId"></param>
<returns></returns>
</member>
<member name="M:RMuseum.Services.IGanjoorService.GetVersesByQuery(System.String,System.Int32,RSecurityBackend.Models.Generic.PagingParameterModel)">
<summary>
Get Verses By query
@ -7646,6 +7666,26 @@
<param name="id"></param>
<returns></returns>
</member>
<member name="M:RMuseum.Services.Implementation.GanjoorService.CacheCleanForPageById(System.Int32)">
<summary>
clean cache for paeg by id
</summary>
<param name="id"></param>
<returns></returns>
</member>
<member name="M:RMuseum.Services.Implementation.GanjoorService.CacheCleanForPageByUrl(System.String)">
<summary>
clean cache for page by url
</summary>
<param name="url"></param>
</member>
<member name="M:RMuseum.Services.Implementation.GanjoorService.CacheCleanForComment(System.Int32)">
<summary>
clean cache for page by comment
</summary>
<param name="commentId"></param>
<returns></returns>
</member>
<member name="M:RMuseum.Services.Implementation.GanjoorService.GetPageByUrl(System.String,System.Boolean)">
<summary>
get page by url
@ -7961,7 +8001,12 @@
Image File Service
</summary>
</member>
<member name="M:RMuseum.Services.Implementation.GanjoorService.#ctor(RMuseum.DbContext.RMuseumDbContext,Microsoft.Extensions.Configuration.IConfiguration,RSecurityBackend.Services.IBackgroundTaskQueue,RSecurityBackend.Services.IAppUserService,RSecurityBackend.Services.IRNotificationService,RSecurityBackend.Services.IImageFileService)">
<member name="F:RMuseum.Services.Implementation.GanjoorService._memoryCache">
<summary>
IMemoryCache
</summary>
</member>
<member name="M:RMuseum.Services.Implementation.GanjoorService.#ctor(RMuseum.DbContext.RMuseumDbContext,Microsoft.Extensions.Configuration.IConfiguration,RSecurityBackend.Services.IBackgroundTaskQueue,RSecurityBackend.Services.IAppUserService,RSecurityBackend.Services.IRNotificationService,RSecurityBackend.Services.IImageFileService,Microsoft.Extensions.Caching.Memory.IMemoryCache)">
<summary>
constructor
</summary>
@ -7971,6 +8016,7 @@
<param name="appUserService"></param>
<param name="notificationService"></param>
<param name="imageFileService"></param>
<param name="memoryCache"></param>
</member>
<member name="T:RMuseum.Services.Implementation.ImportedFromDesktopGanjoor.GPersianTextSync">
<summary>

View File

@ -322,6 +322,26 @@ namespace RMuseum.Services
/// <returns></returns>
RServiceResult<bool> HealthCheckContents();
/// <summary>
/// clean cache for paeg by id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task CacheCleanForPageById(int id);
/// <summary>
/// clean cache for page by url
/// </summary>
/// <param name="url"></param>
void CacheCleanForPageByUrl(string url);
/// <summary>
/// clean cache for page by comment
/// </summary>
/// <param name="commentId"></param>
/// <returns></returns>
Task CacheCleanForComment(int commentId);
/// <summary>
/// Get Verses By query
/// </summary>

View File

@ -19,6 +19,7 @@ using RSecurityBackend.Services.Implementation;
using DNTPersianUtils.Core;
using System.IO;
using RSecurityBackend.Models.Image;
using Microsoft.Extensions.Caching.Memory;
namespace RMuseum.Services.Implementation
{
@ -325,6 +326,47 @@ namespace RMuseum.Services.Implementation
}
}
/// <summary>
/// clean cache for paeg by id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task CacheCleanForPageById(int id)
{
var dbPage = await _context.GanjoorPages.Where(p => p.Id == id).AsNoTracking().SingleOrDefaultAsync();
if (dbPage != null)
{
CacheCleanForPageByUrl(dbPage.FullUrl);
}
}
/// <summary>
/// clean cache for page by url
/// </summary>
/// <param name="url"></param>
public void CacheCleanForPageByUrl(string url)
{
var cachKey = $"GanjoorService::GetPageByUrl::{url}";
if (!_memoryCache.TryGetValue(cachKey, out GanjoorPageCompleteViewModel page))
{
_memoryCache.Remove(cachKey);
}
}
/// <summary>
/// clean cache for page by comment
/// </summary>
/// <param name="commentId"></param>
/// <returns></returns>
public async Task CacheCleanForComment(int commentId)
{
var comment = await _context.GanjoorComments.Where(c => c.Id == commentId).SingleOrDefaultAsync();
if(comment != null)
{
await CacheCleanForPageById(comment.PoemId);
}
}
/// <summary>
/// get page by url
/// </summary>
@ -346,109 +388,117 @@ namespace RMuseum.Services.Implementation
url = url.Substring(0, url.Length - 1);
}
var dbPage = await _context.GanjoorPages.Where(p => p.FullUrl == url).AsNoTracking().SingleOrDefaultAsync();
if (dbPage == null)
return new RServiceResult<GanjoorPageCompleteViewModel>(null); //not found
var secondPoet = dbPage.SecondPoetId == null ? null :
await
(from poet in _context.GanjoorPoets
join cat in _context.GanjoorCategories.Where(c => c.ParentId == null)
on poet.Id equals cat.PoetId
where poet.Id == (int)dbPage.SecondPoetId
orderby poet.Name descending
select new GanjoorPoetViewModel()
{
Id = poet.Id,
Name = poet.Name,
FullUrl = cat.FullUrl,
RootCatId = cat.Id,
Nickname = poet.Nickname,
Published = poet.Published,
ImageUrl = poet.RImageId == null ? "" : $"/api/ganjoor/poet/image{cat.FullUrl}.png"
}
)
.AsNoTracking().SingleAsync();
GanjoorPageCompleteViewModel page = new GanjoorPageCompleteViewModel()
url = url.Replace("//", "/"); //duplicated slashes would be merged
var cachKey = $"GanjoorService::GetPageByUrl::{url}";
if (!_memoryCache.TryGetValue(cachKey, out GanjoorPageCompleteViewModel page))
{
Id = dbPage.Id,
GanjoorPageType = dbPage.GanjoorPageType,
Title = dbPage.Title,
FullTitle = dbPage.FullTitle,
UrlSlug = dbPage.UrlSlug,
FullUrl = dbPage.FullUrl,
HtmlText = dbPage.HtmlText,
SecondPoet = secondPoet
var dbPage = await _context.GanjoorPages.Where(p => p.FullUrl == url).AsNoTracking().SingleOrDefaultAsync();
if (dbPage == null)
return new RServiceResult<GanjoorPageCompleteViewModel>(null); //not found
var secondPoet = dbPage.SecondPoetId == null ? null :
await
(from poet in _context.GanjoorPoets
join cat in _context.GanjoorCategories.Where(c => c.ParentId == null)
on poet.Id equals cat.PoetId
where poet.Id == (int)dbPage.SecondPoetId
orderby poet.Name descending
select new GanjoorPoetViewModel()
{
Id = poet.Id,
Name = poet.Name,
FullUrl = cat.FullUrl,
RootCatId = cat.Id,
Nickname = poet.Nickname,
Published = poet.Published,
ImageUrl = poet.RImageId == null ? "" : $"/api/ganjoor/poet/image{cat.FullUrl}.png"
}
)
.AsNoTracking().SingleAsync();
page = new GanjoorPageCompleteViewModel()
{
Id = dbPage.Id,
GanjoorPageType = dbPage.GanjoorPageType,
Title = dbPage.Title,
FullTitle = dbPage.FullTitle,
UrlSlug = dbPage.UrlSlug,
FullUrl = dbPage.FullUrl,
HtmlText = dbPage.HtmlText,
SecondPoet = secondPoet
};
switch (page.GanjoorPageType)
{
case GanjoorPageType.PoemPage:
{
var poemRes = await GetPoemById((int)dbPage.PoemId);
if (!string.IsNullOrEmpty(poemRes.ExceptionString))
};
switch (page.GanjoorPageType)
{
case GanjoorPageType.PoemPage:
{
return new RServiceResult<GanjoorPageCompleteViewModel>(null, poemRes.ExceptionString);
}
page.Poem = poemRes.Result;
}
break;
case GanjoorPageType.CatPage:
{
var catRes = await GetCatById((int)dbPage.CatId);
if (!string.IsNullOrEmpty(catRes.ExceptionString))
{
return new RServiceResult<GanjoorPageCompleteViewModel>(null, catRes.ExceptionString);
}
page.PoetOrCat = catRes.Result;
}
break;
default:
{
if (dbPage.PoetId != null)
{
var poetRes = await GetPoetById((int)dbPage.PoetId);
if (!string.IsNullOrEmpty(poetRes.ExceptionString))
var poemRes = await GetPoemById((int)dbPage.PoemId);
if (!string.IsNullOrEmpty(poemRes.ExceptionString))
{
return new RServiceResult<GanjoorPageCompleteViewModel>(null, poetRes.ExceptionString);
return new RServiceResult<GanjoorPageCompleteViewModel>(null, poemRes.ExceptionString);
}
page.PoetOrCat = poetRes.Result;
page.Poem = poemRes.Result;
}
break;
var pre = await _context.GanjoorPages.Where(p => p.GanjoorPageType == page.GanjoorPageType && p.ParentId == dbPage.ParentId && p.PoetId == dbPage.PoetId &&
((p.PageOrder < dbPage.PageOrder) || (p.PageOrder == dbPage.PageOrder && p.Id < dbPage.Id)))
.OrderByDescending(p => p.PageOrder)
.ThenByDescending(p => p.Id)
.AsNoTracking()
.FirstOrDefaultAsync();
if(pre != null)
case GanjoorPageType.CatPage:
{
var catRes = await GetCatById((int)dbPage.CatId);
if (!string.IsNullOrEmpty(catRes.ExceptionString))
{
page.Previous = new GanjoorPageSummaryViewModel()
return new RServiceResult<GanjoorPageCompleteViewModel>(null, catRes.ExceptionString);
}
page.PoetOrCat = catRes.Result;
}
break;
default:
{
if (dbPage.PoetId != null)
{
var poetRes = await GetPoetById((int)dbPage.PoetId);
if (!string.IsNullOrEmpty(poetRes.ExceptionString))
{
Id = pre.Id,
Title = pre.Title,
FullUrl = pre.FullUrl
};
}
return new RServiceResult<GanjoorPageCompleteViewModel>(null, poetRes.ExceptionString);
}
page.PoetOrCat = poetRes.Result;
var next = await _context.GanjoorPages.Where(p => p.GanjoorPageType == page.GanjoorPageType && p.ParentId == dbPage.ParentId && p.PoetId == dbPage.PoetId &&
((p.PageOrder > dbPage.PageOrder) || (p.PageOrder == dbPage.PageOrder && p.Id > dbPage.Id)))
.OrderBy(p => p.PageOrder)
.ThenBy(p => p.Id)
.AsNoTracking()
.FirstOrDefaultAsync();
if (next != null)
{
page.Next = new GanjoorPageSummaryViewModel()
var pre = await _context.GanjoorPages.Where(p => p.GanjoorPageType == page.GanjoorPageType && p.ParentId == dbPage.ParentId && p.PoetId == dbPage.PoetId &&
((p.PageOrder < dbPage.PageOrder) || (p.PageOrder == dbPage.PageOrder && p.Id < dbPage.Id)))
.OrderByDescending(p => p.PageOrder)
.ThenByDescending(p => p.Id)
.AsNoTracking()
.FirstOrDefaultAsync();
if (pre != null)
{
Id = next.Id,
Title = next.Title,
FullUrl = next.FullUrl
};
page.Previous = new GanjoorPageSummaryViewModel()
{
Id = pre.Id,
Title = pre.Title,
FullUrl = pre.FullUrl
};
}
var next = await _context.GanjoorPages.Where(p => p.GanjoorPageType == page.GanjoorPageType && p.ParentId == dbPage.ParentId && p.PoetId == dbPage.PoetId &&
((p.PageOrder > dbPage.PageOrder) || (p.PageOrder == dbPage.PageOrder && p.Id > dbPage.Id)))
.OrderBy(p => p.PageOrder)
.ThenBy(p => p.Id)
.AsNoTracking()
.FirstOrDefaultAsync();
if (next != null)
{
page.Next = new GanjoorPageSummaryViewModel()
{
Id = next.Id,
Title = next.Title,
FullUrl = next.FullUrl
};
}
}
}
}
break;
break;
}
_memoryCache.Set(cachKey, page);
}
return new RServiceResult<GanjoorPageCompleteViewModel>(page);
}
@ -627,6 +677,7 @@ namespace RMuseum.Services.Implementation
}
}
await CacheCleanForPageById(poemId);
return new RServiceResult<GanjoorCommentSummaryViewModel>
@ -668,6 +719,8 @@ namespace RMuseum.Services.Implementation
return new RServiceResult<bool>(false); //not found
}
await CacheCleanForComment(commentId);
htmlComment = htmlComment.ApplyCorrectYeKe();
comment.HtmlComment = htmlComment;
@ -699,6 +752,8 @@ namespace RMuseum.Services.Implementation
return new RServiceResult<bool>(false); //not found
}
await CacheCleanForComment(commentId);
if (comment.UserId != null)
{
reason = string.IsNullOrEmpty(reason) ? "" : $"علت ارائه شده برای حذف یا متن گزارش کاربر شاکی: {Environment.NewLine}" +
@ -756,6 +811,8 @@ namespace RMuseum.Services.Implementation
return new RServiceResult<bool>(false); //not found
}
await CacheCleanForComment(commentId);
//if user has got replies, delete them and notify their owners of what happened
var replies = await _FindReplies(comment);
for (int i = replies.Count - 1; i >= 0; i--)
@ -2021,6 +2078,9 @@ namespace RMuseum.Services.Implementation
await _context.SaveChangesAsync();
CacheCleanForPageByUrl(dbPage.FullUrl);
return await GetPageByUrl(dbPage.FullUrl);
}
catch(Exception exp)
@ -2348,6 +2408,11 @@ namespace RMuseum.Services.Implementation
/// </summary>
protected readonly IImageFileService _imageFileService;
/// <summary>
/// IMemoryCache
/// </summary>
protected readonly IMemoryCache _memoryCache;
/// <summary>
@ -2359,13 +2424,15 @@ namespace RMuseum.Services.Implementation
/// <param name="appUserService"></param>
/// <param name="notificationService"></param>
/// <param name="imageFileService"></param>
public GanjoorService(RMuseumDbContext context, IConfiguration configuration, IBackgroundTaskQueue backgroundTaskQueue, IAppUserService appUserService, IRNotificationService notificationService, IImageFileService imageFileService)
/// <param name="memoryCache"></param>
public GanjoorService(RMuseumDbContext context, IConfiguration configuration, IBackgroundTaskQueue backgroundTaskQueue, IAppUserService appUserService, IRNotificationService notificationService, IImageFileService imageFileService, IMemoryCache memoryCache)
{
_context = context;
_backgroundTaskQueue = backgroundTaskQueue;
_appUserService = appUserService;
_notificationService = notificationService;
_imageFileService = imageFileService;
_memoryCache = memoryCache;
Configuration = configuration;
}
}