views:

263

answers:

5

Given two assemblies:

project.web
project.lib

The project.web assembly references project.lib which contains some business logic. A simple class from project.lib:

public class Person
{
    public string Name;
}

In project.web.Controllers:

Using project.lib.models;

public class PersonController : Controller
{
    Person person = new Person();

    public ActionResult Index()
    {
        return View(person);
    }
}

This is the part where I have some questions. In a lot of sample projects I've seen the following in the View (in this case Index.aspx):

<% @Import Namespace="project.lib.models" %>

Allowing you to use the Model object like this:

<%= Model.Name %>

I haven't gotten that to work like the examples, I've had to do:

<%= (Model as Person).Name %>

or

<%
    var person = (Person)Model;
    Response.Write(person.Name);
%>

Why is this thus? What is the reason for this thusness? Comments? Suggestions? My class definition looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace project.lib.models
{
    public class Person
    {
        public Int64 PersonID;
        public string DisplayName;
        public string RealName;
    }
}
+1  A: 

Your view may not be strongly typed. Try the following:

  1. Copy the View markup
  2. Delete the View
  3. Go to the controller action that drives the View
  4. Right click within this method, select the Add View option.
  5. Ensure that this is a Strongly typed view and that you properly identify the type of your intended model.
  6. Paste your View markup into the newly created view.

This should work. It doesn't look like you're missing an assembly because you're able to cast the model correctly.

It should be noted that you can do the above without the pain of deleting/restoring a View. Each view has a declaration as its first line that is similar to the following:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<DomainModel.Person>" %>

The important section to understand is the Inherits attribute, which implies that this View extends the MVC ViewPage<DomainModel.Person> class. The Model property will be of type DomainModel.Person at runtime.

Also, there are issues with previous versions of ASP.NET MVC that effectively prevent strongly-typed views from working correctly. See http://stackoverflow.com/questions/492671/problem-using-add-view-dialog-in-asp-net-mvc-rc1-for-strongly-typed-view for more detail.

EDIT: After a bit of detective work by everyone who has posted here, it looks like Visual Studio was referencing older versions of the assembly containing the Person class. Closing the development environment down, clearing out all obj/bin folders, and restarting seems to have fixed this issue.

David Andres
I've tried this without success. I've recreated it, I've tried manually adding it. When I do that, Model doesn't even appear in the intelli-sense popup when I start typing.
Mr. Smith
Yeah sorry, I meant <project.lib.models.Person>.
Mr. Smith
@Mr. Smith: (1) Are you referencing the project.lib.models project within your UI project (2) what type is shown in the View declaration Inherits attribute?
David Andres
@Mr. Smith: You will get some information by trying to compile and navigate to this View during a debug session. I'm sure the exception that gets thrown when you do will shed some light on the issue.
David Andres
(1) Yes. (2) <project.lib.models.Person>.
Mr. Smith
I get Parser Error Message: Could not load type 'System.Web.Mvc.ViewPage<project.lib.models.Person>'.
Mr. Smith
Check that your type is public, and that the case of the namespace/class matches what you've put in your Inherits clause.
David Andres
It would be very helpful if you could post your Person class definition.
David Andres
Updated my question with class definition. The namespace/class matches exactly as far as I can tell.
Mr. Smith
Right click on your web project, and then on "Add Reference..." In the dialog that opens, select Projects and then your models project. See if that helps with intellisense and with page execution.
David Andres
Already done that, it wouldn't compile without it.
Mr. Smith
Try to make sure the System.Web.Mvc dll is in your GAC. If you're using the import line as you describe in the OP, you can change the Inherits clause to System.Web.Mvc.ViewPage<Person>.
David Andres
My guess is that this is a problem resolving the System.Web.Mvc.ViewPage class and not the projects.lib.model.Person class.
David Andres
It seems unlikely to me that would be an issue loading System.Web.Mvc.ViewPage as he said it works when he use the regular version of the page along with the cast <%= (Model as Person).Name %>.
eglasius
Freddy, I agree. However, this is just one of those scenarios where we can't quite look at the View markup or the code itself. I'm trying to rule out all possibilities. He can load type Person because he can cast to it, but the error message he receives when strongly-typing the view is that ViewPage<Person> is not a known type.
David Andres
@Mr Smith: I recommend you close Visual Studio, clean out ALL compiled assemblies from the bin and obj folders, reopen the solution and recompile.
David Andres
@David I agree with that line of thought. If there might be something wrong with the environment he is using, he also needs to clean the asp.net temporary files - you can receive really crazy errors when those aren't right.
eglasius
That fixed it David, thanks.
Mr. Smith
@Mr. Smith: Glad to hear it. I'm truly surprised that closing VS down worked.
David Andres
I imagine it was more the clearing out of old assemblies - using the "Clean" option in the Build menu might also have solved the issue.
Zhaph - Ben Duguid
@Zhaph: Clean is a solid approach, but I had concerns that the assemblies may have no longer been referenced (explicitly) but were still kept in memory. That's why I asked Mr. Smith to do the clean manually. Get rid of all assemblies, referenced or not. As far as I know, Clean retains assemblies that happen to be in bin/obj but are not referenced. Please correct me if I'm mistaken.
David Andres
+8  A: 

