Table of Contents

DynamicWeb templates in Razor

Server-Side Rendering using Razor templates

By far the most common way to implement a DynamicWeb 10 solution is to use templates and have the DW10 rendering engine compile them to generate webpages. The templates are based on Razor, a markup language for embedding .NET code into webpages. Apart from that, the frontend stack can be anything you desire and you can use build tools, node, npm, bundlers, minifiers, etc.

To implement a DynamicWeb 10 solution using this method you need:

  • DynamicWeb solution installed locally
  • An IDE for template development that supports Razor, i.e. VS Code or Visual Studio
  • Experience with HTML, CSS, Javascript
  • Experience with Razor
  • Basic understanding of DynamicWeb and its concepts
  • Optional: knowledge of GIT, NPM, Bundlers, Sass, Typescript and other frontend technologies

Development environment

To setup a local development environment, you can follow our Install using Visual Studio or Install using VS Code guides and then the local frontend development section under each guide to get set up.

For more advanced setups see the Environments article.

Designs & Templates

All templates are physically store on disc and are organized in the Templates-folder of your solution. A collection of templates and static files which control how the frontend of a website looks is called a design. You can have multiple designs on a solution, each of them represented by a folder under Files/Templates/Designs:

/Files/
├── Templates/
│   ├── Designs/
│   │   ├── myDesign/
│   │   │   ├── Paragraph/
│   │   │   │   ├── image.cshtml
│   │   │   │   ├── text.cshtml
│   │   │   ├── Navigation/
│   │   │   │   ├── topNavigation.cshtml
│   │   │   │   ├── leftNavigation.cshtml
│   │   │   ├── myLayout1.cshtml
│   │   │   ├── myLayout2.cshtml
│   │   │   ├── myMaster.cshtml

If you're new to templates, designs and DynamicWeb we recommend that you check out our Designs and Templates tutorial, which will provide you with a good introduction to all the moving parts which constitute a design in DynamicWeb 10.

When DynamicWeb 10 serves a page, multiple templates which belong to different parts of the page are rendered individually and then combined. How many templates are combined like this depends on you content model - but typically:

  • A Master-template contains markup common to most pages - e.g. the <head>-section, references to static resources like JS and CSS, and usually also a navigation
  • A Page-template (or layout) contains the main markup, sections and columns of a particular page type – e.g. blogpost, shop or frontpage
  • A Paragraph-template controls how content - text, images, app output - from a paragraph type is organized
  • An App-template (or module template) controls how content from a paragraph app is shown, e.g. a product list or a login form

They typically fit together like this: template-hierarchy

When a page is requested for the first time, the various templates are parsed, merged into one, and saved to a _parsed-folder inside the design-folder. They are recompiled whenever we detect a change to them.

Razor

Razor is a markup syntax for embedding .NET based code into webpages. The Razor syntax consists of Razor markup, C#, and HTML. Files containing Razor generally have a .cshtml file extension.

Here is an example Razor template:

@inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@Model.Title</title>
  </head>
  <body>
    <h1>Welcome to the page '@Model.Name'</h1>
  </body>
</html>

In the example above, most of the code is markup - and a view model from DynamicWeb is injected and can be used for dynamic content. We call it to fetch the Name property of the PageViewModel, making the h1-content dynamic.

The result of the rendering would be this:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DynamicWeb - CMS, PIM and Ecommerce</title>
  </head>
  <body>
    <h1>Welcome to the page 'Home'</h1>
  </body>
</html>

ViewModels and TemplateTags

There are two ways to fetch dynamic content to a template:

  • ViewModels
  • TemplateTags

Of these, ViewModels is the recommended approach - they are type safe, perform better, and allow you to have IntelliSense/code prediction in your IDEs. TemplateTags is an older approach which is being phased out, but which is still in use in some template contexts.

A ViewModel-based template:

@inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Ecommerce.ProductCatalog.ProductListViewModel>

<h1>@Model.Group.Name</h1>

<ul>
@foreach (var product in Model.Products)
{
    <li>@product.Name (@product.Price.PriceWithVatFormatted)</li>
}
</ul>

A tag-based template:

@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>

<h1>@GetString("Ecom:ProductList:Page.GroupName")</h1>

<ul>
@foreach (LoopItem product in GetLoop("Products"))
{
    <li>@product.GetString("Ecom:Product.Name") (@product.GetString("Ecom:Product.Price.PriceWithVATFormatted"))</li>
}
</ul>

Extensibility

By default, ViewModels contain all the properties which we regard as necessary to do whatever you need to do in each template. If you need to add custom properties to a ViewModel, please see Extending ViewModels.

Please note, however, that you risk making the ViewModel perform at an unacceptable level. To avoid this, keep these guidelines in mind:

  • Be careful not to add 'business logic' in the template, e.g. price calculations and the like. Use other extensibility points for that, e.g. custom providers
  • Creating extension methods for code only used once compiles the code away so it is harder to update and harder to understand how the template work.
  • Templates are rendered and the code in them executed many times - too many API-calls or too much C#-code can cause performance issues if you're not careful

Read more about extensibility here.

To top