Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Warren Buckley 2106 posts 4836 karma points MVP 7x admin c-trib
    May 31, 2013 @ 17:29
    Warren Buckley
    0

    Umbraco 6 MVC - CurrentUmbracoPage() & Model MisMatch

    Hello all,
    I am currently getting a YSOD when trying to use CurrentUmbracoPage() in my SurfaceController.

    The model item passed into the dictionary is of type 'Umbraco.Web.Models.RenderModel', but this dictionary requires a model item of type 'Site.Models.LoginViewModel'.

    I have provided the code of my views & ActionResult in the controller below.
    I would love to see what you think.

    Cheers,
    Warren

     

    Login Template - Login.cshtml

    @inherits Umbraco.Web.Mvc.UmbracoTemplatePage
    @{
        Layout = "Master.cshtml";
    }
    
    <div class="row">
        <div class="large-8 large-centered columns">
            <h1>Loginh1>
            @Html.Action("RenderLogin","AuthSurface")
        div>
    div>
    

    Login Action Result in SurfaceController

    /// 
    /// Handles the login form when user posts the form/attempts to login
    /// 
    /// "model">
    /// 
    [HttpPost]
    public ActionResult HandleLogin(LoginViewModel model)
    {
        if (!ModelState.IsValid)
        {
            //return RedirectToCurrentUmbracoPage();
            return PartialView("Login", model);
        }
    
        //Member already logged in - redirect to home
        if (Member.IsLoggedOn())
        {
            return new RedirectResult("/");
        }
    
        //Lets TRY to log the user in
        try
        {
            //Try and login the user...
            if (Membership.ValidateUser(model.EmailAddress, model.Password))
            {
                //Valid credentials
                        
                //Get the member from their email address
                var checkMember = Member.GetMemberFromEmail(model.EmailAddress);
    
                //Check the member exists
                if (checkMember != null)
                {
                    //Let's check they have verified their email address
                    if (Convert.ToBoolean(checkMember.getProperty("hasVerifiedEmail").Value))
                    {
                        //Update number of logins counter
                        int noLogins = 0;
                        if (int.TryParse(checkMember.getProperty("numberOfLogins").Value.ToString(), out noLogins))
                        {
                            //Managed to parse it to a number
                            //Don't need to do anything as we have default value of 0
                        }
    
                        //Update the counter
                        checkMember.getProperty("numberOfLogins").Value = noLogins + 1;
    
                        //Update label with last login date to now
                        checkMember.getProperty("lastLoggedIn").Value = DateTime.Now.ToString("dd/MM/yyyy @ HH:mm:ss");
    
                        //Update label with last logged in IP address & Host Name
                        string hostName         = Dns.GetHostName();
                        string clientIPAddress  = Dns.GetHostAddresses(hostName).GetValue(0).ToString();
    
                        checkMember.getProperty("hostNameOfLastLogin").Value    = hostName;
                        checkMember.getProperty("IPofLastLogin").Value          = clientIPAddress;
    
                        //Save the details
                        checkMember.Save();
    
                        //If they have verified then lets log them in
                        //Set Auth cookie
                        FormsAuthentication.SetAuthCookie(model.EmailAddress, true);
    
                        //Once logged in - redirect them back to the return URL
                        return new RedirectResult(model.ReturnUrl);
                    }
                    else
                    {
                        //User has not verified their email yet
                        ModelState.AddModelError("LoginForm.""Email account has not been verified");
                        return CurrentUmbracoPage();
                        //return PartialView("Login", model);
                    }
                }
            }
            else
            {
                ModelState.AddModelError("LoginForm.""Invalid details");
                return CurrentUmbracoPage();
                //return PartialView("Login", model);
            }
        }
        catch (Exception ex)
        {
            ModelState.AddModelError("LoginForm.""Error: " + ex.ToString());
            return CurrentUmbracoPage();
            //return PartialView("Login", model);
        }
    
        //Update success flag
        TempData["IsSuccessful"] = true;
        return RedirectToCurrentUmbracoPage();
    }

    Partial View - Login.cshtml

    @using Site.Controllers.SurfaceControllers
    @using Site.Models
    @model LoginViewModel @{     Html.EnableClientValidation(true);     Html.EnableUnobtrusiveJavaScript(true); } @if (!ViewData.ModelState.IsValid) {                  @foreach (ModelState modelState in ViewData.ModelState.Values)                 {                     var errors = modelState.Errors;                     if (errors.Any())                     {                          <ul>                             @foreach(ModelError error in errors)                             {                                 <li><em>@error.ErrorMessageem>li>                             }                         ul>                     }                 } } @using(Html.BeginUmbracoForm<AuthSurfaceController>("HandleLogin")) {     @Html.ValidationSummary(true)     <fieldset>         <legend>Loginlegend>          <div class="editor-label">             @Html.LabelFor(model => model.EmailAddress)         div>         <div class="editor-field">             @Html.EditorFor(model => model.EmailAddress)             @Html.ValidationMessageFor(model => model.EmailAddress)         div>                  <div class="editor-label">             @Html.LabelFor(model => model.Password)         div>         <div class="editor-field">             @Html.EditorFor(model => model.Password)             @Html.ValidationMessageFor(model => model.Password)         div>                  @Html.HiddenFor(Model => Model.ReturnUrl)         <p>             <input type="submit" value="Login" />         p>     fieldset> }
  • Shannon Deminick 1526 posts 5272 karma points MVP 3x
    Jun 01, 2013 @ 02:28
    Shannon Deminick
    0

    This error is not because of the code above, it is because of the  code you left out ;)

    This error is saying that you are trying to render a View that has a model of type "LoginViewModel" but you are passing it a model of type "RenderModel". The view that has this model is "Login.cshtml". The code that you are using to render this view is

    @Html.Action("RenderLogin","AuthSurface")

    So, what is the code for your RenderLogin action?

    Also I've noticed the numerous calls for returning a PartialView from your [HttpPost]. So many other people are attempting to do this because they are not actually understanding what is going on. I've posted a similar description of the whole process here (see answer)

    http://our.umbraco.org/forum/developers/api-questions/41357-return-CurrentUmbracoPage()-results-in-Error-loading-Partial-View-script

    I'll update the docs to make it clear what the sequence of events is during all of this rendering .

  • Shannon Deminick 1526 posts 5272 karma points MVP 3x
    Jun 01, 2013 @ 03:12
    Shannon Deminick
    0

    BTW, I've updated the docs here to explain the routing process:

    http://our.umbraco.org/documentation/Reference/Mvc/forms#UnderstandingtheRoutingProcess

    and added docs describing how to access the ViewData in child actions here:

    http://our.umbraco.org/documentation/Reference/Mvc/forms/turorial-child-action#AccessingViewData

  • Warren Buckley 2106 posts 4836 karma points MVP 7x admin c-trib
    Jun 01, 2013 @ 15:15
    Warren Buckley
    0

    Hey Shannon,
    Here is my code for my RenderLogin Action

    /// <summary>
    /// Renders the Login view
    /// </summary>
    /// <returns></returns>
    public ActionResult RenderLogin()
    {
        LoginViewModel loginModel = new LoginViewModel();
    
    
        if (string.IsNullOrEmpty(HttpContext.Request["ReturnUrl"]))
        {
            //If returnURL is empty then set it to /
            loginModel.ReturnUrl = "/";
        }
        else
        {
            loginModel.ReturnUrl = HttpContext.Request["ReturnUrl"];
        }
    
        return PartialView("Login", loginModel); 
    }

     

    Cheers,
    Warren

     

  • Shannon Deminick 1526 posts 5272 karma points MVP 3x
    Jun 03, 2013 @ 02:12
    Shannon Deminick
    103

    @Warren, $10 bucks says you have another .cshtml file called "Login.cshtml" in your ~/Views folder which is a non-partial Umbraco view ?

    If that is the case,the problem is because the MVC View Engines are looking in ~/Views for your partial view before it is looking in the place where you've stored your Login.cshtml partial view (most likely in ~/Views/Partials ? )

    You have a couple of options:

    • use a full virtual path to render your partial view: return PartialView("~/Views/Partials/Login.cshtml")
    • put your partial view inside a controller folder that matches the controller name you are rendering your view with. In this case, you are rendering this partial view using the AuthSurfaceController so you can put your partial view here: ~/Views/AuthSurface/Login.cshtml . Hopefully the view engines will look in controller specific folders first before the generic views or views/partials folder (they should, if not it is a bug)
    • rename your partial Login.cshtml file to something that doesn't overlap with a non-partial view in your views folder. Like: LoginPartial.cshtml

  • Warren Buckley 2106 posts 4836 karma points MVP 7x admin c-trib
    Jun 03, 2013 @ 12:35
    Warren Buckley
    0

    Hey Shan,
    Seems like your bang on the money!

    I have a Login.chstml for the main template in the /Views folder and then I have the Login.chstml view in the /Views/AuthSurface folder.
    I will try at lunchtime today to see if providing the full paths will resolve this issue, but I am sure it will.

    Cheers,
    Warren :) 

  • Justin Spradlin 139 posts 347 karma points
    Nov 16, 2013 @ 21:09
    Justin Spradlin
    0

    @Shannon - Thank you for the solution. I have spent about three hours this morning trying to figure out what I was doing wrong. I had a similar setup as Warren (using the CWS Membership bits as a guide). I am so glad I finally found this!

    Justin

  • Kyle 24 posts 63 karma points
    Nov 18, 2013 @ 20:29
    Kyle
    0

    @Shannon - Where do we send the $10 ! Spot on thank you.

    Kyle

  • Matt 76 posts 280 karma points
    Mar 18, 2014 @ 07:13
    Matt
    0

    Glad I found this thread - I just spent 2 hours trying to work out what was going on.

    Was this ever fixed? I'm using v6.2

    • put your partial view inside a controller folder that matches the controller name you are rendering your view with. In this case, you are rendering this partial view using the AuthSurfaceController so you can put your partial view here: ~/Views/AuthSurface/Login.cshtml . Hopefully the view engines will look in controller specific folders first before the generic views or views/partials folder (they should, if not it is a bug)
Please Sign in or register to post replies

Write your reply to:

Draft