Could you please post your <%@ Page %> directive? It should be something like:

<%@ Page Language="C#"
         [...]
         Inherits="System.Web.Mvc.ViewPage<project.lib.models.Person>" %>

Have you tried creating a strongly typed code-behind file for this view instead?

You'd need to update the inherits property of the view to be the code-behind file:

<%@ Page Language="C#" 
    CodeBehind="Index.aspx.cs" Inherits="project.web.Views.People.Index" %>

and then in the code-behind:

namespace project.web.Views.People.Index {
  public partial class Index : System.Web.Mvc.ViewPage<project.lib.models.Person>
  {}
}

I don't think it's an issue with resolving the System.Web.Mvc.ViewPage class as then the page wouldn't load (you'd get an exception along the lines that System.Web.Mvc.ViewPage cannot be found), and you wouldn't even be able to access the Model property.

Zhaph - Ben Duguid
I'll let you know when I get home, I haven't tried this yet.
Mr. Smith
I tried this, it didn't make any difference. When I type, Model does not appear on the list of available options. I tried ViewData.Model too, but ViewData has no definition for Model either.
Mr. Smith
What does your page directive look like?
Zhaph - Ben Duguid
I don't know why your answer got so many upvotes, it didn't solve anything. As I said before, I tried this and it doesn't work. Thanks for the help anyway.
Mr. Smith
Presumably because in the context of the supplied information it was the best answer - it supplied more detail than the accepted answer, which has (fairly) been accepted because: 1) it said the same as mine, first, but in less detail and 2) a suggestion made in the comments solved your answer (it would help if you Upvoted the comment as well - it wasn't displaying for me last time I looked, and I couldn't work out why the accepted answer was).
Zhaph - Ben Duguid
A: 

What version of System.Web.MVC are you using?

RailRhoad
+1  A: 

Update 1: Note that you can be pretty certain that it isn't an issue loading/getting to the types System.Web.Mvc.ViewPage or project.lib.models.Person. As you mentioned in your question, it does work when you use:

<% @Import Namespace="project.lib.models" %>
...
<%= (Model as Person).Name %>

Using System.Web.Mvc.ViewPage<project.lib.models.Person> on the page directive and <%= Model.Name %> must work. Some extra things I would try if that doesn't work:

  • Remove the import directive when doing so.
  • Check if you have that namespace added on the web.config.

While none of those 2 above should cause any trouble, if you don't get it to work with what is mentioned before that, it would be a very weird scenario. Also note that if you did add commonly used namespaces in the web.config you can use ViewPage<Person> on the page directive.


The Model.Name you refer to doesn't have to do with importing the namespace, you get it from the type you set in the page directive.

The ViewPage class has the property T Model, which is why you get access to the Name property (you are working with the type you specified).

eglasius
A: 

to do that your view should be strongly typed to your model object in your case the Person class

all you need to make it work is adding refrence to the project.lib and adding updating the page derictive :

<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<Project.lib.Models.Person>" %>
Yassir