Merge pull request #2097 from abpframework/Abp-Error-status-Page-option

Abp error status page option
pull/2165/head
Yunus Emre Kalkan 5 years ago committed by GitHub
commit 3c444ebd59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared
{
public class AbpErrorPageOptions
{
public readonly IDictionary<string, string> ErrorViewUrls;
public AbpErrorPageOptions()
{
ErrorViewUrls = new Dictionary<string, string>();
}
}
}

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using Localization.Resources.AbpUi;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Views.Error;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Controllers
{
public class ErrorController : AbpController
{
private readonly IExceptionToErrorInfoConverter _errorInfoConverter;
private readonly IHttpExceptionStatusCodeFinder _statusCodeFinder;
private readonly IStringLocalizer<AbpUiResource> _localizer;
private readonly AbpErrorPageOptions _abpErrorPageOptions;
public ErrorController(
IExceptionToErrorInfoConverter exceptionToErrorInfoConverter,
IHttpExceptionStatusCodeFinder httpExceptionStatusCodeFinder,
IOptions<AbpErrorPageOptions> abpErrorPageOptions,
IStringLocalizer<AbpUiResource> localizer)
{
_errorInfoConverter = exceptionToErrorInfoConverter;
_statusCodeFinder = httpExceptionStatusCodeFinder;
_localizer = localizer;
_abpErrorPageOptions = abpErrorPageOptions.Value;
}
public IActionResult Index(int httpStatusCode)
{
var exHandlerFeature = HttpContext.Features.Get<IExceptionHandlerFeature>();
var exception = exHandlerFeature != null
? exHandlerFeature.Error
: new Exception(_localizer["UnhandledException"]);
var errorInfo = _errorInfoConverter.Convert(exception);
if (httpStatusCode == 0)
{
httpStatusCode = (int)_statusCodeFinder.GetStatusCode(HttpContext, exception);
}
HttpContext.Response.StatusCode = httpStatusCode;
var page = GetErrorPageUrl(httpStatusCode);
return View(page, new AbpErrorPageModel
{
ErrorInfo = errorInfo,
HttpStatusCode = httpStatusCode
});
}
private string GetErrorPageUrl(int statusCode)
{
var page = _abpErrorPageOptions.ErrorViewUrls.GetOrDefault(statusCode.ToString());
if (string.IsNullOrWhiteSpace(page))
{
return "~/Pages/Error/Default.cshtml";
}
return page;
}
}
}

@ -1,41 +0,0 @@
@page
@using System.Linq
@using System.Collections.Generic
@using Localization.Resources.AbpUi
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Error
@model IndexModel
@inject IHtmlLocalizer<AbpUiResource> L
@{
var errorMessage = Model.ErrorInfo.Message;
var errorDetails = Model.ErrorInfo.Details;
if (errorDetails.IsNullOrEmpty())
{
errorDetails = errorMessage;
errorMessage = L["Error"].Value + "!";
}
}
<h1>
[@Model.HttpStatusCode] @errorMessage
</h1>
<div>
<p>
@errorDetails
</p>
<p>
@if (!Model.ErrorInfo.ValidationErrors.IsNullOrEmpty())
{
foreach (var validationError in Model.ErrorInfo.ValidationErrors)
{
<text>* </text>@(validationError.Message)
if (validationError.Members != null && validationError.Members.Any())
{
<text>(@string.Join(", ", validationError.Members))</text>
}
<br />
}
}
</p>
</div>

