Friday, February 24, 2012

MVC4 Beta seems to work quite a bit better with Entity Framework DbValidationExceptiona

In MVC3, if you had an exception from the Fluent validation upon save, you had to specifically catch these exceptions and add them to modelstate. Check out the prior post, I have code in there to handle this case in MVC3 (see below)

I've tested MVC4 and it seems to now catch these validation errors automatically as expected. However I've had problems with fields such as
[Timestamp]
public byte[] Timestamp {get;set;}

no matter what I do these won't save and contain errors so I'll have to experiment a little more with those. Even using [ReadOnly(true)] is ignored and errors are still generated.

 /// 
    /// Author: Adam Tuliper
    /// adam.tuliper@gmail.com
    /// completedevelopment.blogspot.com
    /// www.secure-coding.com
    /// Use freely, just please retain original credit.
    /// 
    /// This filter will add errors to ModelState when an entity fails validation and raises DbEntityValidationException
    /// The properties in the entity should share the same name as the ViewModel properties otherwise
    /// the errors will show up in the validation summary as 'general' errors not assigned to a property
    /// Also note in MVC4 this IS NOT REQUIRED as this is finally handled by the framework then.
    /// 
    public class MapEntityExceptionsToModelErrorsAttribute : FilterAttribute, IExceptionFilter
    {

        public MapEntityExceptionsToModelErrorsAttribute()
        {
        }

        public void OnException(ExceptionContext filterContext)
        {
            if (!filterContext.ExceptionHandled && filterContext.Exception is DbEntityValidationException)
            {
                var model = filterContext.Controller.ViewData.Model;

                foreach (var error in ((System.Data.Entity.Validation.DbEntityValidationException)filterContext.Exception).EntityValidationErrors.First().ValidationErrors)
                {
                    //If the error does not exist in the modelstate, then we will simply add it as a general validation message.
                    var keys = filterContext.Controller.ViewData.ModelState.Keys;
                    if (filterContext.Controller.ViewData.ModelState[error.PropertyName].Errors.Count == 0)
                    {
                        filterContext.Controller.ViewData.ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
                    }
                    else
                    {
                        //Ensure this same message doesn't already exist. If ModelState is detected to have failed,
                        //for instance from a [Required] field, then we don't want to re-add the error. However if we have
                        //a more serious validation error, possibly stemming from some other data validation maybe not related to 
                        //our viewmodel (invalid dat in db, or some other code error bypassing validations)
                        //then we want to add the error. This can happen on Save() and not caught in modelstate.
                        bool found = false;
                        foreach (var errorItem in filterContext.Controller.ViewData.ModelState[error.PropertyName].Errors)
                        {
                            if (errorItem.ErrorMessage == error.ErrorMessage)
                            {
                                found = true;
                                break;
                            }
                        }

                        if (!found)
                        {
                            filterContext.Controller.ViewData.ModelState.AddModelError("", error.ErrorMessage);
                        }
                    }
                }
                //No need to have other exception filters run
                filterContext.ExceptionHandled = true;

                filterContext.Result = new ViewResult() { ViewData = filterContext.Controller.ViewData };
            }
        }
    }

3 comments:

  1. We are a honest and committed team of Marketing, Advertising and IT Consultants. Our specialization is in Business Development, Advertising, Web Designing, Web development, Graphic Designing, Mobile Apps Development, Digital Marketing Expert for more technically complex projects. We're a passionate group of digital marketing and advertising experts.Ecommerce

    ReplyDelete
  2. If you are interested in generating cash from your traffic with popunder ads, you can embed one of the biggest networks: ADFLY.

    ReplyDelete