Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How return View with model in the ExceptionFilter in Asp.Net Core MVC

I have created an Asp.Net Core MVC application. I want to handle two types of errors.

I have create two exceptions: UserFriendlyException and UserFriendlyViewException.

I have tried to create the ExceptionFilter that I need handle these two exceptions according these rules:

If is exception UserFriendlyViewException called then I want to return ViewResult with original ViewName and AddModelError and return original Model.

If is exception UserFriendlyException called then I want to redirect to Error view.

This is my 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);
    }
}

I have two issues:

1.) How can I pass original Model from ExceptionContext to ViewResult?

2.) How return correct ViewName for UserFriendlyViewException if exists more Views with same name but in another Controller?

like image 544
Jenan Avatar asked Nov 23 '17 11:11

Jenan


People also ask

How do I return a view model?

To return a model from the controller action method to the view, we need to pass the model/object in the View() method. Here, the View gets the model as UserNamePasswordModel object with its property set. To retrieve properties of this object in the view, we can use @Model ; like @Model.

What does return View () in MVC do?

View discovery The default behavior of the View method ( return View(); ) is to return a view with the same name as the action method from which it's called. For example, the About ActionResult method name of the controller is used to search for a view file named About. cshtml .

How do you pass view model to view?

The recommended way to pass the ViewModel to the View is to make use of the View method. The View method takes the model as one of the argument, which internally sets it to the ViewData. Model Property.


1 Answers

How can I pass original Model from ExceptionContext to ViewResult?

You may use context.ModelState collection.

 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}");
 }

Note, collection will contain only bound parameters.


How return correct ViewName for UserFriendlyViewException if exists more Views with same name but in another Controller?

The same View discovery process will be used by framework as in the controller's action, so instead of View name you can specify the path:

A view file path can be provided instead of a view name. If using an absolute path starting at the app root (optionally starting with "/" or "~/"), the .cshtml extension must be specified:

return View("Views/Home/About.cshtml");

You can also use a relative path to specify views in different directories without the .cshtml extension. Inside the HomeController, you can return the Index view of your Manage views with a relative path:

return View("../Manage/Index");

Similarly, you can indicate the current controller-specific directory with the "./" prefix:

return View("./About");
like image 133
Set Avatar answered Oct 20 '22 17:10

Set