@ -1,69 +0,0 @@
using System;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.Http;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Error
{
public class IndexModel : PageModel
{
public RemoteServiceErrorInfo ErrorInfo { get; set; }
[BindProperty(SupportsGet = true)]
public int HttpStatusCode { get; set; }
private readonly IExceptionToErrorInfoConverter _errorInfoConverter;
private readonly IHttpExceptionStatusCodeFinder _statusCodeFinder;
public IndexModel(IExceptionToErrorInfoConverter errorInfoConverter, IHttpExceptionStatusCodeFinder statusCodeFinder)
{
_errorInfoConverter = errorInfoConverter;
_statusCodeFinder = statusCodeFinder;
}
public void OnGet()
{
HandleError();
}
public void OnPost()
{
HandleError();
}
public void OnPut()
{
HandleError();
}
public void OnDelete()
{
HandleError();
}
public void OnPatch()
{
HandleError();
}
private void HandleError()
{
var exHandlerFeature = HttpContext.Features.Get<IExceptionHandlerFeature>();
var exception = exHandlerFeature != null
? exHandlerFeature.Error
: new Exception("Unhandled exception!"); //TODO: Localize?
ErrorInfo = _errorInfoConverter.Convert(exception);
if (HttpStatusCode == 0)
{
HttpStatusCode = (int)_statusCodeFinder.GetStatusCode(HttpContext, exception);
}
HttpContext.Response.StatusCode = HttpStatusCode;
}
}
}

@ -0,0 +1,11 @@
using Volo.Abp.Http;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Views.Error
{
public class AbpErrorPageModel
{
public RemoteServiceErrorInfo ErrorInfo { get; set; }
public int HttpStatusCode { get; set; }
}
}

@ -0,0 +1,40 @@
@using System.Linq
@using System.Collections.Generic
@using Localization.Resources.AbpUi
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Error
@model AbpErrorPageModel
@inject IHtmlLocalizer<AbpUiResource> L
@{
var errorMessage = Model.ErrorInfo.Message;
var errorDetails = Model.ErrorInfo.Details;
if (errorDetails.IsNullOrEmpty())
{
errorDetails = errorMessage;
errorMessage = L["Error"].Value + "!";
}
}
<h1>
[@Model.HttpStatusCode] @errorMessage
</h1>
<div>
<p>
@errorDetails
</p>
<p>
@if (!Model.ErrorInfo.ValidationErrors.IsNullOrEmpty())
{
foreach (var validationError in Model.ErrorInfo.ValidationErrors)
{
<text>* </text>@(validationError.Message)
if (validationError.Members != null && validationError.Members.Any())
{
<text>(@string.Join(", ", validationError.Members))</text>
}
<br />
}
}
</p>
</div>

@ -46,6 +46,13 @@
"DatatableActionDropdownDefaultText": "Actions",
"ChangePassword": "Change password",
"PersonalInfo": "My profile",
"AreYouSureYouWantToCancelEditingWarningMessage": "You have unsaved changes."
"AreYouSureYouWantToCancelEditingWarningMessage": "You have unsaved changes.",
"UnhandledException": "Unhandled exception!",
"401Message": "Unauthorized",
"403Message": "Forbidden",
"404Message": "Page not found",
"500Message": "Internal Server Error",
"GoHomePage": "Go to the homepage",
"GoBack": "Go back"
}
}

@ -46,6 +46,13 @@
"DatatableActionDropdownDefaultText": "İşlemler",
"ChangePassword": "Şifre değiştir",
"PersonalInfo": "Profilim",
"AreYouSureYouWantToCancelEditingWarningMessage": "Kaydedilmemiş değişiklikler var."
"AreYouSureYouWantToCancelEditingWarningMessage": "Kaydedilmemiş değişiklikler var.",
"UnhandledException": "Yakalanmamış hata!",
"401Message": "Yetkisiz",
"403Message": "Yasak",
"404Message": "Sayfa bulunamadı",
"500Message": "Sunucu tarafında hata",
"GoHomePage": "Ana sayfaya git",
"GoBack": "Geri dön"
}
}

