2
votes

EDIT FOR SOLUTION:

The answer can be found here:

http://forums.asp.net/p/1794394/4941748.aspx/1?p=True&t=634704481730535356

BUT please see the below from Ricardo as well.

I've got a Controller/View called LedgerUser. I have a ViewModel called LedgerViewModel which contains an instance of LedgerUser and SelectList for instances of UserType and a property called UniqueId which i use for Images.

Now when i POST the form back from my Create View I get the following error:

The model item passed into the dictionary is of type 'Accounts.Models.LedgerUser', but this dictionary requires a model item of type 'Accounts.ViewModels.LedgerUserViewModel'. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The model item passed into the dictionary is of type 'Accounts.Models.LedgerUser', but this dictionary requires a model item of type 'Accounts.ViewModels.LedgerUserViewModel'.

Now my understanding is that you pass the Model back to the Action Method and not the ViewModel? Im using the following technologies:

  1. ASP.NET MVC3
  2. Entity Framework 4 Database First

My code is:

LedgerUserViewModel:

/// <summary>
/// ViewModel to represent the LedgerUser & its required fields.
/// </summary>
public class LedgerUserViewModel
{
    public SelectList UserTypes { get; set; }
    public string UserType { get; set; }
    public LedgerUser LedgerUser { get; set; }
    public string UniqueKey { get; set; }               //--Used for the Images.
    public bool Thumbnail { get; set; }

}

I have extended the LedgerUser Model to decorate with Data Annotations:

[MetadataType(typeof(LedgerUserMetaData))]
public partial class LedgerUser
{
    public class LedgerUserMetaData
    {

        [Required(ErrorMessage = "Date Of Birth Required")]
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = " {0:dd/MM/yyyy}")]
        [DataType(DataType.Date)]
        public object DateOfBirth { get; set; }
    }
}

My GET Action Method for LedgerUser:

    // GET: /LedgerUser/Create
    /// <summary>
    /// Action Method to create the LedgerUser. Usually this will be once a user has registered
    /// and will be directed from the AccountController.
    /// </summary>
    /// <param name="id">id</param>
    /// <returns></returns>
    public ActionResult Create(string id)
    {
        var uniqueKey = new Guid(id);
        var userTypes = new SelectList(db.UserTypes, "id", "Description");

        var ledgerUser = new LedgerUser()
        {
            id = uniqueKey,
            RecordStatus = " ",
            CreatedDate = DateTime.Now,
            DateOfBirth = DateTime.Today
        };

        var viewModel = new LedgerUserViewModel()
        {
            UserTypes = userTypes,
            LedgerUser = ledgerUser
        };

        return View(viewModel);
    } 

My POST Action Method for LedgerUser:

[HttpPost]
public ActionResult Create(bool Thumbnail,LedgerUser ledgeruser, HttpPostedFileBase imageLoad2)
{
      ///---code to do stuff..
}

My Create View:

@model Accounts.ViewModels.LedgerUserViewModel
@using Accounts.Models
    @using (Html.BeginForm("Create", "LedgerUser", new { Thumbnail = true}, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.ValidationSummary(true)
<fieldset>
    <legend>Ledger User</legend>

    <div class="editor-field">
        @Html.HiddenFor(model => model.LedgerUser.id)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.LedgerUser.AccountNumber,"Account Number")
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.LedgerUser.AccountNumber)
        @Html.ValidationMessageFor(model => model.LedgerUser.AccountNumber)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.LedgerUser.FirstName,"First Name")
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.LedgerUser.FirstName)
        @Html.ValidationMessageFor(model => model.LedgerUser.FirstName)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.LedgerUser.LastName,"Last Name")
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.LedgerUser.LastName)
        @Html.ValidationMessageFor(model => model.LedgerUser.LastName)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.LedgerUser.DateOfBirth,"D.O.B.")
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.LedgerUser.DateOfBirth)
        @Html.ValidationMessageFor(model => model.LedgerUser.DateOfBirth)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.LedgerUser.UserType, "User Type")
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.LedgerUser.UserType,Model.UserTypes)
    </div>

    <div class="editor-label">
        @Html.Label("Avatar")
    </div>
    <div class="editor-field">
        @Html.UploadImageFor(model => model.UniqueKey,thumbnail:true)
    </div>
    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>
}

Now i have interrogated the POST using Fiddler and i have found that name is correctly being set to "LedgerUser."

Content-Disposition: form-data; name="LedgerUser.id"

d1cd8e85-700d-4462-aa95-7428dbf58deb -----------------------------7dc963b2304b4 Content-Disposition: form-data; name="LedgerUser.AccountNumber"

1 -----------------------------7dc963b2304b4 Content-Disposition: form-data; name="LedgerUser.FirstName"

Gareth -----------------------------7dc963b2304b4 Content-Disposition: form-data; name="LedgerUser.LastName"

Bradley -----------------------------7dc963b2304b4 Content-Disposition: form-data; name="LedgerUser.DateOfBirth"

12 April 2012 -----------------------------7dc963b2304b4 Content-Disposition: form-data; name="LedgerUser.UserType"

b8502da9-3baa-4727-9143-49e33edc910c -----------------------------7dc963b2304b4 Content-Disposition: form-data; name="imageLoad2"; filename="001.jpg" Content-Type: image/jpeg

Im at a loss. Thanks guys

2

2 Answers

2
votes

In your post action method for LedgerUser you are returning to the same view with an incorrect model, your code probably looks like this:

return View();

If you are returning to the same page after creating a new record, you need to make sure you do the same as in your get method:

var ledgerUser = new LedgerUser()
    {
        id = uniqueKey,
        RecordStatus = " ",
        CreatedDate = DateTime.Now,
        DateOfBirth = DateTime.Today
    };

    var viewModel = new LedgerUserViewModel()
    {
        UserTypes = userTypes,
        LedgerUser = ledgerUser
    };

    return View(viewModel);

If you don't want to do this, then just redirect after the post action method to another view such as (assuming you have an Index action):

return View("Index")

Better yet, IF you do need to post to the same view, then just use AJAX/jQuery post to call your Create action instead of the form post.

Good luck.

0
votes

The error you're getting sounds like the error you'd receive if you passed the wrong type of viewmodel to your viewpage. Does your post method look like this?

[HttpPost]
public ActionResult Create(bool Thumbnail,LedgerUser ledgeruser, HttpPostedFileBase imageLoad2)
{
  ///---code to do stuff..
   return View(ledgeruser);
}

If so, you're issue is that you're recreating the view with the wrong model type. That said, yes, you should be taking LedgerViewModel as your post parameter. With MVC, typically whatever model you passed into your view with your get, will be your parameter on the Post.

Suggested structure for your post. Uses the Post Redirect Get (PRG) pattern.

[HttpPost]
public ActionResult Create(LedgerViewModel model)
{
  ///---code to do stuff..
   return RedirectToAction("Create", new {id = model.LedgerUser.id.ToString()});
}