Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RuntimeBinderException with dynamic anonymous objects in MVC

The code

I've got an MVC project with a partial page that looks somewhat like this:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<div class="tab-window <%= Model.TargetClass %> <%= Model.TargetTab == Model.SelectedTab ? "selected" : "" %>"
    data-window-url="/SomeUrl/Partial/<%= Model.TargetTab %>/"
    <%= Model.TargetTab == Model.SelectedTab ? "data-content-loaded=\"true\"" : "" %>>
    <% if (Model.TargetTab == Model.SelectedTab) {
           Html.RenderPartial(Model.TargetTab as string, Model.Model as object);
        } %>
</div>

What it does is open another partial (the one named in Model.TargetTab) with Model.Model if it's the currently visible tab, otherwise just renders an empty div (which is loaded with jQuery when needed).

It's called like this:

<% Html.RenderPartial("TabWindowContainer", new { TargetTab = "MyTabName", TargetClass = "my-tab-class", SelectedTab = Model.Tab, Model = Model }); %>

This used to work.

Then I changed the value that goes into the Model, and it stopped working. I changed it back, and it's still not working. To be clear, hg status currently doesn't show any of these files.

The exception

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'TargetClass'

When you try to open Model in the Quickwatch window you see it has all the properties setup with correct values

Quickwatch

But when you try to view any property, you get the same exception as before

Quickwatch with exception

Thinking about it, I realized that possibly, this shouldn't work at all; the object we're trying to access is from a different assembly so we wouldn't see its properties. But then, why did it use to work? I still have a running version where this works. What can I do to make it work again?

Update: It should work; the model is coming from another view in the same assembly, not from the controller.

like image 420
configurator Avatar asked May 02 '11 14:05

configurator


1 Answers

Your dynamic type can't find the properties within the anonymous type because the anonymous type's properties are internal (not public). Thus, your app throws an exception even thought the anonymous type's properties are plainly visible to the debugger. Reference.

Create an Expando extension method.

public static ExpandoObject ToExpando(this object anonymousObject)
            {
                IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(anonymousObject);
                IDictionary<string, object> expando = new ExpandoObject();
                foreach (var item in anonymousDictionary)
                    expando.Add(item);
                return (ExpandoObject)expando;
            }

Apply the extension as so.

<% Html.RenderPartial("TabWindowContainer", new { TargetTab = "MyTabName", TargetClass = "my-tab-class", SelectedTab = Model.Tab, Model = Model }.ToExpando()); %>

Hopefully, this will work and I didn't embarrass myself by misunderstanding the issue.

like image 123
Eric W. Avatar answered Oct 20 '22 12:10

Eric W.