Tutorial 1: Core Concepts

Basically, Dynamicweb is a content management system (CMS) for building websites, which also contains native functionality for handling e-commerce, marketing efforts, and with a powerful and flexible framework for integration with external systems such as a Dynamics NAV or Dynamics AX solution.

Broadly speaking, Dynamicweb contains the following components:

  • A content management system for creating and managing content – websites, pages, paragraphs and a system for creating custom content types called items.
  • A set of marketing tools for doing email marketing, leads management, social media publishing, content personalization, etc.
  • An integrated Ecommerce system which lets you create and manage shops, products, orders, RMAs, quotes, discounts, integrate with payment and shipping providers, etc.
  • An integration framework which lets you import and export data to and from the solution, either on an ad-hoc basis, on a schedule, or in real-time when rendering e.g. a product price or a stock level

In addition, there’s a file manager, a user management system, and so on – all fully integrated, so you have access to e.g. browsing patterns and previous purchases when sending marketing emails to you users.

But enough about the features – you’re here to learn about extending the default features.

To be able to do that, you must understand the basic architecture and some of the core concepts fundamental to the system. In this tutorial, we will go over the following concepts:

  • The basic file structure of a solution
  • The application lifecycle and how it exposes notifications
  • The types of extension points available to you
  • The public API
  • How to access the database using the API

Before you started this course, you followed our guide to install a solution locally.

In the root folder of the solution, you will find core files such as Global.asax, Web.Config, and packages.config, as well as the Files, bin, and admin folders.

In ASP.NET, the bin folder of a website is a special folder for specific types of content - it is meant to contain compiled assemblies (.dll files) for custom ASP.NET controls, components, or other code that you want to reference in the application. So when you extend a solution with a custom provider or a notification subscriber, you simply copy the compiled assembly to the bin folder to make it available to the rest of the application.

The files folder contains the files and folders which you can also access from the file manager in the administration interface of the solution.

The Dynamicweb application has a lifecycle within the IIS. The headings for the overall lifecycle states are the following:

  1. Application_Start
  2. Application_BeginRequest
    • Ensure Dynamicweb is started
  3. Application_OnPreRequestHandlerExecute
  4. Application_EndRequest
  5. Application_Error
  6. Application_End

The naming is purposely similar to the ASP.NET Application Life Cycle Overview for IIS 7.0 . The formatting is present to illustrate when a state has a corresponding end-state.

You can read more in-depth information about the lifecycle states in the application lifecycle documentation, which is continually updated.

Of the above states, 1 to 4 are of particular interest, as they expose notifications which you can hook onto in your custom code. Notification are one of the two main extension types in Dynamicweb.

Most areas of Dynamicweb can be extended with custom functionality, so that you can do more things (or different things) than you could out of the box.

There are two main types of extension points in Dynamicweb:

  • You can create notification subscribers which hook onto system notifications, executing their code every time that notification fires.
  • You can create custom providers, which are used to deliver data or information to the system, e.g. prices, email recipients or simply data which should be imported to the solution.

Previous versions of Dynamicweb also made use of template extendersbut as they are used to extend html templates with C# functionality, they have been replaced by ASP.NET Razor templates, which are introduced in the next tutorial.

Notification Subscribers allow developers to perform custom actions whenever certain events occur. For instance, you may want to create a user account for customer when they create an order. If so, you can create a notification subscriber that listens to the Ecommerce.Order.AfterSave notification and creates the user when the order completes.

In other words, notification subscribers are a way for you to react to certain events raised by Dynamicweb. When the conditions for a notification are raised, Dynamicweb will iterate through all public classes in the AppDomain that inherit from the NotificationSubscriber base class and are decorated with a Subscribe attribute with the appropriate notification.

For each class found it will invoke the OnNotify method passing a NotificationArgs object to it. The NotificationArgs object is a container for other types that Dynamicweb want to provide when processing the NotificationSubscriber. For each notification there is a sibling NotificationArgs type, which you can cast the NotificationArgs object to and access specialized objects in the given context, i.e. access the Product instance in the BeforeRender notification.

For instance, if you want to take action every time a product is rendered, you just compile a public class that inherits from the NotificationSubscriber class, subscribe to the appropriate notifications and override the OnNotify method:

