[{"data":1,"prerenderedAt":605},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Forchard-core-shapes":50,"\u002Fblog\u002Forchard-core-shapes-surround":600},[4],{"title":5,"path":6,"stem":7,"children":8,"page":49},"Blog","\u002Fblog","blog",[9,13,17,21,25,29,33,37,41,45],{"title":10,"path":11,"stem":12},"Data Catalog 3.0: Rise of the Active Metadata Platform","\u002Fblog\u002Fdata-catalog-3","blog\u002Fdata-catalog-3",{"title":14,"path":15,"stem":16},"dbt on Databricks: Data Transformation Pipelines","\u002Fblog\u002Fdbt-on-databricks","blog\u002Fdbt-on-databricks",{"title":18,"path":19,"stem":20},"Deploying Azure Resources with VS Code","\u002Fblog\u002Fdeploying-azure-resource-with-vs-code","blog\u002Fdeploying-azure-resource-with-vs-code",{"title":22,"path":23,"stem":24},"Dynamic Management Views (DMVs)","\u002Fblog\u002Fdynamic-management-views","blog\u002Fdynamic-management-views",{"title":26,"path":27,"stem":28},"General Delta Table Processing","\u002Fblog\u002Fgeneral-delta-table","blog\u002Fgeneral-delta-table",{"title":30,"path":31,"stem":32},"Microsoft Fabric as an All-in-One Analytics Solution","\u002Fblog\u002Fmicrosoft-fabric","blog\u002Fmicrosoft-fabric",{"title":34,"path":35,"stem":36},"Orchard Core Shapes: Demystifying the View Data Model","\u002Fblog\u002Forchard-core-shapes","blog\u002Forchard-core-shapes",{"title":38,"path":39,"stem":40},"Power BI DAX Masterclass","\u002Fblog\u002Fpower-bi-dax-masterclass","blog\u002Fpower-bi-dax-masterclass",{"title":42,"path":43,"stem":44},"Power BI Incremental Refresh","\u002Fblog\u002Fpower-bi-incremental-refresh","blog\u002Fpower-bi-incremental-refresh",{"title":46,"path":47,"stem":48},"Set Power BI Row-Level Security to SAP Cost Center","\u002Fblog\u002Fpower-bi-row-level-security","blog\u002Fpower-bi-row-level-security",false,{"id":51,"title":34,"author":52,"body":56,"date":593,"description":594,"extension":595,"image":596,"meta":597,"minRead":203,"navigation":181,"path":35,"seo":598,"stem":36,"__hash__":599},"blog\u002Fblog\u002Forchard-core-shapes.md",{"name":53,"avatar":54},"Radek Řezáč",{"src":55,"alt":53},"\u002Faboutme.png",{"type":57,"value":58,"toc":582},"minimark",[59,68,73,85,106,111,140,144,147,235,245,249,257,276,280,298,313,336,344,348,355,413,416,442,446,451,481,484,539,542,549,552,558,565,569,578],[60,61,62,63,67],"p",{},"Orchard Core doesn't render HTML directly. Instead, it renders ",[64,65,66],"strong",{},"Shapes"," — objects that represent what to render and carry all the data and metadata needed to produce HTML. Understanding shapes is fundamental to customising and theming Orchard Core applications.",[69,70,72],"h2",{"id":71},"what-is-a-shape","What Is a Shape?",[60,74,75,76,80,81,84],{},"A shape is an object implementing the ",[77,78,79],"code",{},"IShape"," interface. It is a ",[64,82,83],{},"dynamic data model"," containing:",[86,87,88,95],"ul",{},[89,90,91,94],"li",{},[64,92,93],{},"Data"," — values that will be rendered by ASP.NET views",[89,96,97,100,101,105],{},[64,98,99],{},"Metadata"," — instructions on ",[102,103,104],"em",{},"how"," to render (template name, alternates, placement, etc.)",[107,108,110],"h3",{"id":109},"benefits-of-the-shape-system","Benefits of the Shape System",[86,112,113,116,122,128,131,134,137],{},[89,114,115],{},"No view name is hard-coded — the view name is derived from the shape type",[89,117,118,121],{},[64,119,120],{},"Priority-based view resolution"," via Alternates (multiple templates can match the same shape, resolved in priority order)",[89,123,124,127],{},[64,125,126],{},"Theming"," — user-defined templates (views) override default ones without modifying core",[89,129,130],{},"Dynamic caching",[89,132,133],{},"Wrapping and placement (zones, ordering)",[89,135,136],{},"Multiple data sources (database, files, code)",[89,138,139],{},"Event-driven rendering pipeline",[69,141,143],{"id":142},"creating-and-rendering-shapes","Creating and Rendering Shapes",[60,145,146],{},"The basic flow for creating and rendering a shape programmatically:",[148,149,154],"pre",{"className":150,"code":151,"language":152,"meta":153,"style":153},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F 1. Create a shape by shape factory\nvar factory = context.RequestServices.GetRequiredService\u003CIShapeFactory>();\nvar shape = await factory.CreateAsync(\"Car\");\n\n\u002F\u002F 2. Render to HTML via display helper\nvar displayHelper = context.RequestServices.GetRequiredService\u003CIDisplayHelper>();\nvar htmlContent = await displayHelper.ShapeExecuteAsync(shape);\n\n\u002F\u002F 3. Create a view matching the shape name: Car.cshtml\n\n\u002F\u002F 4. Write HTML to response\nawait using var sw = new StreamWriter(context.Response.Body);\nhtmlContent.WriteTo(sw, HtmlEncoder.Default);\n","csharp","",[77,155,156,164,170,176,183,189,195,201,206,212,217,223,229],{"__ignoreMap":153},[157,158,161],"span",{"class":159,"line":160},"line",1,[157,162,163],{},"\u002F\u002F 1. Create a shape by shape factory\n",[157,165,167],{"class":159,"line":166},2,[157,168,169],{},"var factory = context.RequestServices.GetRequiredService\u003CIShapeFactory>();\n",[157,171,173],{"class":159,"line":172},3,[157,174,175],{},"var shape = await factory.CreateAsync(\"Car\");\n",[157,177,179],{"class":159,"line":178},4,[157,180,182],{"emptyLinePlaceholder":181},true,"\n",[157,184,186],{"class":159,"line":185},5,[157,187,188],{},"\u002F\u002F 2. Render to HTML via display helper\n",[157,190,192],{"class":159,"line":191},6,[157,193,194],{},"var displayHelper = context.RequestServices.GetRequiredService\u003CIDisplayHelper>();\n",[157,196,198],{"class":159,"line":197},7,[157,199,200],{},"var htmlContent = await displayHelper.ShapeExecuteAsync(shape);\n",[157,202,204],{"class":159,"line":203},8,[157,205,182],{"emptyLinePlaceholder":181},[157,207,209],{"class":159,"line":208},9,[157,210,211],{},"\u002F\u002F 3. Create a view matching the shape name: Car.cshtml\n",[157,213,215],{"class":159,"line":214},10,[157,216,182],{"emptyLinePlaceholder":181},[157,218,220],{"class":159,"line":219},11,[157,221,222],{},"\u002F\u002F 4. Write HTML to response\n",[157,224,226],{"class":159,"line":225},12,[157,227,228],{},"await using var sw = new StreamWriter(context.Response.Body);\n",[157,230,232],{"class":159,"line":231},13,[157,233,234],{},"htmlContent.WriteTo(sw, HtmlEncoder.Default);\n",[60,236,237,238],{},"Code for this pattern is available on GitHub: ",[239,240,244],"a",{"href":241,"rel":242},"https:\u002F\u002Fgithub.com\u002Fradekrezac\u002FDemystifyingShapes\u002Ftree\u002FTest_Shape_With_Razor_View",[243],"nofollow","Test_Shape_With_Razor_View",[69,246,248],{"id":247},"rendering-shapes-with-liquid-templates","Rendering Shapes with Liquid Templates",[60,250,251,256],{},[239,252,255],{"href":253,"rel":254},"https:\u002F\u002Fshopify.github.io\u002Fliquid\u002F",[243],"Liquid"," is a secure, flexible templating language ideal for dynamic content generation in Orchard Core.",[60,258,259,260,263,264,267,268,271,272,275],{},"To use Liquid templates instead of Razor views, add the ",[77,261,262],{},"OrchardCore.DisplayManagement.Liquid"," package and register ",[77,265,266],{},"AddLiquidViews()"," in ",[77,269,270],{},"Program.cs",". Orchard Core will resolve a ",[77,273,274],{},"Car.liquid"," template for a shape of type \"Car\".",[69,277,279],{"id":278},"adding-data-to-shapes","Adding Data to Shapes",[60,281,282,283,285,286,289,290,293,294,297],{},"The ",[77,284,79],{}," interface exposes a ",[77,287,288],{},"Properties"," dictionary (",[77,291,292],{},"IDictionary",") where you store data accessible in templates via the ",[77,295,296],{},"Model"," object:",[148,299,301],{"className":150,"code":300,"language":152,"meta":153,"style":153},"shape.Properties[\"Brand\"] = \"Renault\";\nshape.Properties[\"Color\"] = \"Red\";\n",[77,302,303,308],{"__ignoreMap":153},[157,304,305],{"class":159,"line":160},[157,306,307],{},"shape.Properties[\"Brand\"] = \"Renault\";\n",[157,309,310],{"class":159,"line":166},[157,311,312],{},"shape.Properties[\"Color\"] = \"Red\";\n",[60,314,315,316,319,320,323,324,327,328,331,332,335],{},"In the template, data is accessed as ",[77,317,318],{},"Model.Brand"," (not ",[77,321,322],{},"Model.Properties[\"Brand\"]",") because the ",[77,325,326],{},"DynamicObject","-based ",[77,329,330],{},"Compose"," class implements ",[77,333,334],{},"TryGetMember",", enabling direct property access.",[60,337,338,339],{},"Code: ",[239,340,343],{"href":341,"rel":342},"https:\u002F\u002Fgithub.com\u002Fradekrezac\u002FDemystifyingShapes\u002Ftree\u002FTest_ShapeData_With_Liquid_Template",[243],"Test_ShapeData_With_Liquid_Template",[69,345,347],{"id":346},"strongly-typed-shapes","Strongly Typed Shapes",[60,349,350,351,354],{},"For better performance and IDE support, use the generic ",[77,352,353],{},"CreateAsync\u003CT>"," overload to bind a POCO class to the shape:",[148,356,358],{"className":150,"code":357,"language":152,"meta":153,"style":153},"public class Car\n{\n    public string? Brand { get; set; }\n    public string? Color { get; set; }\n}\n\nvar shape = await factory.CreateAsync\u003CCar>(\"Car\", c =>\n{\n    c.Brand = \"Renault\";\n    c.Color = \"Red\";\n});\n",[77,359,360,365,370,375,380,385,389,394,398,403,408],{"__ignoreMap":153},[157,361,362],{"class":159,"line":160},[157,363,364],{},"public class Car\n",[157,366,367],{"class":159,"line":166},[157,368,369],{},"{\n",[157,371,372],{"class":159,"line":172},[157,373,374],{},"    public string? Brand { get; set; }\n",[157,376,377],{"class":159,"line":178},[157,378,379],{},"    public string? Color { get; set; }\n",[157,381,382],{"class":159,"line":185},[157,383,384],{},"}\n",[157,386,387],{"class":159,"line":191},[157,388,182],{"emptyLinePlaceholder":181},[157,390,391],{"class":159,"line":197},[157,392,393],{},"var shape = await factory.CreateAsync\u003CCar>(\"Car\", c =>\n",[157,395,396],{"class":159,"line":203},[157,397,369],{},[157,399,400],{"class":159,"line":208},[157,401,402],{},"    c.Brand = \"Renault\";\n",[157,404,405],{"class":159,"line":214},[157,406,407],{},"    c.Color = \"Red\";\n",[157,409,410],{"class":159,"line":219},[157,411,412],{},"});\n",[60,414,415],{},"In the view, type the model directly:",[148,417,421],{"className":418,"code":419,"language":420,"meta":153,"style":153},"language-razor shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","@using OrchardCore.DisplayManagement;\n@model Car\n\nThis is a car @Model.Brand with @Model.Color color\n","razor",[77,422,423,428,433,437],{"__ignoreMap":153},[157,424,425],{"class":159,"line":160},[157,426,427],{},"@using OrchardCore.DisplayManagement;\n",[157,429,430],{"class":159,"line":166},[157,431,432],{},"@model Car\n",[157,434,435],{"class":159,"line":172},[157,436,182],{"emptyLinePlaceholder":181},[157,438,439],{"class":159,"line":178},[157,440,441],{},"This is a car @Model.Brand with @Model.Color color\n",[69,443,445],{"id":444},"adding-metadata-to-shapes","Adding Metadata to Shapes",[60,447,448,450],{},[77,449,79],{}," metadata controls how the shape is wrapped in HTML. Key properties:",[148,452,454],{"className":150,"code":453,"language":152,"meta":153,"style":153},"shape.Id = \"my-renault\";\nshape.TagName = \"h3\";\nshape.Classes.Add(\"car\");\nshape.Classes.Add(\"brand-renault\");\nshape.Attributes.Add(\"data-brand\", \"renault\");\n",[77,455,456,461,466,471,476],{"__ignoreMap":153},[157,457,458],{"class":159,"line":160},[157,459,460],{},"shape.Id = \"my-renault\";\n",[157,462,463],{"class":159,"line":166},[157,464,465],{},"shape.TagName = \"h3\";\n",[157,467,468],{"class":159,"line":172},[157,469,470],{},"shape.Classes.Add(\"car\");\n",[157,472,473],{"class":159,"line":178},[157,474,475],{},"shape.Classes.Add(\"brand-renault\");\n",[157,477,478],{"class":159,"line":185},[157,479,480],{},"shape.Attributes.Add(\"data-brand\", \"renault\");\n",[60,482,483],{},"Render the metadata in a Razor template using the tag builder helper:",[148,485,487],{"className":418,"code":486,"language":420,"meta":153,"style":153},"@using OrchardCore.DisplayManagement;\n@model Car\n\n@{\n    var shape = Model as IShape;\n    var tagBuilder = shape.GetTagBuilder();\n}\n\n@tagBuilder.RenderStartTag()\nThis is a car @Model.Brand with @Model.Color\n@tagBuilder.RenderEndTag()\n",[77,488,489,493,497,501,506,511,516,520,524,529,534],{"__ignoreMap":153},[157,490,491],{"class":159,"line":160},[157,492,427],{},[157,494,495],{"class":159,"line":166},[157,496,432],{},[157,498,499],{"class":159,"line":172},[157,500,182],{"emptyLinePlaceholder":181},[157,502,503],{"class":159,"line":178},[157,504,505],{},"@{\n",[157,507,508],{"class":159,"line":185},[157,509,510],{},"    var shape = Model as IShape;\n",[157,512,513],{"class":159,"line":191},[157,514,515],{},"    var tagBuilder = shape.GetTagBuilder();\n",[157,517,518],{"class":159,"line":197},[157,519,384],{},[157,521,522],{"class":159,"line":203},[157,523,182],{"emptyLinePlaceholder":181},[157,525,526],{"class":159,"line":208},[157,527,528],{},"@tagBuilder.RenderStartTag()\n",[157,530,531],{"class":159,"line":214},[157,532,533],{},"This is a car @Model.Brand with @Model.Color\n",[157,535,536],{"class":159,"line":219},[157,537,538],{},"@tagBuilder.RenderEndTag()\n",[60,540,541],{},"The resulting HTML:",[60,543,544],{},[545,546],"img",{"alt":547,"src":548},"Rendered car shape","https:\u002F\u002Fradekrezac.dotnest.net\u002Fmedia\u002FOC\u002Frendered-car.jpg",[60,550,551],{},"The HTML source shows the metadata-driven output:",[60,553,554],{},[545,555],{"alt":556,"src":557},"Rendered car source","https:\u002F\u002Fradekrezac.dotnest.net\u002Fmedia\u002FOC\u002Frendered-car-source.jpg",[60,559,338,560],{},[239,561,564],{"href":562,"rel":563},"https:\u002F\u002Fgithub.com\u002Fradekrezac\u002FDemystifyingShapes\u002Ftree\u002FTest_Shape_With_Metadata",[243],"Test_Shape_With_Metadata",[69,566,568],{"id":567},"references","References",[86,570,571],{},[89,572,573],{},[239,574,577],{"href":575,"rel":576},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=yaZhKuD2qoI&list=PLpCsCyd254FpDNAMH_Pat0YADI2jMWTTT&index=6",[243],"Orchard Harvest 2024: Demystifying Shapes, Part 1",[579,580,581],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":153,"searchDepth":166,"depth":166,"links":583},[584,587,588,589,590,591,592],{"id":71,"depth":166,"text":72,"children":585},[586],{"id":109,"depth":172,"text":110},{"id":142,"depth":166,"text":143},{"id":247,"depth":166,"text":248},{"id":278,"depth":166,"text":279},{"id":346,"depth":166,"text":347},{"id":444,"depth":166,"text":445},{"id":567,"depth":166,"text":568},"2025-09-09","How Orchard Core Shapes work as a dynamic view data model — creating, rendering, and extending shapes with data, metadata, Liquid templates, and strongly typed models.","md","\u002Fblog\u002Forchard-shapes.png",{},{"title":34,"description":594},"1897QUuFy2HpRjdgIGXvgkPjsEPI2cCUYpcQC-xKbBQ",[601,603],{"title":30,"path":31,"stem":32,"description":602,"children":-1},"A deep dive into Microsoft Fabric — OneLake, Workspaces, Lakehouse, Warehouse, Apache Spark, and how it compares to Data Mesh and decentralised approaches.",{"title":38,"path":39,"stem":40,"description":604,"children":-1},"Best practices and key patterns for Power BI DAX: calculated columns vs. measures, date tables, iterator functions, CALCULATE, time intelligence, and more.",1782253168249]