Exception calling UpdateModel - Value cannot be null or empty - asp.net-mvc-2

This is probably something silly I'm missing but I'm definitely lost. I'm using .NET 4 RC and VS 2010. This is also my first attempt to use UpdateModel in .NET 4, but every time I call it, I get an exception saying Value cannont be null or empty. I've got a simple ViewModel called LogOnModel:
[MetadataType(typeof(LogOnModelMD))]
public class LogOnModel
{
public string Username { get; set; }
public string Password { get; set; }
public class LogOnModelMD
{
[StringLength(3), Required]
public object Username { get; set; }
[StringLength(3), Required]
public object Password { get; set; }
}
}
My view uses the new strongly typed helpers in MVC2 to generate a textbox for username and one for the password. When I look at FormCollection in my controller method, I see values for both coming through.
And last but not least, here's are post controller methods:
// POST: /LogOn/
[HttpPost]
public ActionResult Index(FormCollection form)
{
var lm = new LogOnModel();
UpdateModel(lm, form);
var aservice = new AuthenticationService();
if (!aservice.AuthenticateLocal(lm.Username, lm.Password))
{
ModelState.AddModelError("User", "The username or password submitted is invalid, please try again.");
return View(lm);
}
return Redirect("~/Home");
}
Can someone please lend some insight into why UpdateModel would be throwing this exception? Thanks!

Known issue with early previews of MVC 2. This was fixed for MVC 2 RTM. You can download MVC 2 RTM from http://www.asp.net/mvc/. Information on how to jury-rig this installation into VS2010 RC can be found at http://haacked.com/archive/2010/02/10/installing-asp-net-mvc-2-rc-2-on-visual-studio.aspx.

Related

Database First Validation

I have an auto-generated Entity Framework model. It was generated using a database first approach. The mid_initial column has a database defined constraint that limits the column to a maximum length of 3 characters.
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Agency.DataAccess.RegistrationModel
{
using System;
using System.Collections.Generic;
public partial class Registrant
{
public Registrant()
{
}
public int id { get; set; }
public string fname { get; set; }
public string mid_initial { get; set; }
public string lname { get; set; }
}
}
When I try and create a model with a mid_initial greater than 3 characters, a invalid state, ModelState.IsValid is returning true. Because of this db.SaveChanges is then called, which then raises DbEntityValidationException.
[HttpPost]
public ActionResult Create(Registrant registrant)
{
try
{
if (ModelState.IsValid)
{
Debug.WriteLine("Entity was valid.");
db.Registrants.Add(registrant);
db.SaveChanges();
return RedirectToAction("Index");
}
return View("Create", registrant);
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
Debug.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
eve.Entry.Entity.GetType().Name, eve.Entry.State);
foreach (var ve in eve.ValidationErrors)
{
Debug.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage);
}
}
return View(registrant);
}
}
Why is the ModelState.IsValid method returning true? It would seem that my model is not aware of the maximum length constraint. How do I make it aware?
EF db-first can't infer constraints from database.
Use the MaxLenght data annotation attribute:
public partial class Registrant
{
public Registrant()
{
}
public int id { get; set; }
public string fname { get; set; }
[MaxLength(3, ErrorMessage = "")]
public string mid_initial { get; set; }
public string lname { get; set; }
}
Note: this class is a auto generated class and every time you update and save your model (.EDMX file), this code will be overwritten and you'll loose your attributes.
To avoid that, you should extend your classes with some partial classes with the same name and same namespace as your auto-generated classes. If you need examples to show you how, tell me to put it in answer.
MVC is EF-agnostic, and as such doesn't implicitly attempt to validate the model using EF validation to populate its ModelState.
You have four basic solutions I can think of right now:
Hook them up yourself, for example using MVC filters, DbContext.GetValidationErrors and ModelState.
Find and use third-party code that does this already.
Validate the code separately using facilities that MVC can use, for example using DataAnnotations. You may try to generate them automatically by modifying the EF T4 template. Note that this is still technically redundant (the code will be validated twice, once by MVC, once by EF).
Submit a patch for MVC so that it can support EF explicitly (as a soft dependency) and make it all just work (both projects are open source) -- or downvote me because they already did so and I never knew it.

EF Upgrade from 4.0.0 to 4.3.1 causing strange errors