using Dynamicweb.Extensibility.Notifications; using Dynamicweb.Ecommerce.Products; [Subscribe(Dynamicweb.Ecommerce.Notifications.Ecommerce.Product.BeforeRender)] public class OrderCompleted : NotificationSubscriber { public override void OnNotify(string notification, NotificationArgs args) { Dynamicweb.Ecommerce.Notifications.Ecommerce.Product.BeforeRenderArgs myArgs = (Dynamicweb.Ecommerce.Notifications.Ecommerce.Product.BeforeRenderArgs)args; Product product = myArgs.Product; // Do something with product. } }

You can use the same class to hook up to multiple notifications by adding a Subscribe attribute for each notification separated by comma, but the associated NotificationArgs objects are unique to each notification and should be treated as such.

using Dynamicweb.Extensibility.Notifications; [Subscribe(Dynamicweb.Ecommerce.Notifications.Ecommerce.Order.AfterDelete), Subscribe(Dynamicweb.Ecommerce.Notifications.Ecommerce.Order.AfterSave)] public class EcomOrderAfterDeleteObserver1 : NotificationSubscriber { public override void OnNotify(string notification, NotificationArgs args) { if (notification == Dynamicweb.Ecommerce.Notifications.Ecommerce.Order.AfterDelete) { //If the order was deleted } else { //If the order was saved } } }

You can find the notifications you can subscribe to in the API documentation – which is introduced later in this tutorial.

Providers are a way of adding your own runtime objects to the normal processing in Dynamicweb and Dynamicweb Ecommerce. They are designed to either alter the processing logic or provide alternative data storage.

For instance, if the price of a specific product to a specific customer in a given context is the result of a complex calculation, and this calculation is already implemented in your business system, you might consider integrating Ecommerce with this and have the business system calculate prices for Ecommerce. So you can create a custom PriceProvider to replace the default price provider.

Different providers are available for different purposes; all providers inherit from a provider base class relative to the type of provider you want to create. So a price provider inherits from the PriceProvider base class, a navigation provider inherits from the NavigationProvider base class, and so on.

Different provider models have their own unique DNA, so they must be reviewed independently – here are some of the key provider types points in Dynamicweb:

  • A PriceProvider provides the system with an algorithm for retrieving a specific price for a product, which overrides the default price calculation logic
  • A Data Integration provider is used to move data to and from a Dynamicweb solution
  • A FeeProvider is used to manipulate the shipping fee of an order
  • A CheckoutHandler contains the business logic required to complete an order, e.g. communicates with an external payment provider
  • An EmailRecipientProvider provides recipients for an Email Marketing email, if you want to retrieve recipients from an outside source or based on non-default parameters
  • Etc.

During these tutorials, you will see an example of a custom PriceProvider, a custom data integration provider, and a custom sales discount provider – but there are many more provider types than we can comfortable cover in a single course, and we encourage you to explore the API to get the full picture.

Dynamicweb features an extensive public API, which is auto-generated every night and published to the documentation portal. Using the API docs, you can explore the fundamental classes and basic infrastructure of the Dynamicweb application.

For instance:

  1. The Dynamicweb.Content namespace contains the API for managing content in Dynamicweb, including websites, pages, paragraphs and items. Use the AreaService, PageService, ParagraphService and ItemService to do operations on data like adding, updating and deleting.
  2. The Dynamicweb.Frontend namespace contains the frontend runtime of Dynamicweb serving pages through the Dynamicweb.Frontend.PageView class. URL and Navigation handling is also handled in the namespace.
  3. The Dynamicweb.Notifications and Dynamicweb.Ecommerce.Notification namespaces contain a lot of the notifications and notification argument classes used in Dynamicweb assembly.
  4. The Dynamicweb.Data namespace contains types for accessing and managing data in the database. The CommandBuilder class is the recommended way of accessing the database.

And so on. During the course of these tutorials, you will get acquainted with select parts of the API, but we encourage you to explore the API documentation on your own as well.

The Dynamicweb database is a regular MS SQL Server database, so you can access it just like you would normally access a database. However, the Dynamicweb.Data namespace contains several convenient classes for interacting with the database.

Here’s a short introduction to some of them.

The Database class offers a range of static members that ease the process of interacting with the database. For instance, reading from the database is as easy as: 

var DR = Database.CreateDataReader("SELECT * FROM Page");

This returns a DataReader instance containing all records from the Page table.

If you want to do other DML (Data Manipulation Language) or DDL (Data Defintion Language) operations within the permission scope of the SQL user (db_datareader, db_datawriter, db_ddladmin) there is also a method for that: 

Database.ExecuteNonQuery("UPDATE Page SET PageMenuText = 'Home Page' WHERE PageID = 1");

The Database class also supports transactions, allowing developers perform roll back a series of operations in case of errors. 

var connection = Database.CreateConnection(); var transaction = connection.BeginTransaction(); ... transaction.Commit(); ... transaction.Rollback();

While the Database class can also update data, the DataManager class offers a slightly simpler interface: 

var dataManager = new DataManager(); var dataSet = dataManager.CreateDataSet("SELECT * FROM Page WHERE PageID = 1"); ... dataManager.Update(dataSet); dataSet.Dispose(); dataManager.Dispose();

A major advantage to using the Database and DataManager classes is that they incorporate logging, which means that you can inspect their performance metrics using the built-in debugging features.

CommandBuilder is a public class that helps us create SQL queries that aren’t vulnerable to SQL Injection attacks. It does this by parsing a (part of a) query text. It finds all the placeholders (the same type that string.Format uses) and turns them into parameters, which then turns the whole query into a parameterized query where all values are escaped properly.

Placeholders insert any number of values into a SQL-query fragment, using the same principle of format items like the String.Format-methods, even arrays:

var value = 1; var cb = CommandBuilder.Create("SELECT * FROM [Table] WHERE ( [Column] = {0} )", value);

You can combine multiple instances of the CommandBuilder class to create complex SQL-queries with multiple parameter values based on business logic.

To create simple SQL statements you can use the Create method: 

var pageId = 1; var cb = CommandBuilder.Create("SELECT * FROM [Page] " + "WHERE ( [Page].[PageId] = {0} )", pageId); using (var dataReader = Database.CreateDataReader(cb)) { while (dataReader.Read()) { // TODO: Add code here } }

To create large and/or complex SQL statement you can use a constructor:

var pageId = 1; var cb = new CommandBuilder(); cb.Add("SELECT * "); cb.Add("FROM [Page]"); cb.Add("WHERE ( [Page].[PageId] = {0} )", pageId); using (var dataReader = Database.CreateDataReader(cb)) { while (dataReader.Read()) { // TODO: Add code here } }

In this tutorial you’ve been introduced to:

  • The basic file structure of a solution
  • The application lifecycle, and where to read more
  • The API documentation, and some of the more interesting parts of the API
  • The database and some of the classes from the Dynamicweb.Data namespace which can be used to interact with it.

In the next tutorial we will cover the template hierarchy, the rendering process, and some of the basic tools for frontend development in Dynamicweb.