using System.Diagnostics;
using System.Net;
using Microsoft.AspNetCore.Diagnostics;
using MessagesResources = Roblox.TranslationResources.CommonUI.Messages;
namespace Roblox.Website.Pages
{
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
private readonly ILogger _logger;
public IStringLocalizer Resources { get; }
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ErrorTitle { get; set; }
public string? ErrorDescription { get; set; }
public string? ErrorMessage { get; set; }
public int ResponseCode { get; set; }
public ErrorModel(ILogger logger, IStringLocalizer resources)
{
_logger = logger;
Resources = resources;
// If shit really hits the fan and we can't translate, we can always fallback to this
ResponseCode = 500;
ErrorTitle = "Unexpected error with your request";
ErrorDescription = "Please try again after a few moments.";
}
private void SetErrorInfo(HttpStatusCode? statusCode, Exception? exception = null)
{
switch (statusCode)
{
case HttpStatusCode.BadRequest:
ResponseCode = 400;
ErrorTitle = Resources["Response.BadRequest"];
ErrorDescription = Resources["Response.BadRequestDescription"];
break;
case HttpStatusCode.Forbidden:
ResponseCode = 403;
ErrorTitle = Resources["Response.AccessDenied"];
ErrorDescription = Resources["Response.AccessDeniedDescription"];
break;
case HttpStatusCode.NotFound:
ResponseCode = 404;
ErrorTitle = Resources["Response.PageNotFound"];
ErrorDescription = Resources["Response.PageNotFoundDescription"];
break;
case HttpStatusCode.InternalServerError:
ResponseCode = 500;
ErrorTitle = Resources["Response.InternalServerError"];
ErrorDescription = Resources["Response.InternalServerErrorDescription"];
break;
default: // Covers any other error codes the user might throw at us
ResponseCode = 500;
ErrorTitle = Resources["Response.SomethingWentWrong"];
ErrorDescription = Resources["Response.UnexpectedError"];
break;
}
if (exception != null)
ErrorMessage = exception.ToString();
}
private IActionResult OnRequest()
{
try
{
// HACK: Clear HttpContext items to prevent script and CSS files from bleeding over from errored page
HttpContext.Items.Clear();
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var codeStr = Request.Query["code"].FirstOrDefault();
HttpStatusCode? statusCode = null;
if (Enum.TryParse(codeStr, out var codeOut))
statusCode = codeOut;
Exception? exception = null;
var feature =
HttpContext.Features.Get();
if (feature != null && feature.Error != null)
{
exception = feature.Error;
// All exceptions give 500s by default
statusCode = HttpStatusCode.InternalServerError;
}
SetErrorInfo(statusCode, exception);
HttpContext.Response.StatusCode = ResponseCode;
}
catch { }
try
{
return Page();
}
catch { }
// If everything's imploded, fallback to plaintext
return Content("The site is currently offline for maintenance and upgrades.\r\nPlease check back soon!");
}
public IActionResult OnGet() => OnRequest();
public IActionResult OnPost() => OnRequest();
}
}