views:

593

answers:

2

I am using asp.net's modelbinder functionality to bind form values to my entity when posting from a view.

The html renders correctly in the initial view with correct option and value items.

When completing the form and posting, all values are populated correctly into the entity except the value from the dropdown list. not sure what I am doing wrong.

code attached below:

Customer Entity:

 public class Customer : EntityBase
    {
        public virtual string Name { get; set; }
        public virtual string Email { get; set; }
        public virtual string Mobile { get; set; }
        public virtual Store LocalStore { get; set; }
        public virtual DateTime? DateOfBirth { get; set; }

        public Customer(){}

        public Customer(string name, string email, string mobile, Store localStore):this(name, email, mobile, localStore, null)
        {
        }

        public Customer(string name, string email, string mobile, Store localStore, DateTime? dateOfBirth)
        {
            Name = name;
            Email = email;
            Mobile = mobile;
            LocalStore = localStore;
            DateOfBirth = dateOfBirth;
        }
    }

ViewModel:

 public class CustomerViewModel {

        // Properties
       private IStoreRepository _StoreRepository;
       public Customer Customer { get; private set; }
       public SelectList Stores { get; private set; }

        // Constructor
        public CustomerViewModel(IStoreRepository storeRepository, Customer customer)
        {
            _StoreRepository = storeRepository;
            Customer = customer;
                Stores = new SelectList(_StoreRepository.GetAllStores(), "Id", "Name", Customer.LocalStore.Id);

        }
    }

Controller:

 [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create([Bind(Prefix="")]Customer customer)
        {
            return View(new CustomerViewModel(_StoreRepository, customer));
        }

View:

<%@ Import Namespace="BlackDiamond.Buzz.MVCWeb.Controllers"%>
<%@ Import Namespace="BlackDiamond.Buzz.Core"%>
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CustomerViewModel>" %>
<%
    Customer customer = ViewData.Model.Customer;
    using (Html.BeginForm())
    {
    %>    
    <table>
        <tr>
            <td>Local Store:</td>
            <td><%= Html.DropDownList("LocalStore", ViewData.Model.Stores)%></td>
         </tr>
         <tr>
            <td>Name:</td><td><%= Html.TextBox("Name", customer.Name)%></td>
         </tr>
         <tr>
            <td>Email:</td><td><%= Html.TextBox("Email", customer.Email)%></td>
        </tr>
        <tr>
            <td>Mobile:</td><td><%= Html.TextBox("Mobile", customer.Mobile)%></td>
        </tr>
    </table>
    <input type="submit" value="Create" />
<%}%>
+1  A: 

Maybe because you declare LocalStore as Store type?

public virtual Store LocalStore { get; set; }

I think it should be int (if "id" property is int) or string. Not sure though.

public virtual int LocalStore { get; set; }
Francisco
Thanks for the post. The problem was indeed the LocalStore value being a object of type Store as opposed to a string guid. Had to create a custom modelbinder to retrieve the correct Store using the guid id.Thanks again for the post
+1  A: 

Had to create a custom modelbinder to retrieve the Store entity based on the guid from the dropdown list:

    public class CustomerModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(Customer))
        {
            // get values
            string name = bindingContext.ValueProvider["Name"].AttemptedValue;
            string email = bindingContext.ValueProvider["Email"].AttemptedValue;
            string mobile = bindingContext.ValueProvider["Mobile"].AttemptedValue;
            Guid storeId = new Guid(bindingContext.ValueProvider["LocalStore"].AttemptedValue);
            Store localStore = IoC.Container.Resolve<IStoreRepository>().GetStore(storeId);

            // hydrate
            return new Customer(name, email, mobile, localStore);
        }
        else
        {
            return null;
        }
    }
}