0

I have a view pages that have different partial views with different models. I created a model class that will call other classes so i can use it on the main view page. But my problem is that when i try to change the password it gives me an error that i am passing in a model which i need to pass in another model. I believe i have my structure right but not sure what is causing this issue.

Main view:

 @model Acatar.Models.ProfileModel

        @{
            ViewBag.Title = "ProfileAccount";
        }
        @{ Html.RenderAction("_PlayNamePartial"); }
        @{ Html.RenderAction("_UsernamePartial", "Account");}
        @{ Html.RenderAction("_TalentsPartial", "Account");}

            @if (ViewBag.HasLocalPassword)
            {
                @Html.Partial("_ChangePasswordPartial")
            }
            else
            { 
                @Html.Partial("_SetPasswordPartial")
            }

Profile Model: containing models that i have created

public class ProfileModel
    {
        public LocalPasswordModel LocalPasswordModel { get; set; }
        public PlayNameModel PlayNameModel { get; set; }
        public UsernameModel UsernameModel { get; set; }
        public TalentsModel  TalentsModel { get; set; }
    }

Controller:

public ActionResult Profile(ManageMessageId? message)
    {
        ViewBag.StatusMessage =
            message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
            : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
            : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
            : "";
        ViewBag.HasLocalPassword = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
        ViewBag.ReturnUrl = Url.Action("Profile");
        return View();
    }

POST:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Profile(LocalPasswordModel model)
    {
        bool hasLocalAccount = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
        ViewBag.HasLocalPassword = hasLocalAccount;
        ViewBag.ReturnUrl = Url.Action("Profile");
        if (hasLocalAccount)
        {
            if (ModelState.IsValid)
            {
                // ChangePassword will throw an exception rather than return false in certain failure scenarios.
                bool changePasswordSucceeded;
                try
                {
                    changePasswordSucceeded = WebSecurity.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword);
                }
                catch (Exception)
                {
                    changePasswordSucceeded = false;
                }

                if (changePasswordSucceeded)
                {
                    return RedirectToAction("Profile", new { Message = ManageMessageId.ChangePasswordSuccess });
                }
                else
                {
                    ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
                }
            }
        }
        else
        {
            // User does not have a local password so remove any validation errors caused by a missing
            // OldPassword field
            ModelState state = ModelState["OldPassword"];
            if (state != null)
            {
                state.Errors.Clear();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    WebSecurity.CreateAccount(User.Identity.Name, model.NewPassword);
                    return RedirectToAction("Profile", new { Message = ManageMessageId.SetPasswordSuccess });
                }
                catch (Exception e)
                {
                    ModelState.AddModelError("", e);
                }
            }
        }

        return View(model);
    }

View Page for password change:

@model Project.Models.LocalPasswordModel


@using (Html.BeginForm("Profile", "Account")) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary()

    <fieldset>
        <legend>Change Password Form</legend>

                @Html.LabelFor(m => m.OldPassword)
                @Html.PasswordFor(m => m.OldPassword)

                @Html.LabelFor(m => m.NewPassword)
                @Html.PasswordFor(m => m.NewPassword)

                @Html.LabelFor(m => m.ConfirmPassword)
                @Html.PasswordFor(m => m.ConfirmPassword)

       <br/>
        <input class="btn btn-small" type="submit" value="Change password" />
    </fieldset>

The Error i am getting: The model item passed into the dictionary is of type 'Project.Models.LocalPasswordModel', but this dictionary requires a model item of type 'Project.Models.ProfileModel'.

BB987
  • 181
  • 3
  • 14
  • Where are you passing your profile model? – ssilas777 Feb 13 '13 at 18:21
  • @ssilas777 on the main view page – BB987 Feb 13 '13 at 18:32
  • But from your controller you are passing nothing - View(); you should populate your profile model and pass it like view(model). All other partial views are using Renderaction, so wont get error but in @Html.Partial it requires the model. Hop it makes sense – ssilas777 Feb 13 '13 at 18:39
  • @ssilas777 so do you min that in my `...Profile(ManageMessageId? message)` I should include `var model = new ProfileModel();` and then in the return: `return View(model)` ? – BB987 Feb 13 '13 at 18:46
  • Yes, also you should populate model.LocalPasswordModel model since we are going to use this in our view. or else you can consider changing the @Html.Partial to Html.RenderAction as you done for other views. – ssilas777 Feb 13 '13 at 18:49

1 Answers1

0

Try specifying model in @Html.Partial method. (Excuse my syntax, I dont have an IDE now)

        @if (ViewBag.HasLocalPassword)
        {
            @Html.Partial("_ChangePasswordPartial",Model.LocalPasswordModel)
        }
        else
        { 
            @Html.Partial("_SetPasswordPartial",Model.LocalPasswordModel)
        }

(I guess second view also use same model) But I couldn't see any model passed into your view from your controller, You should pass an model to view

public ActionResult Profile(ManageMessageId? message)
    {
        ViewBag.StatusMessage =
            message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
            : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
            : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
            : "";
        ViewBag.HasLocalPassword = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
        ViewBag.ReturnUrl = Url.Action("Profile");

        var ProfileModel = new ProfileModel();
        ProfileModel.LocalPasswordModel = populateFromDB();
        return View(ProfileModel);
    }

or consider creating an action result to Render this partial view as you have done for other partial views like this.(If there are no other intentions using Html.partial here)

           @if (ViewBag.HasLocalPassword)
            {
                @Html.RenderAction("_ChangePasswordPartial")
            }
            else
            { 
                @Html.RenderAction("_SetPasswordPartial")
            }
ssilas777
  • 9,672
  • 4
  • 45
  • 68
  • When i tried this - i would get the error: `Object reference not set to an instance of an object.` when the page loads – BB987 Feb 13 '13 at 18:31
  • As in my previous comment you are not passing any model to your main view from your controller which is causing this error. – ssilas777 Feb 13 '13 at 18:41
  • As i made these changes the model names in my error message are still the same but flipped. – BB987 Feb 13 '13 at 19:01
  • In this what change have you made, and here you have 2 @Html.Partial methods. make sure you are passing exact model to these views. – ssilas777 Feb 13 '13 at 19:04
  • I'm sorry but i think i just confused myself more i am getting the same two errors. – BB987 Feb 13 '13 at 19:27
  • In the main view (first snip of code i have) when i change `@model Project.Models.LocalPasswordModel` the page works fine. but when i have `@model Project.Models.ProfileModel` and have `LocalPasswordModel` passed in it doesn't like it. – BB987 Feb 13 '13 at 19:31