@ -1,51 +1,58 @@
{
"culture": "zh-Hans",
"texts": {
"InternalServerErrorMessage": "对不起,在处理你的请求期间,产生了一个服务器内部错误!",
"ValidationErrorMessage": "你的请求无效!",
"ValidationNarrativeErrorMessageTitle": "验证时发现以下错误.",
"DefaultErrorMessage": "发生错误!",
"DefaultErrorMessageDetail": "服务器未发送错误的详细信息.",
"DefaultErrorMessage401": "未通过身份验证!",
"DefaultErrorMessage401Detail": "你需要进行身份认证(登录)后再执行此操作.",
"DefaultErrorMessage403": "你没有权限!",
"DefaultErrorMessage403Detail": "你不能执行此操作!",
"DefaultErrorMessage404": "未找到资源!",
"DefaultErrorMessage404Detail": "未在服务中找到请求的资源!",
"EntityNotFoundErrorMessage": "实体 {0} 不存在,id = {1}!",
"Error": "错误",
"AreYouSure": "你确定吗?",
"Cancel": "取消",
"Yes": "是",
"No": "否",
"Close": "关闭",
"Save": "保存",
"SavingWithThreeDot": "保存中...",
"Actions": "操作",
"Delete": "删除",
"Edit": "编辑",
"Refresh": "刷新",
"ProcessingWithThreeDot": "处理中...",
"LoadingWithThreeDot": "加载中...",
"Welcome": "欢迎",
"Login": "登录",
"Register": "注册",
"Logout": "注销",
"Submit": "提交",
"Back": "返回",
"PagerSearch": "搜索",
"PagerNext": "下一页",
"PagerPrevious": "上一页",
"PagerFirst": "首页",
"PagerLast": "尾页",
"PagerInfo": "显示 _TOTAL_ 个条目中的 _START_ 到 _END_ 个.",
"PagerInfoEmpty": "显示0个条目中的0到0",
"PagerInfoFiltered": "(从 _MAX_ 总条目中过滤掉)",
"NoDataAvailableInDatatable": "表中没有数据",
"PagerShowMenuEntries": "显示 _MENU_ 实体",
"DatatableActionDropdownDefaultText": "操作",
"ChangePassword": "修改密码",
"PersonalInfo": "个人信息",
"AreYouSureYouWantToCancelEditingWarningMessage": "你有未保存的更改."
}
"culture": "zh-Hans",
"texts": {
"InternalServerErrorMessage": "对不起,在处理你的请求期间,产生了一个服务器内部错误!",
"ValidationErrorMessage": "你的请求无效!",
"ValidationNarrativeErrorMessageTitle": "验证时发现以下错误.",
"DefaultErrorMessage": "发生错误!",
"DefaultErrorMessageDetail": "服务器未发送错误的详细信息.",
"DefaultErrorMessage401": "未通过身份验证!",
"DefaultErrorMessage401Detail": "你需要进行身份认证(登录)后再执行此操作.",
"DefaultErrorMessage403": "你没有权限!",
"DefaultErrorMessage403Detail": "你不能执行此操作!",
"DefaultErrorMessage404": "未找到资源!",
"DefaultErrorMessage404Detail": "未在服务中找到请求的资源!",
"EntityNotFoundErrorMessage": "实体 {0} 不存在,id = {1}!",
"Error": "错误",
"AreYouSure": "你确定吗?",
"Cancel": "取消",
"Yes": "是",
"No": "否",
"Close": "关闭",
"Save": "保存",
"SavingWithThreeDot": "保存中...",
"Actions": "操作",
"Delete": "删除",
"Edit": "编辑",
"Refresh": "刷新",
"ProcessingWithThreeDot": "处理中...",
"LoadingWithThreeDot": "加载中...",
"Welcome": "欢迎",
"Login": "登录",
"Register": "注册",
"Logout": "注销",
"Submit": "提交",
"Back": "返回",
"PagerSearch": "搜索",
"PagerNext": "下一页",
"PagerPrevious": "上一页",
"PagerFirst": "首页",
"PagerLast": "尾页",
"PagerInfo": "显示 _TOTAL_ 个条目中的 _START_ 到 _END_ 个.",
"PagerInfoEmpty": "显示0个条目中的0到0",
"PagerInfoFiltered": "(从 _MAX_ 总条目中过滤掉)",
"NoDataAvailableInDatatable": "表中没有数据",
"PagerShowMenuEntries": "显示 _MENU_ 实体",
"DatatableActionDropdownDefaultText": "操作",
"ChangePassword": "修改密码",
"PersonalInfo": "个人信息",
"AreYouSureYouWantToCancelEditingWarningMessage": "你有未保存的更改.",
"UnhandledException": "未处理的异常!",
"401Message": "未授权",
"403Message": "禁止访问",
"404Message": "网页未找到",
"500Message": "内部服务器错误",
"GoHomePage": "返回主页",
"GoBack": "返回"
}
}
Loading…
Cancel
Save