Wondering
Wondering

Reputation: 5086

How to handle ViewData type casting in MVC

I am new to MVC and facing one issue. I have a xml file and i am retrieving its value using Linq to xml and assigning it to ViewData. Controller.cs

           var res=from x in doc.Descendants("person")
                  select new 
                  {
                    Fname=x.Element("fname").Value,
                    Lname=x.Element("lname").Value

                  };
                   ViewData["Persons"]=res;

in View I am trying

         <% foreach (var item in ViewData["Persons"])   
                 { %>  


                   <li> <%= item.Fname %> </li>  


                 <% } %>  

but foreach (var item in ViewData["Persons"] is giving type casting error..what should be the exact type csting so that i can retrive values in the format item.Fname.

Thanks.

Upvotes: 1

Views: 20431

Answers (4)

yardpenalty.com
yardpenalty.com

Reputation: 1244

Personally I really can only think of one (but I am sure there a few more instances) reason to use view data is so that I can fetch some data on client without making callback to server. When you make an HTTP request you typically make a query against the database and render the results.

Very rarely do you need to hide/store some other data that you may or may not need based on the rendering to the point that you do not wish to callback the database for more data. Besides, things may have changed on the database making the stored data useless. Session state or unique user data would likely be stored in some other method but tbat might be a reason to use it.

Upvotes: 0

LukLed
LukLed

Reputation: 31862

Using ViewData, although possible, is not the most elegant way to pass information from controller to view. Using specific view model instead makes code easier and cleaner, and resolves casting issues.

Try defining model first:

public class ViewModelElement
{
    public string Fname { get; set; }
    public string LName { get; set; }
}


public class ViewModel
{
    public List<ViewModelElement> Elements { get; set; };
}

Then use your model in action:

public ActionResult ActionName()
{
  //get doc somehow
  var model = new ViewModel();

  //When querying by linq to xml, you can create ViewModelElement instead of anonymous class
  model.Elements = (from x in doc.Descendants("person")
      select new ViewModelElement
      {
        Fname=x.Element("fname").Value,
        Lname=x.Element("lname").Value
      }).ToList();

  return View(model);
}

Then use your model in view:

<% foreach (var item in model.Elements) { %>  
   <li> <%= item.Fname %> </li>  
<% } %> 

View has to inherit from System.Web.Mvc.ViewPage<ViewModel>.

Upvotes: 9

Robert Harvey
Robert Harvey

Reputation: 180868

The problem with your existing code is that you're projecting your data into an anonymous type with your Linq query, so there is no named type to cast to.

Assuming you had a named type (Person) to cast to (and you still wanted to use ViewData), your solution would be:

<% foreach (var item in (IEnumerable<Person>)ViewData["Persons"])

But inheriting your page from a strongly-typed ViewModel object is a better solution.

Upvotes: 1

thorkia
thorkia

Reputation: 2002

The default type in ViewData collection for a non-strongly typed view is object.

Your view is throwing an exception because it cannot automatically cast from object back to IEnumerable which LINQ queries return.

Change your loop to this and it should work fine:

  <% foreach (var item in (IEnumerable)ViewData["Persons"])   
                 { %>  


                   <li> <%= item.Fname %> </li>  


                 <% } %> 

By far the best advice is to strongly type your views so that you can do what LukLed suggested

Upvotes: 0

Related Questions