Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic typed ViewPage

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.

like image 249
Matthew Groves Avatar asked Jul 24 '09 17:07

Matthew Groves


People also ask

What is the use of strongly typed views?

Strongly typed views are used for rendering specific types of model objects, instead of using the general ViewData structure. By specifying the type of data, you get access to IntelliSense for the model class.

What is the difference between strongly typed and weakly typed view in MVC?

In ASP.NET MVC, we can pass the data from the controller action method to a view in many different ways like ViewBag, ViewData, TempData and strongly typed model object. If we pass the data to a View using ViewBag, TempData, or ViewData, then that view becomes a loosely typed view.

What is a strongly typed model?

What is Strongly Typed View. The view which binds to a specific type of ViewModel is called as Strongly Typed View. By specifying the model, the Visual studio provides the intellisense and compile time checking of type. We learnt how to pass data from Controller to View in this tutorial.


2 Answers

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.

like image 86
Randolpho Avatar answered Oct 08 '22 00:10

Randolpho


What benefit were you hoping to get from using the dynamic type here?

Using the ViewData dictionary is a very easy way of adding arbitrary objects/items to your view output.

You don't need reflection to get the property names within your View. Just use ViewData.Keys to get the collection of names.

Edit: I've just learned a bit more about dynamics myself and I think maybe you need to create your own dynamic object class that inherits from DynamicObject. You'll want to have a private dictionary in that class and then override TrySetMember and TryGetMember.

Edit Aside: I think one advantage of a strongly typed ViewModel is that you can accept it as a parameter in your POST Action methods. The MVC framework will handle the model binding and in the action method you simply have an instance of your ViewModel class. I don't think you'll have that advantage with a dynamic even if they do work.

Edit Result: Well, I tried using a class derived from DynamicObject, but VS2010 crashes when it tries to render the view. I don't get any exception, just a hard crash and Visual Studio restarts. Here's the code I came up with that causes the crash.

The custom dynamic class:

public class DynViewModel : DynamicObject
{
    private Dictionary<string, object> ViewDataBag;
    public DynViewModel()
    {
        this.ViewDataBag = new Dictionary<string, object>();
    }
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        this.ViewDataBag[binder.Name] = value;
        return true;
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = this.ViewDataBag[binder.Name];
        return true;
    }
}

In the controller:

public ActionResult DynamicView()
{
    dynamic p = new DynamicViewModel.Models.DynViewModel();
    p.Name = "Test";
    p.Phone = "111-2222";

    return View(p);
}

My view is basically the same as what is listed in the question:

<p>Name: <%=Model.Name %></p>
<p>Phone: <%=Model.Phone %></p>

My Conclusion: This might work, but in the Beta 1 of VS2010 I can't figure out why my code causes Visual Studio to crash. I'll try it again in VS2010 Beta 2 when it is released because it is an interesting exercise in learning about dynamics. However, even if this were to work, I still don't see any advantage over using the ViewData dictionary.

Phil Haack to the rescue! Here's a blog post by Phil Haack that might help you out. It looks like it is what you were looking for. Fun With Method Missing and C# 4

like image 40
CoderDennis Avatar answered Oct 08 '22 01:10

CoderDennis