Last active
March 12, 2019 22:43
-
-
Save hudo/fa0da9405d3ab68d00d56a645acbf4b6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ValidateModelAttribute : ActionFilterAttribute | |
{ | |
public override async Task OnActionExecutionAsync(ActionExecutingContext context, Action | |
{ | |
var result = new ViewResult(); | |
if (!context.ModelState.IsValid) | |
{ | |
// Usually POST action looks like: IActionResult Save(MyMode model) | |
// if validation failed we need to forward that model back to view | |
// Model is in ActionArgument[0] in this case, but you may tweak | |
// this to your specific needs | |
if (context.ActionArguments.Count > 0) | |
{ | |
SetViewData(context, result); | |
} | |
// This is same as | |
// return View(mnodel); | |
context.Result = result; | |
} | |
else | |
{ | |
try | |
{ | |
// This was all happening BEFORE actione executed. | |
// Lets exec the action now and catch possible exceptions! | |
await next.Invoke(); | |
} | |
// You can catch here app specific exception! | |
// catch(MySpecialException e) | |
catch (Exception e) | |
{ | |
// Uh, something went wrong:( | |
// Pull logger for IOC container. | |
// Note: I don't really like this approach, it would be much nicer to inject | |
// interfaces into ctor, but then we wouldn't be able to use this filter like: | |
// [ValidateModel] <- ctor requires interface, doesn't compile | |
// but like this: | |
// [ServiceFilter(typeof(ValidateModelAttribute))] | |
// so pick whatever approach you like! | |
var loggerFactory = context.HttpContext.RequestServices.GetService<ILoggerFactory>(); | |
var message = e.Unwrap().Message; // Dig for inner exception message | |
var descriptor = context.ActionDescriptor as ControllerActionDescriptor; | |
var logger = loggerFactory.CreateLogger(descriptor.ControllerName); | |
logger.LogError($"Error while executing {descriptor.ControllerName}/{descriptor.ActionName}: {message}"); | |
// Sets view model, and adds error to ModelState list | |
if (context.ActionArguments.Count > 0) | |
{ | |
SetViewData(context, result); | |
result.ViewData.ModelState.AddModelError("", message); | |
} | |
// Again, return View(model); | |
context.Result = result; | |
} | |
} | |
} | |
/// <summary> | |
/// Sets view model from action executing context | |
/// </summary> | |
private static void SetViewData(ActionExecutingContext context, ViewResult result) | |
{ | |
result.ViewData = new ViewDataDictionary( | |
context.HttpContext.RequestServices.GetService<IModelMetadataProvider>(), | |
context.ModelState); | |
result.ViewData.Model = context.ActionArguments.First().Value; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment