switching back to httpclient instead of direct db access in GanjooRazor

This commit is contained in:
Hamid Reza Mohammadi 2021-05-17 12:39:39 +04:30
parent 9de66e2013
commit cf3b10549c
6 changed files with 80 additions and 247 deletions

View File

@ -4,8 +4,10 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RMuseum.Models.Auth.Memory;
using RMuseum.Models.Ganjoor;
using RMuseum.Models.Ganjoor.ViewModels;
@ -32,37 +34,27 @@ namespace GanjooRazor.Pages
/// </summary>
private readonly IConfiguration _configuration;
/// <summary>
/// IAppUserService instance
/// </summary>
private readonly IAppUserService _appUserService;
/// <summary>
/// ganjoor service
/// </summary>
private readonly IGanjoorService _ganjoorService;
/// <summary>
/// HttpClient instance
/// </summary>
private readonly HttpClient _httpClient;
private readonly IMemoryCache _memoryCache;
/// <summary>
/// constructor
/// </summary>
/// <param name="configuration"></param>
/// <param name="appUserService"></param>
/// <param name="ganjoorService"></param>
/// <param name="httpClient"></param>
/// <param name="memoryCache"></param>
public IndexModel(IConfiguration configuration,
IAppUserService appUserService,
IGanjoorService ganjoorService,
HttpClient httpClient)
HttpClient httpClient,
IMemoryCache memoryCache
)
{
_configuration = configuration;
_appUserService = appUserService;
_ganjoorService = ganjoorService;
_httpClient = httpClient;
_memoryCache = memoryCache;
}
[BindProperty]
@ -212,7 +204,6 @@ 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)
{
@ -280,7 +271,6 @@ 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)
@ -305,7 +295,6 @@ 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)
{
@ -468,7 +457,16 @@ namespace GanjooRazor.Pages
private async Task preparePoets()
{
Poets = new List<GanjoorPoetViewModel>((await _ganjoorService.GetPoets(true, false)).Result);
var cacheKey = $"/api/ganjoor/poets?includeBio=false";
if (!_memoryCache.TryGetValue(cacheKey, out List<GanjoorPoetViewModel> poets))
{
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poets?includeBio=false");
response.EnsureSuccessStatusCode();
poets = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoetViewModel>>();
_memoryCache.Set(cacheKey, poets);
}
Poets = poets;
}
/// <summary>
@ -491,23 +489,26 @@ namespace GanjooRazor.Pages
if (!string.IsNullOrEmpty(Request.Query["p"]))
{
var pageUrlRes = await _ganjoorService.GetPageUrlById(int.Parse(Request.Query["p"]));
return Redirect(pageUrlRes.Result);
var pageUrlResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/pageurl?id={Request.Query["p"]}");
pageUrlResponse.EnsureSuccessStatusCode();
var pageUrl = JsonConvert.DeserializeObject<string>(await pageUrlResponse.Content.ReadAsStringAsync());
return Redirect(pageUrl);
}
await preparePoets();
if (!IsHomePage)
{
var pageRes = await _ganjoorService.GetPageByUrl(Request.Path, true);
if(string.IsNullOrEmpty(pageRes.ExceptionString))
var pageQuery = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/page?url={Request.Path}");
if (!pageQuery.IsSuccessStatusCode)
{
if(pageRes.Result == null)
if (pageQuery.StatusCode == HttpStatusCode.NotFound)
{
return NotFound();
}
}
GanjoorPage = pageRes.Result;
pageQuery.EnsureSuccessStatusCode();
GanjoorPage = JObject.Parse(await pageQuery.Content.ReadAsStringAsync()).ToObject<GanjoorPageCompleteViewModel>();
GanjoorPage.HtmlText = GanjoorPage.HtmlText.Replace("https://ganjoor.net/", "/").Replace("http://ganjoor.net/", "/");
switch (GanjoorPage.GanjoorPageType)
{
@ -528,7 +529,13 @@ namespace GanjooRazor.Pages
if (IsPoemPage)
{
Banner = (await _ganjoorService.GetARandomActiveSiteBanner()).Result;
var bannerQuery = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/site/banner");
bannerQuery.EnsureSuccessStatusCode();
string bannerResponse = await bannerQuery.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(bannerResponse))
{
Banner = JObject.Parse(bannerResponse).ToObject<GanjoorSiteBannerViewModel>();
}
}
}

View File

@ -1,10 +1,13 @@
using DNTPersianUtils.Core;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RMuseum.Models.Auth.ViewModel;
using RMuseum.Models.Ganjoor.ViewModels;
using RSecurityBackend.Models.Auth.ViewModels;
using RSecurityBackend.Models.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace GanjooRazor.Pages
@ -25,20 +28,15 @@ namespace GanjooRazor.Pages
string filterUserId = Request.Query["userid"];
string url = $"{APIRoot.Url}/api/ganjoor/comments?PageNumber={pageNumber}&PageSize=20";
string htmlText = "";
if (!string.IsNullOrEmpty(filterUserId))
{
RServiceResult<PublicRAppUser> userInfo = await _appUserService.GetUserInformation(Guid.Parse(filterUserId));
var responseUserProfile = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/user/profile/{filterUserId}");
responseUserProfile.EnsureSuccessStatusCode();
GanjoorUserPublicProfile profile = JsonConvert.DeserializeObject<GanjoorUserPublicProfile>(await responseUserProfile.Content.ReadAsStringAsync());
GanjoorUserPublicProfile profile = new GanjoorUserPublicProfile()
{
Id = (Guid)userInfo.Result.Id,
NickName = userInfo.Result.NickName,
Bio = userInfo.Result.Bio,
Website = userInfo.Result.Website,
RImageId = userInfo.Result.RImageId
};
ViewData["Title"] = $"گنجور &raquo; حاشیه‌های {profile.NickName}";
@ -63,19 +61,18 @@ namespace GanjooRazor.Pages
htmlText += $"</div>{Environment.NewLine}";
htmlText += $"<hr />{Environment.NewLine}";
url += $"&filterUserId={filterUserId}";
}
var commentsRes = await _ganjoorService.GetRecentComments(new PagingParameterModel()
{
PageNumber = pageNumber,
PageSize = 20
},
string.IsNullOrEmpty(filterUserId) ? Guid.Empty : Guid.Parse(filterUserId), true);
var response = await _httpClient.GetAsync(url);
PaginationMetadata paginationMetadata = commentsRes.Result.PagingMeta;
GanjoorCommentFullViewModel[] comments = commentsRes.Result.Items;
response.EnsureSuccessStatusCode();
string paginnationMetadata = response.Headers.GetValues("paging-headers").FirstOrDefault();
PaginationMetadata paginationMetadata = JsonConvert.DeserializeObject<PaginationMetadata>(paginnationMetadata);
var comments = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorCommentFullViewModel>>();
foreach (var comment in comments)

View File

@ -7,7 +7,6 @@ using RSecurityBackend.Models.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace GanjooRazor.Pages
@ -35,20 +34,12 @@ namespace GanjooRazor.Pages
string metre = Request.Query["v"];
string rhyme = Request.Query["g"];
var poemsRes =
(
await _ganjoorService.GetSimilarPoems
(
new PagingParameterModel()
{
PageNumber = pageNumber,
PageSize = 20
},
metre,
rhyme,
null
)
).Result;
string url = $"{APIRoot.Url}/api/ganjoor/poems/similar?PageNumber={pageNumber}&PageSize=20&metre={metre}&rhyme={rhyme}";
var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var poems = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoemCompleteViewModel>>();
GanjoorPage.Title = "شعرهای ";
@ -65,10 +56,7 @@ namespace GanjooRazor.Pages
foreach (var poem in poemsRes.Items)
foreach (var poem in poems)
{
htmlText += $"<div class=\"sitem\" id=\"post-{poem.Id}\">{Environment.NewLine}<h2><a href=\"{poem.FullUrl}\" rel=\"bookmark\">{poem.FullTitle}</a>{Environment.NewLine}</h2>{Environment.NewLine}" +
$"<div class=\"spacer\">&nbsp;</div>{Environment.NewLine}"
@ -85,8 +73,10 @@ namespace GanjooRazor.Pages
htmlText += "<p style=\"text-align: center;\">";
PaginationMetadata paginationMetadata = poemsRes.PagingMeta;
string paginnationMetadata = response.Headers.GetValues("paging-headers").FirstOrDefault();
PaginationMetadata paginationMetadata = JsonConvert.DeserializeObject<PaginationMetadata>(paginnationMetadata);
if (paginationMetadata.totalPages > 1)
{
GanjoorPage.Title += $" - صفحهٔ {pageNumber.ToPersianNumbers()}";

View File

@ -29,22 +29,16 @@ namespace GanjooRazor.Pages
}
string metre = Request.Query["v"];
int? poetId = string.IsNullOrEmpty(Request.Query["a"]) ? null : int.Parse(Request.Query["a"]);
int poetId = string.IsNullOrEmpty(Request.Query["a"]) ? 0 : int.Parse(Request.Query["a"]);
var poemsRes = await _ganjoorService.GetSimilarPoems
(
new PagingParameterModel()
{
PageNumber = pageNumber,
PageSize = 20
},
metre: metre,
rhyme: "",
poetId: poetId
);
string url = $"{APIRoot.Url}/api/ganjoor/poems/similar?PageNumber={pageNumber}&PageSize=20&metre={metre}&poetId={poetId}";
var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
GanjoorPage.Title = "شعرهای ";
if (poetId != null)
if (poetId != 0)
{
GanjoorPage.Title += $"{Poets.Where(p => p.Id == poetId).Single().Name} ";
}
@ -56,7 +50,7 @@ namespace GanjooRazor.Pages
string htmlText = "";
if (poetId != null)
if (poetId != 0)
{
htmlText += $"<div class=\"sitem\" id=\"all\">{Environment.NewLine}";
htmlText += $"<h2>{Environment.NewLine}";
@ -65,9 +59,9 @@ namespace GanjooRazor.Pages
htmlText += $"</div>{Environment.NewLine}";
}
var poems = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoemCompleteViewModel>>();
foreach (var poem in poemsRes.Result.Items)
foreach (var poem in poems)
{
htmlText += $"<div class=\"sitem\" id=\"post-{poem.Id}\">{Environment.NewLine}<h2><a href=\"{poem.FullUrl}\" rel=\"bookmark\">{poem.FullTitle}</a>{Environment.NewLine}</h2>{Environment.NewLine}" +
$"<div class=\"spacer\">&nbsp;</div>{Environment.NewLine}"
@ -84,7 +78,9 @@ namespace GanjooRazor.Pages
htmlText += "<p style=\"text-align: center;\">";
PaginationMetadata paginationMetadata = poemsRes.Result.PagingMeta;
string paginnationMetadata = response.Headers.GetValues("paging-headers").FirstOrDefault();
PaginationMetadata paginationMetadata = JsonConvert.DeserializeObject<PaginationMetadata>(paginnationMetadata);
string queryPoetId = poetId == 0 ? "" : $"&a={poetId}";

View File

@ -42,9 +42,10 @@ namespace GanjooRazor
{
services.AddHttpClient();
services.AddMemoryCache();
services.AddSingleton(
HtmlEncoder.Create(allowedRanges: new[] { UnicodeRanges.BasicLatin,
HtmlEncoder.Create(allowedRanges: new[] { UnicodeRanges.BasicLatin,
UnicodeRanges.Arabic }));
services.AddRazorPages(options =>
@ -52,162 +53,6 @@ namespace GanjooRazor
options.Conventions.AddPageRoute("/index", "{*url}");
});
services.AddDbContextPool<RMuseumDbContext>(
options => options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"),
providerOptions => providerOptions.EnableRetryOnFailure()
)
);
Audit.Core.Configuration.JsonSettings.ContractResolver = AuditNetEnvironmentSkippingContractResolver.Instance;
Audit.Core.Configuration.DataProvider = new RAuditDataProvider(Configuration.GetConnectionString("DefaultConnection"));
services.AddIdentityCore<RAppUser>(
options =>
{
// Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
options.User.RequireUniqueEmail = false;
}
).AddErrorDescriber<PersianIdentityErrorDescriber>();
new IdentityBuilder(typeof(RAppUser), typeof(RAppRole), services)
.AddRoleManager<RoleManager<RAppRole>>()
.AddSignInManager<SignInManager<RAppUser>>()
.AddEntityFrameworkStores<RMuseumDbContext>()
.AddErrorDescriber<PersianIdentityErrorDescriber>();
services.AddAuthentication(options =>
{
options.DefaultScheme = "bearer";
}).AddJwtBearer("bearer", options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidAudience = "Everyone",
ValidateIssuer = true,
ValidIssuer = "Ganjoor",
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes($"{Configuration.GetSection("Security")["Secret"]}")),
ValidateLifetime = true, //validate the expiration and not before values in the token
ClockSkew = TimeSpan.Zero
};
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
});
services.AddAuthorization(options =>
{
//this is the default policy to make sure the use session has not yet been deleted by him/her from another client
//or by an admin (Authorize with no policy should fail on deleted sessions)
var defPolicy = new AuthorizationPolicyBuilder();
defPolicy.Requirements.Add(new UserGroupPermissionRequirement("null", "null"));
options.DefaultPolicy = defPolicy.Build();
foreach (SecurableItem Item in RMuseumSecurableItem.Items)
{
foreach (SecurableItemOperation Operation in Item.Operations)
{
options.AddPolicy($"{Item.ShortName}:{Operation.ShortName}", policy => policy.Requirements.Add(new UserGroupPermissionRequirement(Item.ShortName, Operation.ShortName)));
}
}
});
services.AddMemoryCache();
//security context maps to main db context
services.AddTransient<RSecurityDbContext<RAppUser, RAppRole, Guid>, RMuseumDbContext>();
//captcha service
services.AddTransient<ICaptchaService, CaptchaServiceEF>();
//generic image file service
services.AddTransient<IImageFileService, ImageFileServiceEF>();
//app user services
services.AddTransient<IAppUserService, GanjoorAppUserService>();
//user groups services
services.AddTransient<IUserRoleService, RoleService>();
//audit service
services.AddTransient<IAuditLogService, AuditLogServiceEF>();
//user permission checker
services.AddTransient<IUserPermissionChecker, UserPermissionChecker>();
//secret generator
services.AddTransient<ISecretGenerator, SecretGenerator>();
// email service
services.AddTransient<IEmailSender, MailKitEmailSender>();
services.Configure<SmptConfig>(Configuration);
//picture file service
services.AddTransient<IPictureFileService, PictureFileService>();
//messaging service
services.AddTransient<IRNotificationService, RNotificationService>();
//artifact service
services.AddTransient<IArtifactService, ArtifactService>();
//audio service
services.AddTransient<IRecitationService, RecitationService>();
//ganjoor service
services.AddTransient<IGanjoorService, GanjoorService>();
//music catalogue service
services.AddTransient<IMusicCatalogueService, MusicCatalogueService>();
//long running job service
services.AddTransient<ILongRunningJobProgressService, LongRunningJobProgressServiceEF>();
//upload limit for IIS
services.Configure<IISServerOptions>(options =>
{
options.MaxRequestBodySize = int.Parse(Configuration.GetSection("IIS")["UploadLimit"]);
});
services.AddHostedService<QueuedHostedService>();
services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
}
@ -222,8 +67,6 @@ namespace GanjooRazor
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>

View File

@ -8,8 +8,8 @@
},
"AllowedHosts": "*",
"GoogleAnalyticsCode": "",
"APIRoot": "http://localhost:3439",
"GlobalAPIRoot": "http://localhost:3439",
"APIRoot": "https://ganjgah.ir",
"GlobalAPIRoot": "https://ganjgah.ir",
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=museum;Trusted_Connection=True;MultipleActiveResultSets=true"
},