Getting Started
An introduction to server-side rendering using Razor templates
DynamicWeb 10 is a web application with a database - you login to the application via your browser and create different kinds of content; pages, products, etc. You can then use different means to show that content to people - e.g. our delivery api - but by far the most common way to implement a DynamicWeb 10 solution is to use the DW10 rendering engine to compile a set of templates to generate html-pages and serve them as a website.
This section of the developer documentation will explore this implementation method - server-side rendering using the built-in rendering engine and Razor-based templates.
Setting up a developer environment
To implement a DynamicWeb 10 solution using the DW10 templates system you need:
- A DynamicWeb 10 solution installed locally
- An IDE for template development which supports Razor, e.g. VS Code or Visual Studio
- Experience with HTML, CSS, Javascript
- Experience with Razor
- A basic understanding of DynamicWeb and its concepts
Apart from that, the frontend stack can be anything you desire and you can use build tools, GIT, Node.js, NPM, bundlers, TypeScript, minifiers, etc.
To install a solution locally you can follow one of our guides...
...and then the local frontend development section under each guide to get set up.
For more advanced setups see the Environments article.
The template hierarchy
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:
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.
Using Razor in templates
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 ViewModel from DynamicWeb is injected and can be used to fetch content dynamically from the DynamicWeb 10 solution. In this example, we call it to fetch the Name property of the PageViewModel, making the h1-content dynamic - *@Model.Name* will be replaced with whatever the name of the page being shown to the visitor is called.
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>
Showing dynamic content
Building on the previous paragraph, there are two ways to fetch dynamic content to a template:
- ViewModels - type safe, perform better, allows you to have IntelliSense/code prediction in your IDE
- TemplateTags - older, being phased out, sometimes still used in some template contexts
ViewModel templates
A ViewModel-based template starts by inheriting a context-specific ViewModel - here a ProductListViewModel. You can then use the @Model-directive to access the properties of the ViewModel, making the template dynamic:
@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>
You can find all our ViewModels in the API reference - and many of them are also described and explained in the articles which form this part of the developer documentation.
TemplateTag templates
A tag-based template uses various loops and Get-methods to fetch content based on TemplateTags:
@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>
To see which TemplateTags are available you can use the @TemplateTags()
helper method somewhere in the template; it will render a table in frontend with a list of available tags, loops, and values for the context. You can read more about the TemplateTags-system on our old documentation site.
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