Dynamic Anonymous type in Razor causes RuntimeBinderException

后端 未结 12 791
不思量自难忘°
不思量自难忘° 2020-11-22 07:45

I\'m getting the following error:

\'object\' does not contain a definition for \'RatingName\'

When you look at the anonymous dyn

相关标签:
12条回答
  • 2020-11-22 07:54

    Wrote a console application and add Mono.Cecil as reference (you can now add it from NuGet), then write the piece of code:

    static void Main(string[] args)
    {
        var asmFile = args[0];
        Console.WriteLine("Making anonymous types public for '{0}'.", asmFile);
    
        var asmDef = AssemblyDefinition.ReadAssembly(asmFile, new ReaderParameters
        {
            ReadSymbols = true
        });
    
        var anonymousTypes = asmDef.Modules
            .SelectMany(m => m.Types)
            .Where(t => t.Name.Contains("<>f__AnonymousType"));
    
        foreach (var type in anonymousTypes)
        {
            type.IsPublic = true;
        }
    
        asmDef.Write(asmFile, new WriterParameters
        {
            WriteSymbols = true
        });
    }
    

    The code above would get the assembly file from input args and use Mono.Cecil to change the accessibility from internal to public, and that would resolve the problem.

    We can run the program in the Post Build event of the website. I wrote a blog post about this in Chinese but I believe you can just read the code and snapshots. :)

    0 讨论(0)
  • 2020-11-22 07:55

    Anonymous types having internal properties is a poor .NET framework design decision, in my opinion.

    Here is a quick and nice extension to fix this problem i.e. by converting the anonymous object into an ExpandoObject right away.

    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;
    }
    

    It's very easy to use:

    return View("ViewName", someLinq.Select(new { x=1, y=2}.ToExpando());
    

    Of course in your view:

    @foreach (var item in Model) {
         <div>x = @item.x, y = @item.y</div>
    }
    
    0 讨论(0)
  • 2020-11-22 07:55

    You can use the framework impromptu interface to wrap an anonymous type in an interface.

    You'd just return an IEnumerable<IMadeUpInterface> and at the end of your Linq use .AllActLike<IMadeUpInterface>(); this works because it calls the anonymous property using the DLR with a context of the assembly that declared the anonymous type.

    0 讨论(0)
  • 2020-11-22 08:03

    Instead of creating a model from an anonymous type and then trying to convert the anonymous object to an ExpandoObject like this ...

    var model = new 
    {
        Profile = profile,
        Foo = foo
    };
    
    return View(model.ToExpando());  // not a framework method (see other answers)
    

    You can just create the ExpandoObject directly:

    dynamic model = new ExpandoObject();
    model.Profile = profile;
    model.Foo = foo;
    
    return View(model);
    

    Then in your view you set the model type as dynamic @model dynamic and you can access the properties directly :

    @Model.Profile.Name
    @Model.Foo
    

    I'd normally recommend strongly typed view models for most views, but sometimes this flexibility is handy.

    0 讨论(0)
  • 2020-11-22 08:04

    I'm going to do a little bit of stealing from https://stackoverflow.com/a/7478600/37055

    If you install-package dynamitey you can do this:

    return View(Build<ExpandoObject>.NewObject(RatingName: name, Comment: comment));
    

    And the peasants rejoice.

    0 讨论(0)
  • 2020-11-22 08:07

    I tried the ExpandoObject but it didn't work with a nested anonymous complex type like this:

    var model = new { value = 1, child = new { value = 2 } };
    

    So my solution was to return a JObject to View model:

    return View(JObject.FromObject(model));
    

    and convert to dynamic in .cshtml:

    @using Newtonsoft.Json.Linq;
    @model JObject
    
    @{
        dynamic model = (dynamic)Model;
    }
    <span>Value of child is: @model.child.value</span>
    
    0 讨论(0)
提交回复
热议问题