I have just upgraded from EF 4.0.0 to EF 4.3.1.
I am using Visual Studio 2010 Ultimate on Windows XP updated to latest release and all Windows updates/patches applied. The database engine I'm using is SQL Server 2008 R2 Developers Edition.
The following code works perfectly under EF 4.0.0 but not under EF 4.3.1.
public class ItemBase
{
public DateTime Created { get; set; }
public int CreatedByUserID { get; set; }
public DateTime LastModified { get; set; }
public int LastModifiedByUserID { get; set; }
public User CreatedBy { get; set; }
public User LastModifiedBy { get; set; }
public ItemBase()
{
CreatedByUserID = -1;
LastModifiedByUserID = -1;
CreatedBy = null;
LastModifiedBy = null;
}
}
public class User : ItemBase
{
public int UserID { get; set; }
public string LoginName { get; set; }
public string Password { get; set; }
public string EmailAddress { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string DisplayName { get; set; }
public User() : base()
{
UserID = -1;
LoginName = String.Empty;
Password = String.Empty;
EmailAddress = String.Empty;
Firstname = String.Empty;
Lastname = String.Empty;
DisplayName = String.Empty;
}
}
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().Property(u => u.UserID).HasDatabaseGenerationOption(DatabaseGenerationOption.Identity);
}
The only thing that has changed is the version of Entity Framework I'm using.
I have checked the references etc and everything is as expected.
As you can see from the code above, the User class inherits from ItemBase which in turn has a reference to a User instance. The underlying User table contains all the properties from the User class and the ItemBase class (except for the two navigation properties public User CreatedBy { get; set; } and public User LastModifiedBy { get; set; })
Running this code under 4.0.0 everything works as expected, not a single problem or issue whatsoever.
BUT, when I run the same code under 4.3.1 (without any changes whatsoever to anything else, including the database I'm using) I get the following error:
"Unable to determine the principal end of an association between the types 'User' and 'User'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations."
So I then added the following two lines to the OnModelCreating method:
modelBuilder.Entity<User>().HasRequired(u => u.CreatedBy).WithMany().HasForeignKey(k => k.CreatedByUserID);
modelBuilder.Entity<User>().HasRequired(u => u.LastModifiedBy).WithMany().HasForeignKey(k => k.LastModifiedByUserID);
I then get these strange errors:
"The provider did not return a ProviderManifestToken string."
"A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections.
(provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)"
I also noticed loads and loads of these errors in the output window:
"A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll"
However, these errors appear to be a bit of a red-herring, as the database is fine, available, and the connection string is perfect too. If I subsequently undo the changes to the OnModelCreating method I get the original error again, so I don't believe the error messages I'm getting actually reflect the underlying problem that's occurring here.
So, based on all of this, I come to the following conclusions:
There is a bug in version 4.3.1 of the Entity Framework?
The fact that my code worked under 4.0.0 without the extra two lines
in the OnModelCreating method was probably due to checks not being
made in 4.0.0 which are now subsequently being made in 4.3.1?
I need to add something extra to my configuration/code, or I'm
missing something else to make this work again under 4.3.1?
Can anyone shed some light on this for me? Its driving me nuts!
Many thanks for your time on this.
Kind Regards
Steve
It looks like you have been using a pre-release version of EF 4.1. Probably CTP4 or CTP5. This is apparent because:
ModelBuilder was renamed to DbModelBuilder before 4.1 RTM
DatabaseGenerationOption was renamed to DatabaseGeneratedOption
The exception you are seeing was introduced before EF 4.1 was RTM'ed
Given this, I'm not 100% sure what model was being created with the pre-release version you were using. With 4.1 and above the two navigation properties are detected as inverses of each other and Code First tries to make a 1:1 relationship between User and User. Code First cannot determine the principal for this relationship so rather than guessing it throws asking you to provide it.
However, looking at your model it is clear that this is not what you want anyway. It seems much more likely that you want two 1:* uni-directional navigation props--one for CreatedBy and one for LastModifiedBy. This is what you setup in your OnModelCreating call.
With the changes made to the names of the classes to match 4.1/4.3 and with the code added to OnModelCreating, your code works fine for me on EF 4.3.1.
With regard to not being able to make the connection, you say that the connection string is correct, in which case it must be a case of EF not finding it. Assuming it is in your app.config, then you need to pass the name of it to the DbContext constructor. For example:
public class MyContext : DbContext
{
public MyContext()
: base("name=MyConnectionStringName")
{
}
}
If you're using the connection string in some other way then we'll need more details on that.

order of MVC execution

Just trying to learn MVC2/ .net 4.0 at the same time. I am just using the generic template VS comes with when you start with a "MVC 2 Web" project (ie, the account controller and home controllers are setup for you).
So my question is that the view is strongly typed again a model. The model looks like this:
[PropertiesMustMatch("Password", "ConfirmPassword", ErrorMessage = "The password and confirmation password do not match.")]
public class RegisterModel {
[Required]
[DisplayName("User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[DisplayName("Email address")]
public string Email { get; set; }
[Required]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[DisplayName("Password")]
public string Password { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("Confirm password")]
public string ConfirmPassword { get; set; }
[Required]
[DisplayName("School")]
public string School { get; set; }
}
then I guess I press "register" on my web page and it executes the following from my controller:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus = MembershipService.CreateUser(model.UserName, model.Password, model.Email);
if (createStatus == MembershipCreateStatus.Success)
{
FormsService.SignIn(model.UserName, false /* createPersistentCookie */);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", AccountValidation.ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
return View(model);
}
so a couple of questions.
1) The classes that are [] above the method name.. are they executed (i dont know what term to use here) first? For example the model has a [ValidatePasswordLength] above its property. Does that mean upon submitting a password that dosnt validate, it dosnt even hit the controller? Can I also put this logic in the controller?
2) Where is ModelState class coming from ?
I just kinda wanna know in a flow chart way on how everything is connected in MVC. It seems like its a big circle, and there is no starting point.
Attributes aren't executed so much as checked.
During modelbinding the view model will be scanned for attributes, the model binder gets a list of these attributes and can then change its behaviour (eg the [bind] attribute affects if the model binder will try and populate a given property) or call the class (eg Validation attributes).
To answer your questions specifically:
1)Validation can happen in two places, either before the action is called, ie when your action takes a view model, or explicitly in the action when you call TryValidateModel. Either way the action is called, it is up to you to check validity and handle the response accordingly within the action as you did in your action above.
2) ModelState comes from the ModelBinder.
The easiest way to see how MVC works is to download the source, debug and step through a request.

