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?
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.
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 .
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.
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");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With