Archive

Posts Tagged ‘Tip’

[MVC3] ViewModel Binding To Controller–POST Methods

March 8, 2012 4 comments

Now we should be writing strongly typed Views based on our Models. Now in some cases you may want to use the ViewModel pattern, which allows you to create a View based on:

 

a) One Model and some additional properties

b) Two or more combined Models

c) Two or more combined Models plus some additional properties.

These ViewModel classes would sit in a folder structure, you guessed it, ViewModels in your Visual Studio Project.An example would be my RegisterViewModel i have created:

 

 

public class RegisterViewModel {
    public RegisterModel RegisterModel { get; set; }
    public string UniqueKey { get; set; }
    public bool Thumbnail { get; set; }

}

 

 

So this is quite straight forward really. I have a RegisterModel which is the MVC default Membership model for handling when a new user Registers. I have a property called UniqueKey which will hold the of a created user, and a Boolean field Thumbnail which will be set to true if he want thumbnail images or false if we don’t.

So this is nice a simple then. So what this means that in our GET Action controller for register we can setup the required values. In this instance we only set the Thumbnail property:

 

// GET: /Account/Register public ActionResult Register()
{
    var viewModel = new RegisterViewModel {
        Thumbnail = true };

    return View(viewModel);
}

 

 

Then in our Review View, we need to declare our ViewModel instead of our RegisterModel, plus all our Model fields and the additional properties are parsed:

 

@model MvcImage.ViewModels.RegisterViewModel @using MvcImage.Models
@using Bradaz.OpenSource.MVC
@using Bradaz.OpenSource.MVC.HTMLHelpers

@{     ViewBag.Title = "Register";
} @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.ValidationSummary(true, "Account creation was unsuccessful. Please correct the errors and try again.")
    <div> <fieldset> <legend>Account Information</legend> <div class="editor-label"> @Html.LabelFor(model => model.RegisterModel.UserName)
            </div> <div class="editor-field"> @Html.TextBoxFor(model => model.RegisterModel.UserName)
                @Html.ValidationMessageFor(model => model.RegisterModel.UserName)
            </div> <div class="editor-label"> @Html.LabelFor(model => model.RegisterModel.Email)
            </div> <div class="editor-field"> @Html.TextBoxFor(model => model.RegisterModel.Email)
                @Html.ValidationMessageFor(model => model.RegisterModel.Email)
            </div> <div class="editor-label"> @Html.LabelFor(model => model.RegisterModel.Password)
            </div> <div class="editor-field"> @Html.PasswordFor(model => model.RegisterModel.Password)
                @Html.ValidationMessageFor(model => model.RegisterModel.Password)
            </div> <div class="editor-label"> @Html.LabelFor(model => model.RegisterModel.ConfirmPassword)
            </div> <div class="editor-field"> @Html.PasswordFor(model => model.RegisterModel.ConfirmPassword)
                @Html.ValidationMessageFor(model => model.RegisterModel.ConfirmPassword)
            </div> <div class="editor-label"> @Html.Label("Avatar")
            </div> <div class="editor-field"> @Html.UploadImageFor(model => model.UniqueKey,thumbnail:true)
            </div> <div class="editor-field"> @Html.HiddenFor(model => model.Thumbnail)
            </div> <p> <input type="submit" value="Register" /> </p> </fieldset> </div> }

 

NB: I have changed my UploadImageFor HTML Helper to include Thumbnail support. This will be documented separately and released under my Open Source MvcImage Project.

So this all sounds simple right? Well you may get into a bit of a pickle (like me) when handling the POST Register ActionMethod. This would be peoples first attempts, which are both wrong:

Attempt 1

[HttpPost]
public ActionResult Register(RegisterModel registermodel,
    HttpPostedFileBase imageLoad2)
{
    ///---Code something }

Attempt 2

[HttpPost]
public ActionResult Register(RegisterViewModel registerviewmodel,
    HttpPostedFileBase imageLoad2)
{
    ///---Code something }

 

These are wrong if you wish to access the additional properties and the ResgiterModel within the RegisterViewModel. Let me explain:

 

Attempt 1 – You would be able to access the RegisterModel properties but not the Thumbnail property.

 

Attempt 2 – Your RegisterModel would be null and you wont be able to access the Thumbnail.

 

After these attempts most people scratch their head, curse, then head over to ASP.NET/FORUMS or stackoverflow for an answer. Well it took me a lot of scratching, googling and forum posting (plus nagging my poor friend Shawson!) to find the answers. The answer lies in how MVC binds the Models. The best place to start is in Fiddler, which is a free application for debugging HTTP and is very useful. Here is a glimpse of the form POST when i hit the Register button on my view:

 

 

Capture_Blog

 

As you can see our RegisterModel properties are prefixed with “RegisterModel” and our Thumbnail is just Thumbnail. So if you apply the MVC Binding on this, in the two attempts above, in the first attempt, MVC recognises RegisterModel as these have been binded from the HTTP post data, so are available. Thumbnail though isn’t available in the RegisterModel declaration in the class so this is ignored. In the 2nd attempt there is no RegisterViewModel in the POST so the binding will fail, thus nothing is available and you will get null fields.

 

The answer is the following:

[HttpPost]
public ActionResult Register(bool Thumbnail, 
[Bind(Prefix = "RegisterModel")]RegisterModel registermodel,
    HttpPostedFileBase imageLoad2)
{
    ///-Code something }

 

So here we declare Thumbnail as its own separate parameter and Bind the RegisterModel with a Prefix “RegisterModel” using the BindAttribute.  This allows us toaccess our RegisterViewModel properties AND Models within our controller quite happily.

I hope this helps you when using ViewModels.

Enhanced by Zemanta
Categories: Tip Tags: , , ,

[MVC 3]– HiddenFor Helper –Remember to Use!–TIP

September 11, 2011 Leave a comment

I was skyping a MVC problem with my friend Shaw Young the other day, and it turned out the problem i was experiencing was a nOOb error of not passing a my from the view to the Model, and i kept getting the following SQL Foreign Key exception:

 


The INSERT statement conflicted with the FOREIGN KEY constraint FK_source_destination

 

 

This turned out to be a red herring. The issue was that my View hadn’t had my Guid  field Unique_Key declared to be bound, ready for POST Action Method. Now because i don’t want the user to see the keys (It would be ugly!) on the view, you can use the following HTML Helper method:

 

@Html.HiddenFor(model => model.Unique_Key)

 

This will mean my Guid is not rendered to the user BUT is passed to my POST method to be used without throwing any nasty exceptions. A nOOb mistake but easy to miss and even harder to find! I spent along time checking my SQL DB Design.

Enhanced by Zemanta
Categories: Tip Tags: , , ,
Follow

Get every new post delivered to your Inbox.

Join 244 other followers

%d bloggers like this: