Q:

Setting the name attributes in HTML helper methods results in bad naming because of Tuple

Hi I am trying to post a form in asp.net MVC but it seem that when I click the submit button my controller is not called. 
This happens I think because the names of each input is not set corectly because I am using a Tuple. I have tryed setting the name using HTML attributes property but it seems it does not work. 
He is my Model:
    public int Id { get; set; }
            public string Name { get; set; }
            public string Author { get; set; }
            public string Description { get; set;}
            public DateTime PublicationDate { get; set; }
            public int CategoryId { get; set; }

Here is my controller:
    public ActionResult AddBook()
        {
            IEnumerable<CategoryModel> categories = categoryContext. GetCategories();
            Tuple<BookModel1, IEnumerable<CategoryModel>> model =
                new Tuple<BookModel1, IEnumerable<CategoryModel>>(book, categories);
            return View(model);
        }

        [HttpPost]
        public ActionResult AddBook(BookModel1 book)
        {
            bookContext. AddBook(book);
            return RedirectToAction("Index", "ProductManager");
        }

And this is my View:
    @using (Html. BeginForm()) {
        @Html. ValidationSummary(true)
        <fieldset>
               @Html. LabelFor(x => x.Item1.Name , "Book Name")
               @Html. TextBoxFor(x => x.Item1.Name, new { name = "Name" })
               @Html. LabelFor(x => x.Item1.Author)
               @Html. TextBoxFor(x => x.Item1.Author , new { name = "Author" })
               @Html. LabelFor(x => x.Item1.PublicationDate ,"Publication Date")
               @Html. TextBoxFor(x => x.Item1.PublicationDate , new { name = "PublicationDate" })
               @Html. LabelFor(x => x.Item2 , "Select category")
               @Html. DropDownListFor(x => x.Item2, new SelectList(Model. Item2, "Id", "Name")) 
               @Html. LabelFor(x => x.Item1.Description)
               @Html. TextAreaFor(x => x.Item1.Description ,  new { name = "Description" })
            <p>
                <input type="submit" value="Create" class="link"/>
                @Html. ActionLink("Back to List", "Index", "ProductManager", null,new { @class ="link"})
            </p>
        </fieldset>
    }

Even if I tryed setting the name property with HTMLAttributes the resulting names still look something like this : Item1.PublicationDate. 
  I am using ADO.NET for data access. 
How can I solve this problem  so I can call AddBook(BookModel1 book) controller? 

A:

Yes, the problem is because of the Tuple class.  The Item property is readonly and it doesn't have a setter meaning that the default model binder cannot set its value on postback.  You should use a view model instead:
public class MyViewModel
{
    public BookModel1 Book { get; set; }
    public IEnumerable<CategoryModel> Categories { get; set; }
}

and then make your view strongly typed to the view model:
@model MyViewModel
@using (Html. BeginForm()) {
    @Html. ValidationSummary(true)
    <fieldset>
        @Html. LabelFor(x => x.Book. Name, "Book Name")
        @Html. TextBoxFor(x => x.Book. Name, new { name = "Name" })
        @Html. LabelFor(x => x.Book. Author)
        @Html. TextBoxFor(x => x.Book. Author, new { name = "Author" })
        @Html. LabelFor(x => x.Book. PublicationDate, "Publication Date")
        @Html. TextBoxFor(x => x.Book. PublicationDate , new { name = "PublicationDate" })
        @Html. LabelFor(x => x.Book. CategoryId, "Select category")
        @Html. DropDownListFor(
            x => x.Book. CategoryId, 
            new SelectList(Model. Categories, "Id", "Name")
        ) 
        @Html. LabelFor(x => x.Book. Description)
        @Html. TextAreaFor(x => x.Book. Description, new { name = "Description" })
        <p>
            <input type="submit" value="Create" class="link"/>
            @Html. ActionLink("Back to List", "Index", "ProductManager", null, new { @class ="link"})
        </p>
    </fieldset>
}

and finally your controller:
public ActionResult AddBook()
{
    var model = new MyViewModel();
    model. Categories = categoryContext. GetCategories();
    model. Book = ...
    return View(model);
}

[HttpPost]
public ActionResult AddBook(MyViewModel model)
{
    bookContext. AddBook(model. Book);
    return RedirectToAction("Index", "ProductManager");
}

