Reputation: 910
I am trying to create a sample validation attribute to learn more about MVC. I have created the validation attribute, but when I run the application the validation attribute is called twice -> before calling the controller and before saving the DBContext. I believe this should be called only once. Can you guide me where am I doing wrong.
Validation Attribute: I am trying to validate whether the property has too many words than the specified maxWords
public class ValidationEx : ValidationAttribute
{
int _maxWords = 1;
public ValidationEx()
: base("{0} has more too many words")
{
_maxWords = 1;
}
public ValidationEx(int maxWords):base("{0} has more too many words")
{
_maxWords = maxWords;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value != null)
{
string data = value as string;
if (data.Split(' ').Length > _maxWords)
{
var errorMessage = FormatErrorMessage(validationContext.DisplayName);
return new ValidationResult(errorMessage);
}
}
return ValidationResult.Success;
}
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Album album)
{
if (ModelState.IsValid)
{
db.Albums.Add(album);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.GenreID = new SelectList(db.Genres, "GenreID", "Name", album.GenreID);
ViewBag.ArtistID = new SelectList(db.Artists, "ArtistID", "ArtistName", album.ArtistID);
return View(album);
}
Note: Validation is fired before reaching controller and while executing db.SaveChanges()
Model:
public class Album
{
public virtual int AlbumID { get; set; }
public virtual int GenreID { get; set; }
public virtual int ArtistID { get; set; }
[Required(ErrorMessageResourceType= typeof(ErrorMessages), ErrorMessageResourceName="TitleRequired")]
[Display(Name="Movie Name")]
[ValidationEx()]
public virtual string Title { get; set; }
[Range(0,1000)]
public virtual decimal Price { get; set; }
public virtual string AlbumArtUrl { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
[StringLength(40)]
public virtual string Description { get; set; }
}
DBContext
public class MusicAlbumStoreDBContext : DbContext
{
// You can add custom code to this file. Changes will not be overwritten.
//
// If you want Entity Framework to drop and regenerate your database
// automatically whenever you change your model schema, add the following
// code to the Application_Start method in your Global.asax file.
// Note: this will destroy and re-create your database with every model change.
//
// System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges<MusicAlbumProject.Models.MusicAlbumStoreDBContext>());
public MusicAlbumStoreDBContext() : base("name=MusicAlbumStoreDBContext")
{
}
public DbSet<Album> Albums { get; set; }
public DbSet<Genre> Genres { get; set; }
public DbSet<Artist> Artists { get; set; }
public DbSet<Order> Orders { get; set; }
}
Upvotes: 3
Views: 3187
Reputation: 5155
You are using the same class as model and as view model. There is a reason why MVC distringuishes between these 2 types. You really should add a separate model and a separate view model class.
IsValid()
is called twice
db.SaveChanges()
because the DB Context also does a validationUpvotes: 5