If you are using the
ASP.NET MVC
DefaultModelBinder to manage the creating complex types from your views’ form data, as well as the validation summary helper provided with ASP.NET MVC then you may have run into the situation I did. I created a simple form, in a dummy app, to create a new contact. The page is named AddContactClassic.aspx, the contents are shown below.
<%
@
Page
Title
=""
Language
="C#"
MasterPageFile
="~/Views/Shared/Site.Master"
Inherits
="System.Web.Mvc.ViewPage"
%>
<%
@
Import
Namespace
="Sedodream.Web.Common.Contact"
%>
<
asp
:
Content
ID
="Content1"
ContentPlaceHolderID
="TitleContent"
runat
="server">
Add Contact Classic
asp
:
Content
>
<
asp
:
Content
ID
="Content2"
ContentPlaceHolderID
="MainContent"
runat
="server">
<
h2
>
Add Contact Classic
h2
>
<%
=
Html.ValidationSummary(
"Errors exist"
) %>
<
ol
><
li
><
span
class
="success-message">
<%
=
ViewData[
"SuccessMessage"
]%>
span
>
li
>
ol
>
<%
using
(Html.BeginForm())
{ %>
<
fieldset
>
<
legend
>
Account Information
legend
>
<
ol
>
<
li
>
<
label
for
="FirstName">
First name
label
>
<%
=
Html.TextBox(
"FirstName"
) %>
<%
=
Html.ValidationMessage(
"FirstName"
,
"*"
) %>
li
>
<
li
>
<
label
for
="LastName">
Last name
label
>
<%
=
Html.TextBox(
"LastName"
) %>
<%
=
Html.ValidationMessage(
"LastName"
,
"*"
) %>
li
>
<
li
>
<
label
for
="Email">
Email
label
>
<%
=
Html.TextBox(
"Email"
)%>
<%
=
Html.ValidationMessage(
"Email"
,
"*"
)%>
li
>
<
li
>
<
label
for
="Phone">
Phone
label
>
<%
=
Html.TextBox(
"Phone"
)%>
<%
=
Html.ValidationMessage(
"Phone"
,
"*"
)%>
li
>
<
li
>
<
div
class
="option-group"
id
="Gender">
<%
=
Html.RadioButton(
"Gender"
,
Gender
.Male.ToString())%>
<
span
>
<%
=
Gender
.Male.ToString() %>
span
>
<%
=
Html.RadioButton(
"Gender"
,
Gender
.Female.ToString())%>
<
span
>
<%
=
Gender
.Female.ToString() %>
span
>
div
>
li
>
<
li
>
<
input
type
="submit"
value
="Add contact"
/>
li
>
ol
>
fieldset
>
<% } %>
asp
:
Content
>
In my
ContactController
class the following methods are defined.
public
ActionResult
AddContactClassic()
{
return
View();
}
[
AcceptVerbs
(
HttpVerbs
.Post)]
public
ActionResult
AddContactClassic(
Contact
contact)
{
if
(contact ==
null
) {
throw
new
ArgumentNullException
(
"contact"
); }
InternalAddContact(contact);
return
View();
}
When I ran the app and filled in all the values on the AddContactClassic page I was a bit surprised to see an error simply stating “A value is required.” Here is a screen shot.
So I assumed that I must have misspelled one of the names of the fields that were passed to the
Html.TextBox
method. Obviously this was not the issue, so then I remembered that the Contact class that I defined had another property, Id, which I was not contained in a field on the form. This is the case because this page is supposed to create a new Contact, so its Id will not be set. I changed the AddContactClassic(Contact) method to ignore the Id property when binding was occurring. Here is the new method.
[
AcceptVerbs
(
HttpVerbs
.Post)]
public
ActionResult
AddContactClassic(
[
Bind
(Exclude=
"Id"
)]
Contact
contact)
{
if
(contact ==
null
) {
throw
new
ArgumentNullException
(
"contact"
); }
InternalAddContact(contact);
return
View();
}
By using the
Bind attribute
I was able to let the
DefaultModelBinder
know that I was not interested in getting the value for that field. Once I made this change everything worked fine.
In the Contact class I had incorrectly defined the Id property to be
Guid
instead of
Guid?
which is better. If I had correctly declared that then the
DefaultModelBinder
would have known that it was not a required field and it would not have complained. But if you are using the
Entity Framework
, you may still have this issue anyway because it does not always create nullable fields for all nullable columns in my experience. Even after changing the Contact class to use Guid? I have purposefully left the
Bind(Exclude=”Id”)
on the method in case something changes in the implementation of the Contact class.
Sayed Ibrahim Hashimi
Comments are closed.