dav83
dav83

Reputation: 322

MVC Controller/View removing model attribute

I'm creating a small MVC application and am passing a User object from a controller to an ActionResult method in another controller. One of the attributes of the User object is a list of Property objects called Properties.

Here's the rub: when the User object is finally passed to the relevant View, it's list does not contain any properties.

Here's the setup:

User class:

public class User
{
   public int Id {get;set;}
   public List<Property> Properties {get;set;}
}

AccountController

public ActionResult LogOn(int userId, string cryptedHash)
{
   //code to logOn (this works, promise)

   User user = dbContext.getUser(userId);
   //debugging shows the user contains the list of properties at this point

   return RedirectToAction("UserHome", "Home", user);
}

HomeController

public ActionResult UserHome(User user)
{
    ViewBag.Messaage = "Hello, " + user.Forename + "!";
    return View(user);  //debugging shows that user.Properties is now empty(!)
}

UserHome.cshtml View

@model emAPI.Model_Objects.User

@{
    ViewBag.Title = "UserHome";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>UserHome</h2>
<div>
        @Model.Forename, these are your properties:
        <ul>
            @foreach (var property in @Model.Properties)
            {
                <li>property.Name</li>
            }
        </ul>
</div>

The view loads without any problem - @Model.Forename is fine, but as far as HomeController is concerned user.Properties was empty when it received it, although I know it wasn't when AccountController sent it.

Any help or advice anyone has to offer would be gratefully received.

Upvotes: 0

Views: 2376

Answers (2)

Darin Dimitrov
Darin Dimitrov

Reputation: 1038930

You cannot pass entire complex objects when redirecting. Only simple scalar arguments.

The standard way to achieve that is to authenticate the user by emitting a forms authentication cookie which will allow you to store the user id across all subsequent actions. Then if in a controller action you need user details such as forename or whatever you simply query your data store to retrieve the user from wherever it is stored using the id. Just take a look at the way the Account controller is implemented when you create a new ASP.NET MVC 3 application.

So:

public ActionResult LogOn(int userId, string cryptedHash)
{
   //code to logOn (this works, promise)

   User user = dbContext.getUser(userId);
   //debugging shows the user contains the list of properties at this point

   // if you have verified the credentials simply emit the forms
   // authentication cookie and redirect:
   FormsAuthentication.SetAuthCookie(userId.ToString(), false);

   return RedirectToAction("UserHome", "Home");
}

and in the target action simply fetch the user id from the User.Identity.Name property:

[Authorize]
public ActionResult UserHome(User user)
{ 
    string userId = User.Identity.Name;

    User user = dbContext.getUser(int.Parse(userId));

    ViewBag.Messaage = "Hello, " + user.Forename + "!";
    return View(user); 
}

Ah and please, don't use ViewBag. Use view models instead. If all that your view cares about is welcoming the user by displaying his forename simply build a view model containing the forename property and then pass this view model to the view. The view doesn't care about your User domain model and it shouldn't.

Upvotes: 1

Shyju
Shyju

Reputation: 218762

RedirectToAction method returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action. You should not think about passing a complex object in that to the next action method.

In this case, may be you can keep your user object in the Session variable and access it in the remaining places.

public ActionResult LogOn(int userId, string cryptedHash)
{   
   User user = dbContext.getUser(userId);
   if(user!=null)
   {
       Session["LoggedInUser"]=user;
       return RedirectToAction("UserHome", "Home");
   }    
}

public ActionResult UserHome()
{
    var loggedInUser= Session["LoggedInUser"] as User;
    if(loggedInUser!=null)
    {
       ViewBag.Messaage = "Hello, " + user.Forename + "!";
       return View(user); 
    }
    return("NotLoggedIn");
}

Upvotes: 0

Related Questions