question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`Dictionary<string, object>` or `dynamic` model is not supported by layout views

See original GitHub issue

Describe the bug

When the context parameter contains a model of type Dictionary<string, object> or dynamic, expressions in a layout view cannot be bound to it.

This seems to be because the way context is passed to layout views is by wrapping the output of the ‘main’ view and the original context into a DynamicViewModel. Unfortunately, DynamicViewModel only supports reflection member access.

This conflicts with the guidance in the documentation that, for the best performance, models should be dictionaries.

Expected behavior:

When the value of the context parameter of a view is a Dictionary<string, object> or a dynamic, I expect that expressions in the layout view are able to resolve values as they do in regular views.

In more detail: I expect that DynamicViewModel is capable of handling regular dictionaries and dynamic values, as well as POCOs.

Test to reproduce

[Fact]
public void CanUseDictionaryModelInLayout()
{
    var files = new FakeFileSystem()
                {
                    { "views\\layout.hbs", "Layout: {{property}}\r\n{{{body}}}" },
                    { "views\\someview.hbs", "{{!< layout}}\r\n\r\nBody: {{property}}" },
                };

    var handlebarsConfiguration = new HandlebarsConfiguration() { FileSystem = files };
    var handlebars = Handlebars.Create(handlebarsConfiguration);
    var render = handlebars.CompileView("views\\someview.hbs");
    var output = render(
        new Dictionary<string, object>
        {
            { "property", "Foo" },
        }
    );

    Assert.Equal("Layout: Foo\r\n\r\nBody: Foo", output);
    // actual value is "Layout: \r\n\r\nBody: Foo"
}

[Fact]
public void CanUseDynamicModelInLayout()
{
    var files = new FakeFileSystem()
                {
                    { "views\\layout.hbs", "Layout: {{property}}\r\n{{{body}}}" },
                    { "views\\someview.hbs", "{{!< layout}}\r\n\r\nBody: {{property}}" },
                };

    dynamic model = new MyDynamicModel();
    var handlebarsConfiguration = new HandlebarsConfiguration() { FileSystem = files };
    var handlebars = Handlebars.Create(handlebarsConfiguration);
    var render = handlebars.CompileView("views\\someview.hbs");
    var output = render(
        model
    );

    Assert.Equal("Layout: Foo\r\n\r\nBody: Foo", output);
    // actual value is "Layout: \r\n\r\nBody: Foo"
}

private class MyDynamicModel: DynamicObject
{
    private readonly Dictionary<string, object> _properties =
        new Dictionary<string, object>
        {
            { "property", "Foo" },
        };

    public override IEnumerable<string> GetDynamicMemberNames() => _properties.Keys;
    public override bool TryGetMember(GetMemberBinder binder, out object result) =>
        _properties.TryGetValue(binder.Name, out result);
}

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:9 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
heemskerkerikcommented, Mar 24, 2021

@zjklee I actually liked the idea of creating a new type, which can be much more focused and less flexible. Like this

internal class LayoutViewModel
{
  private readonly string _body;
  private readonly object _value;
}

In the member accessor we intercept the body property, and forward the rest to the ObjectDescriptor for _value, and we can do the same for GetProperties (where we amend body) and for Iterator which we just forward altogether.

Let me know what you think.

0reactions
oformaniukcommented, Mar 24, 2021

@heemskerkerik Yep, I like your suggestion and looking forward to see your PR 😉

Read more comments on GitHub >

github_iconTop Results From Across the Web

`Dictionary<string, object>` or `dynamic` model is not ...
Dictionary ` or `dynamic` model is not supported by layout views.
Read more >
Mapping of dynamic / Dictionary<string, object> to class ...
i want to map a Dictionary or ExpandoObject to a class. Problem is that the class has different Names which should be recognized...
Read more >
Custom Dictionary JsonConverter using System.Text.Json
How to customize the deserialization/serialization of Dictionary using System.Text.Json and a custom JsonConverter.
Read more >
Dynamically-rendered ASP.NET Core Razor components
Learn how to use dynamically-rendered Razor components in Blazor apps. ... Name { get; set; } public Dictionary<string, object> Parameters ...
Read more >
How to convert list<object> into dictionary<string, string>
What I have tried: i tried this but it's only working when in my list value are exsits only for index[0] if value...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found