Dynamic typed ViewPage

Matthew Groves picture Matthew Groves · Jul 24, 2009 · Viewed 8.6k times · Source

Is this possible? Here's what I'm trying:

    public ActionResult Index()
    {
        dynamic p = new { Name = "Test", Phone = "111-2222" };
        return View(p);
    }

And then my view inherits from System.Web.Mvc.ViewPage<dynamic> and tries to print out Model.Name.

I'm getting an error: '<>f__AnonymousType1.Name' is inaccessible due to its protection level

So basically, is what I'm trying to do just not possible? Why or why not?

Update: here's my view

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

<asp:Content ...>
    <%=Model.Name%>
    <%=Model.Phone%>
</asp:Content>

The View constructor is built-in to the framework.

Answer

Randolpho picture Randolpho · Jul 24, 2009

Anonymous types cannot be returned by a method; they are only valid within the scope of the method in which they are defined.

You should use a Model class that you have previously defined and pass that to your View. There is nothing wrong with passing a Model class that does not have every field defined.

Update:

I think I was wrong before. This should work. Perhaps the problem is within the View. Can you post more code? Especially the View and its constructor.

Update the Second:

Ok, I was wrong about passing an anonymous type to another method for use as a dynamic variable -- that can be done.

But I was also wrong in my belief that what you're trying to do would work. Unfortunately for you, it will not. The problem is that you are using ViewPage<TModel>, which uses a ViewDataDictionary<TModel> internally. Because they require strong types, you won't be able to use dynamic objects with them. The internal structure just doesn't use dynamic internally, and specifying dynamic as the type fails.

What would be needed is a DynamicViewPage class and corresponding DynamicViewDataDictionary class that accept object and store it internally as a dynamic. Then you could use an anonymous type and pass it to your Views.

That said, you would not gain anything. You would be able to specify your Views as you have done (i.e. <%=Model.Name%>), but you would not benefit from strong typing. There would be no intellisense and there would be no type safety. You'd do just as well to use the untyped ViewDataDictionary as @Dennis Palmer suggests.

This has been an interesting (and, unfortunately for me, absorbing) thought experiment, but I think, ultimately, that it's not going to happen. Either declare a public type and pass it to your Views, or use the untyped dictionary.