MVC 2 Validation and Entity framework

I have searched like a fool but does not get much smarter for it..
In my project I use Entity Framework 4 and own PoCo classes and I want to use DataAnnotations for validation. No problem there, is how much any time on the Internet about how I do it. However, I feel that it´s best to have my validation in ViewModels instead and not let my views use my POCO classes to display data.
How should I do this smoothly? Since my repositories returns obejekt from my POCO classes I tried to use AutoMapper to get everything to work but when I try to update or change anything in the ModelState.IsValid is false all the time..
My English is really bad, try to show how I am doing today instead:
My POCO
public partial User {
public int Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
And my ViewModel
public class UserViewModel {
public int Id { get; set; }
[Required(ErrorMessage = "Required")]
public string UserName { get; set; }
[Required(ErrorMessage = "Required")]
public string Password { get; set; }
}
Controller:
public ActionResult Edit(int id) {
User user = _userRepository.GetUser(id);
UserViewModel mappedUser = Mapper.Map<User, UserViewModel>(user);
AstronomiGuidenModelItem<UserViewModel> result = new AstronomiGuidenModelItem<UserViewModel> {
Item = mappedUser
};
return View(result);
}
[HttpPost]
public ActionResult Edit(UserViewModel viewModel) {
User user = _userRepository.GetUser(viewModel.Id);
Mapper.Map<UserViewModel, User>(viewModel, user);
if (ModelState.IsValid) {
_userRepository.EditUser(user);
return Redirect("/");
}
AstronomiGuidenModelItem<UserViewModel> result = new AstronomiGuidenModelItem<UserViewModel> {
Item = viewModel
};
return View(result);
}
I've noticed now that my validation is working fine but my values are null when I try send and update the database. I have one main ViewModel that looks like this:
public class AstronomiGuidenModelItem<T> : AstronomiGuidenModel {
public T Item { get; set; }
}
Why r my "UserViewModel viewModel" null then i try to edit?
If the validation is working, then UserViewModel viewModel shouldn't be null... or is it that the client side validation is working but server side isn't?
If that's the case it could be because of the HTML generated.
For instance, if in your view you have:
<%: Html.TextBoxFor(x => x.Item.UserName) %>
The html that gets rendered could possibly be:
<input name="Item.UserName" id="Item_UserName" />
When this gets to binding on the server, it'll need your action parameter to be named the same as the input's prefix (Item). E.g.
public ActionResult Edit(UserViewModel item) {
To get around this, do as above and change your action parameter to item OR you could encapsulate the form into a separate PartialView which takes the UserViewModel as it's model - that way the Html.TextBoxFor won't be rendered with a prefix.
HTHs,
Charles
Ps. If I'm totally off track, could you please post some code for the view.

Entity Framework error when submitting empty fields

VS 2010 Beta 2, .NET 4.
In my ASP.NET MVC 2 application, when I submit a form to an action method that accepts an object created by the entity framework, I get the following error:
Exception Details: System.Data.ConstraintException: This property cannot be set to a
null value.
Source Error:
Line 4500: OnTextChanging(value);
Line 4501: ReportPropertyChanging("Text");
Line 4502: _Text = StructuralObject.SetValidValue(value, false);
Line 4503: ReportPropertyChanged("Text");
Line 4504: OnTextChanged();
The property is called "Text" and is of type "text NOT NULL" in MS SQL 2008.
My action will check if the value is nullorempty, if it is, a model error will be added, but I get the error as soon as I submit the form.
Are you binding directly to the entity? Sure looks like it. So you have two choices:
Write a custom model binder which translates null -> empty string.
Bind to an edit model which allows nulls instead, and then change this to empty string when you copy the values to the entity in the action.
I'd choose #2, personally. I think you should always use view/edit models, and this is a great example of why.
I was having the same problem. I looked around and found a work around here. It describes the problem as being caused by the EF validation taking place before the Required field validation. It also shows how we can work around this problem by using a [DisplayFormat] Tag. Hope this will help you.
Here's the link to the question and the workaround:
Server-side validation of a REQUIRED String Property in MVC2 Entity Framework 4 does not work
Is this an issue with the MVC2 and Entity Framework 4 or is this by design? It appears that validation of EF properties works fine for datetime non-nullable (required) fields and data type validation of numeric versus string fields is working without having to use ViewModels.
I recreated the issue using with a simple FOOBAR table using a single, non-nullable varchar(50) column called barName in slq 2008. I generated the EF model from that database and quickly added a controller and a CREATE view for the FOOBAR entity. If I try to POST to the CREATE action without entering in a value for the property barName, VS steps into an exception within the designer.cs file of the model (just like the one above). When, I try to step past the exception, the validation message shows up on the form and the field is highlighted in pink.
It seems like something is not firing in the correct sequence. Because the exception occurs before VS steps into the HTTPPOST CREATE method.
I found the code from the ASP.Net MvcMusicStore sample helpful. http://mvcmusicstore.codeplex.com/releases/view/44445#DownloadId=119336
It appears that binding to the ViewModel fixes the issue.
namespace MvcMusicStore.ViewModels
{
public class StoreManagerViewModel
{
public Album Album { get; set; }
public List<Artist> Artists { get; set; }
public List<Genre> Genres { get; set; }
}
}
........
namespace MvcMusicStore.Models
{
[MetadataType(typeof(AlbumMetaData))]
public partial class Album
{
// Validation rules for the Album class
[Bind(Exclude = "AlbumId")]
public class AlbumMetaData
{
[ScaffoldColumn(false)]
public object AlbumId { get; set; }
[DisplayName("Genre")]
public object GenreId { get; set; }
[DisplayName("Artist")]
public object ArtistId { get; set; }
[Required(ErrorMessage = "An Album Title is required")]
[StringLength(160)]
public object Title { get; set; }
[DisplayName("Album Art URL")]
[StringLength(1024)]
public object AlbumArtUrl { get; set; }
[Required(ErrorMessage = "Price is required")]
[Range(0.01, 100.00, ErrorMessage="Price must be between 0.01 and 100.00")]
public object Price { get; set; }
}
}
}
Ashish Shakya's answer helped me. I added this attribute to the property and now it works.
[DisplayFormat(ConvertEmptyStringToNull = false, NullDisplayText="")]
So it looks like this:
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
[DisplayFormat(ConvertEmptyStringToNull = false, NullDisplayText="")]
public global::System.String MyProperty
{
get
{
return _MyProperty;
}
set
{
OnMyPropertyChanging(value);
ReportPropertyChanging("MyProperty");
_MyProperty = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("MyProperty");
OnMyPropertyChanged();
}
}
Import the namespace:
using System.ComponentModel.DataAnnotations;
And add the attribute property [Required]
[Required]
public global::System.String MyProperty
{
get
{
return _MyProperty;
}
set
{
OnMyPropertyChanging(value);
ReportPropertyChanging("MyProperty");
_MyProperty = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("MyProperty");
OnMyPropertyChanged();
}
}
Thus ModelState.IsValid equals false, showing error message in the validation and will not fail on the server with Null.
I had the same problem and fixed it by making false to true like this:
Line 4502:
_Text = StructuralObject.SetValidValue(value, false);
I just had the same problem myself, and came here to find the solution. However, the answer can be enhanced.
Svavar's and HackITMngr were on the right track, however combining both gives the best outcome. You don't want to go decorating the generated classes, as you risk losing your custom changes upon modifications to the EF model.
[MetadataType(typeof(MyTableMetaData))]
public partial class MyTable
{
// Validation rules for the Album class
public class MyTableMetaData
{
[DisplayFormat(ConvertEmptyStringToNull = false, NullDisplayText="")]
public string MyTextProperty { get; set; }
}
}
To settle any arguments between the two. I'd say Svavar's was the direct answer, HackITMngr was the enhancement.
Works great for me!
I set StoreGeneratedPattern property as Computed for each field and it solved the problem for me.