diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpErrorPageOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpErrorPageOptions.cs new file mode 100644 index 0000000000..71fb8c5680 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpErrorPageOptions.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared +{ + public class AbpErrorPageOptions + { + public readonly IDictionary ErrorViewUrls; + + public AbpErrorPageOptions() + { + ErrorViewUrls = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs new file mode 100644 index 0000000000..2dd064be1f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs @@ -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 _localizer; + private readonly AbpErrorPageOptions _abpErrorPageOptions; + + public ErrorController( + IExceptionToErrorInfoConverter exceptionToErrorInfoConverter, + IHttpExceptionStatusCodeFinder httpExceptionStatusCodeFinder, + IOptions abpErrorPageOptions, + IStringLocalizer localizer) + { + _errorInfoConverter = exceptionToErrorInfoConverter; + _statusCodeFinder = httpExceptionStatusCodeFinder; + _localizer = localizer; + _abpErrorPageOptions = abpErrorPageOptions.Value; + } + + public IActionResult Index(int httpStatusCode) + { + var exHandlerFeature = HttpContext.Features.Get(); + + 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; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Error/Index.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Error/Index.cshtml deleted file mode 100644 index 421363f8b9..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Error/Index.cshtml +++ /dev/null @@ -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 L -@{ - var errorMessage = Model.ErrorInfo.Message; - var errorDetails = Model.ErrorInfo.Details; - if (errorDetails.IsNullOrEmpty()) - { - errorDetails = errorMessage; - errorMessage = L["Error"].Value + "!"; - } -} - -

- [@Model.HttpStatusCode] @errorMessage -

- -
-

- @errorDetails -

-

- @if (!Model.ErrorInfo.ValidationErrors.IsNullOrEmpty()) - { - foreach (var validationError in Model.ErrorInfo.ValidationErrors) - { - * @(validationError.Message) - if (validationError.Members != null && validationError.Members.Any()) - { - (@string.Join(", ", validationError.Members)) - } -
- } - } -

-
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Error/Index.cshtml.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Error/Index.cshtml.cs deleted file mode 100644 index 66ea202442..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Error/Index.cshtml.cs +++ /dev/null @@ -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(); - - 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; - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Views/Error/AbpErrorViewModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Views/Error/AbpErrorViewModel.cs new file mode 100644 index 0000000000..d9fa172648 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Views/Error/AbpErrorViewModel.cs @@ -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; } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Views/Error/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Views/Error/Default.cshtml new file mode 100644 index 0000000000..f1c6bb91d3 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Views/Error/Default.cshtml @@ -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 L + @{ + var errorMessage = Model.ErrorInfo.Message; + var errorDetails = Model.ErrorInfo.Details; + if (errorDetails.IsNullOrEmpty()) + { + errorDetails = errorMessage; + errorMessage = L["Error"].Value + "!"; + } + } + +

+ [@Model.HttpStatusCode] @errorMessage +

+ +
+

+ @errorDetails +

+

+ @if (!Model.ErrorInfo.ValidationErrors.IsNullOrEmpty()) + { + foreach (var validationError in Model.ErrorInfo.ValidationErrors) + { + * @(validationError.Message) + if (validationError.Members != null && validationError.Members.Any()) + { + (@string.Join(", ", validationError.Members)) + } +
+ } + } +

+
diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json index 7aafe07612..4f44ae87c2 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json @@ -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" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json index 5b236f8954..2ebd7e06df 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json @@ -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" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json index f8da65021d..1030a3860f 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json @@ -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": "返回" } +} \ No newline at end of file