0
votes

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'.

1
Where are you passing your profile model? - ssilas777
@ssilas777 on the main view page - BB987
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
@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
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

1 Answers

0
votes

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")
            }