people tags #387

This commit is contained in:
Hamid Reza Mohammadi 2026-10-03 19:38:56 +03:30
parent a1fad2259d
commit 6ecfd8c38a
3 changed files with 56 additions and 2 deletions

View File

@ -635,8 +635,22 @@ namespace GanjooRazor.Areas.Admin.Pages
}
else
{
try
{
// normal case: the API returns the error as a JSON-encoded string (see
// OnPostDeletePoemCorrectionsAsync in Editor.cshtml.cs for the same
// pattern). Guard against it not being one - e.g. an HTML error page
// from a proxy/host in front of the API - so that doesn't throw an
// unhandled exception here and surface as GanjooRazor's own generic HTML
// error page, which is unreadable and leaves the real error only in the
// Windows Event Log.
err = JsonConvert.DeserializeObject<string>(err);
}
catch (JsonException)
{
err = "خطایی در سرور رخ داد. لطفاً بعداً دوباره تلاش کنید.";
}
}
return new BadRequestObjectResult(err);
}

View File

@ -2075,6 +2075,17 @@ namespace RMuseum.Services.Implementation
/// <param name="correction"></param>
/// <returns></returns>
public async Task<RServiceResult<GanjoorPoemCorrectionViewModel>> SuggestPoemCorrection(GanjoorPoemCorrectionViewModel correction)
{
// wrapped in try/catch (matching ModeratePoemCorrection's own pattern) so an unexpected
// exception - e.g. the EF Core "same key value is already being tracked" conflict this
// method used to throw on a second save - comes back as a normal RServiceResult.ExceptionString
// instead of an unhandled exception. Left uncaught, it would bypass GanjoorController's own
// "if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(...)" check entirely
// (that line is never reached because this method never returns), fall through to the
// framework's generic HTML error page, and show up to the user as unreadable HTML source
// instead of a readable message - with the real exception visible only in the Windows Event
// Log.
try
{
if (!string.IsNullOrEmpty(correction.Rhythm3) || !string.IsNullOrEmpty(correction.Rhythm4))
return new RServiceResult<GanjoorPoemCorrectionViewModel>(null, "انتساب وزن سوم و چهارم هنوز پیاده‌سازی نشده است.");
@ -2264,6 +2275,11 @@ namespace RMuseum.Services.Implementation
return new RServiceResult<GanjoorPoemCorrectionViewModel>(correction);
}
catch (Exception exp)
{
return new RServiceResult<GanjoorPoemCorrectionViewModel>(null, exp.ToString());
}
}
/// <summary>
/// last unreviewed user correction for a poem

View File

@ -3,6 +3,7 @@ using Betalgo.Ranul.OpenAI.Extensions;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
@ -16,6 +17,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi;
using Newtonsoft.Json;
using RMuseum.DbContext;
using RMuseum.Models.Auth.Memory;
using RMuseum.Services;
@ -358,7 +360,29 @@ namespace RMuseum
}
else
{
app.UseExceptionHandler("/Error");
// RMuseum is API-only (see UseEndpoints below - MapControllers only), so there is no
// Razor "/Error" page or MVC "Error" action for the old app.UseExceptionHandler("/Error")
// to redirect to - that redirect just 404s, and (especially when hosted behind IIS/ANCM,
// as in production here) a 404 with no body of its own can get replaced by IIS's own
// generic HTML error page instead. Either way, callers - including GanjooRazor's own
// server-side page handlers, which otherwise assume every error body is a JSON-encoded
// string - got back unreadable HTML instead of the real exception, visible only by
// digging through the Windows Event Log. Handling the exception directly here instead
// of redirecting anywhere guarantees a small JSON-string body with the real exception
// message, in the exact same shape a normal RServiceResult.ExceptionString error already
// comes back as (see e.g. GanjoorController's "return BadRequest(res.ExceptionString)"),
// so every existing client-side error handler keeps working unchanged.
app.UseExceptionHandler(errApp =>
{
errApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = "application/json; charset=utf-8";
var exceptionFeature = context.Features.Get<IExceptionHandlerPathFeature>();
var message = exceptionFeature?.Error?.ToString() ?? "خطای غیرمنتظره‌ای در سرور رخ داد.";
await context.Response.WriteAsync(JsonConvert.SerializeObject(message));
});
});
}