views:

31

answers:

1

Hi Recently I installed VS 2010 Release (migrated from RC) and my MVC application is not working anymore. More concrete: I have a wizard with several steps for new customer account creation (Jquery form wizard, but it doesn't really matter). Each step contains a typed partial View for each part of account: Company, Customer, Licence, etc. When I submit the form I see really strange thing in ModelState. There are duplicate keys for Company: with "Company" prefix and without it. Something like this:

[6] "Company.Phone" string
[12] "Phone" string

My model state for all these keys is not valid because Company is actually null and validation fails. When it was RC there were no such keys with "Company" prefix. So these keys in ModelState with prefix "Company" appeared after I installed VS Release. Here is my code: Main View

<div id="registerSteps">
        <div id="firstStep" class="step">  
         <fieldset>       
          <legend><%=Html.Encode(Register.CustomerInfo) %></legend>
           <% Html.RenderPartial("CustomerInfo", ViewData["newCust"]); %>          
         </fieldset>
        </div>
        <div id="secondStep" class="step"> 
         <fieldset>       
          <legend><%=Html.Encode(Register.CompanyInfo) %></legend>       
          <% Html.RenderPartial("CompanyInfo", ViewData["newComp"]); %>
          </fieldset>
        </div>
        <div id="thirdStep" class="step">  
        <fieldset>       
          <legend><%=Html.Encode(Register.LicenceInfo) %></legend>         
          <% Html.RenderPartial("LicenceInfo", ViewData["newLic"]); %>
          </fieldset>
        </div>
        <div id="lastStep" class="step">
         <fieldset>       
          <legend><%=Html.Encode(Register.PrivacyStatement) %></legend>   
          <% Html.RenderPartial("PrivacyStatementInfo"); %>
          </fieldset>
        </div>        
        <div id="registerNavigation">                           
           <input class="navigation_button" value="Back" type="reset"/> 
           <input class="navigation_button" value="Next" type="submit"/>            
        </div> 
       </div>

Two partial views (to show that they are actually identical): Company:

<div id="dCompanyInfo">
 <div>
  <div>
  <%=Html.LocalizableLabelFor(company => company.Name, Register.CompanyName) %>
  </div>
  <div>
  <%=Html.TextBoxFor(company => company.Name) %>
  <%=Html.ValidationMessageFor(company => company.Name) %>
  </div>
 </div>
 <div>
  <div>
  <%=Html.LocalizableLabelFor(company => company.Phone, Register.Phone) %>
  </div>
  <div>
  <%=Html.TextBoxFor(company => company.Phone) %>
  <%=Html.ValidationMessageFor(company => company.Phone) %>
  </div>
 </div>
 <div>
  <div>
  <%=Html.LocalizableLabelFor(company => company.Fax, Register.Fax) %>
  </div>
  <div>
  <%=Html.TextBoxFor(company => company.Fax) %>
  <%=Html.ValidationMessageFor(company => company.Fax) %>
  </div>
 </div>
 <div>
  <div>
  <%=Html.LocalizableLabelFor(company => company.Size_ID, Register.CompanySize) %>
  </div>
  <div>
  <%=Html.ValueListDropDown(company => company.Size_ID, (CodeRoad.AQua.DomainModel.ValueList)ViewData["CompSize"], (string)ViewData["Culture"]) %>
  <%=Html.ValidationMessageFor(company => company.Size_ID) %>
  </div>
 </div>
 <div>
  <div>
  <%=Html.LocalizableLabelFor(company => company.Industry_ID, Register.Industry) %>
  </div>
  <div>
  <%=Html.ValueListDropDown(company => company.Industry_ID, (CodeRoad.AQua.DomainModel.ValueList)ViewData["Industry"], (string)ViewData["Culture"]) %>
  <%=Html.ValidationMessageFor(company => company.Industry_ID) %>
  </div>
 </div>
</div>

And for Customer

<div id="dCustomerInfo"> 
      <div>
       <div>
        <%=Html.LocalizableLabelFor(customer => customer.Email, Register.Email) %>
       </div>
       <div>
        <%=Html.TextBoxFor(customer => customer.Email) %>
        <%=Html.ValidationMessageFor(customer => customer.Email) %>
       </div>
      </div>
      <div>
       <div>
        <%=Html.LocalizableLabelFor(customer => customer.Male, Register.Gender) %>
       </div>
       <div>
        <%=Html.ListBoolEditor(customer => customer.Male, Register.Male, Register.Female, Register.GenderOptionLabel) %>
        <%=Html.ValidationMessageFor(customer => customer.Male) %>
       </div>
      </div>
      <div>
       <div>
        <%=Html.LocalizableLabelFor(customer => customer.FirstName, Register.FirstName) %>
        </div>
        <div>
        <%=Html.TextBoxFor(customer => customer.FirstName) %>
        <%=Html.ValidationMessageFor(customer => customer.FirstName) %>
        </div>
      </div>
      <div>
        <div>
        <%=Html.LocalizableLabelFor(customer => customer.LastName, Register.LastName) %>
        </div>
        <div>
        <%=Html.TextBoxFor(customer => customer.LastName) %>
        <%=Html.ValidationMessageFor(customer => customer.LastName) %>
        </div>
      </div>
      <div>
        <div>
        <%=Html.LocalizableLabelFor(customer => customer.Role_ID, Register.Role) %>
        </div>
        <div>
        <%=Html.ValueListDropDown(customer => customer.Role_ID, (CodeRoad.AQua.DomainModel.ValueList)ViewData["OrgRole"], (string)ViewData["Culture"])  %>
        <%=Html.ValidationMessageFor(customer => customer.Role_ID) %>
        </div>
      </div>   
 </div>

There are some home made extension methods, but they worked pretty well in previous version (VS RC). Html which is generated is also ok, no "Company.Phone"-like stuff. So I wonder, where all these keys with "Company" came from and what can I do with that? I appreciate any solution.

A: 

I suspect that there were some changes with respect to model binding, specifically with respect to templating. My guess is that during model binding the "Company.Phone" elements are added to the model state because the model you are using for the form action contains a Company property with subproperties such as Phone. Unfortunately, your HTML isn't generated the way the model binder expects -- it isn't aware that the property, Phone, is really a subproperty of the Company property on the model. I'd suggest refactoring your view to use templates instead of partial views for your HTML generation. The templating engine is built to understand the model hierarchy and will generate the correct, prefixed properties in the HTML so that the model binder can work with the returned form values.

Brad Wilson has a nice series of articles on templating that may be helpful.

tvanfosson