如何在 Asp.Net Core MVC 的 ExceptionFilter 中返回带有模型的视图

Jen*_*nan 5 c# asp.net-core asp.net-core-2.0

我创建了一个 Asp.Net Core MVC 应用程序。我想处理两种类型的错误。

我创建了两个例外:UserFriendlyExceptionUserFriendlyViewException.

我试图创建ExceptionFilter我需要根据这些规则处理这两个异常的:

如果UserFriendlyViewException调用异常,那么我想返回带有原始 ViewName 的 ViewResultAddModelError并返回原始模型。

如果异常UserFriendlyException被调用,那么我想重定向到Error查看。

这是我的ExceptionFilterAttribute

public class ControllerExceptionFilterAttribute : ExceptionFilterAttribute
{
    private readonly ITempDataDictionaryFactory _tempDataDictionaryFactory;
    private readonly IModelMetadataProvider _modelMetadataProvider;

    public ControllerExceptionFilterAttribute(ITempDataDictionaryFactory tempDataDictionaryFactory,
                IModelMetadataProvider modelMetadataProvider)
    {
        _tempDataDictionaryFactory = tempDataDictionaryFactory;
        _modelMetadataProvider = modelMetadataProvider;
    }
    public override void OnException(ExceptionContext context)
    {
        if (!(context.Exception is UserFriendlyException) && !(context.Exception is UserFriendlyViewException)) return;

        var tempData = _tempDataDictionaryFactory.GetTempData(context.HttpContext);
        //CreateNotification(NotificationHelpers.AlertType.Error, tempData, context.Exception.Message);
        if (!tempData.ContainsKey(NotificationHelpers.NotificationKey)) return;

        if (context.Exception is UserFriendlyViewException userFriendlyViewException)
        {
            context.ModelState.AddModelError(userFriendlyViewException.ErrorKey, userFriendlyViewException.Message);
        }

        if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
        {
            //How pass here Model from context??
            //If exists more views with same name but in another controller how pass correct ViewName?
            var result = new ViewResult
            {
                ViewName = context.Exception is UserFriendlyViewException ?
                controllerActionDescriptor.ActionName
                : "Error",
                TempData = tempData,
                ViewData = new ViewDataDictionary(_modelMetadataProvider, context.ModelState)
                            {
                                {"Notifications", tempData[NotificationHelpers.NotificationKey] },
                            }
            };

            context.ExceptionHandled = true;
            context.Result = result;
        }

        tempData.Remove(NotificationHelpers.NotificationKey);
    }
}
Run Code Online (Sandbox Code Playgroud)

我有两个问题:

1.) 如何将原件Model从传递ExceptionContextViewResult

2.)UserFriendlyViewException如果存在更多同名但在另一个控制器中的视图,如何返回正确的 ViewName ?

Set*_*Set 1

如何将原始模型从 ExceptionContext 传递到 ViewResult?

您可以使用context.ModelState集合。

 foreach(var item in context.ModelState)
 {
    string parameter = item.Key;
    object rawValue = item.Value.RawValue;
    string attemptedValue = item.Value.AttemptedValue;

    System.Console.WriteLine($"Parameter: {parameter}, value: {attemptedValue}");
 }
Run Code Online (Sandbox Code Playgroud)

请注意,集合将仅包含绑定参数。


如果存在多个同名视图但在另一个控制器中,如何为 UserFriendlyViewException 返回正确的 ViewName?

框架将使用与控制器操作中相同的视图发现过程,因此您可以指定路径而不是视图名称:

可以提供视图文件路径而不是视图名称。如果使用从应用程序根目录开始的绝对路径(可以选择以“/”或“~/”开头),则必须指定 .cshtml 扩展名:

return View("Views/Home/About.cshtml");
Run Code Online (Sandbox Code Playgroud)

您还可以使用相对路径来指定不同目录中的视图,而无需使用 .cshtml 扩展名。在 HomeController 内部,您可以使用相对路径返回 Manage 视图的 Index 视图:

return View("../Manage/Index");
Run Code Online (Sandbox Code Playgroud)

同样,您可以使用“./”前缀指示当前特定于控制器的目录:

return View("./About");
Run Code Online (Sandbox Code Playgroud)