Skip to content

Instantly share code, notes, and snippets.

@hudo
Last active March 12, 2019 22:43
Show Gist options
  • Save hudo/fa0da9405d3ab68d00d56a645acbf4b6 to your computer and use it in GitHub Desktop.
Save hudo/fa0da9405d3ab68d00d56a645acbf4b6 to your computer and use it in GitHub Desktop.
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