Pages Framework

Pages Framework Home page

Page Elements Overview | The Owin Framework Pages


In the Pages Framework you build your web application by defining elements. These elements are of specific types that fit into the overall design of the Pages Framework. This page briefly describes each type of element and provides a link to a page that provides more detail.

The Fluent Builder is the entry point for building elements, it is used by the template parsers, CMS and other high level pieces that help to define your web application.

The fluent builder has a plug-in architecture allowing specific build engines to be selected for each type of element. This documentation describes the build engines that come with the Pages Framework itself. If you configure a third party build engine for a specifc element type, then you should refer to the third party documentation instead.

You can also write a build engine as part of your application if you want to change how elements are built, but still want to use the template languages or CMS features of the Pages Framework.

Page Elements

These elements are the html pages of your website. Each page element can be dynamic and parameterized resulting in what appears to be many pages to a visitor to your website. If you look at the source code for this website you will see it contains very few Page Elements even though this website contains many pages of content.

Every Page Element must specify a Layout Element that defines the arangement of content on the page. Several pages can share the same layout but populate the regions of the layout differently.

Layout Elements

These elements define a fixed arrangement of regions that can have content placed in them. Each region of the layout must be named so that the contents of each region can be defined for the various places where the layout is used.

Note that the regions of a layout contain Region Elements but the name of the regions within the layout do not have to match the name of the Region Element within it, and typically it is more readable if these names are different, for example:
    [IsLayout("two_column", "left,right")]
    [ZoneRegion("left", "fixed_left_region")]
    [ZoneRegion("right", "flexible_right_region")]
    [RegionHtml("left", null, "Left column content")]
    [RegionHtml("right", null, "Right column content")]
    internal class TwoColumnLayout { }

The layout itself can also be named, and this name can be used to specify which layout to use (for example on a specific page). Elements with name references can be defined in any order - all of the name references are resolved after all of the elements are loaded.

Each region of the layout can contain one Region Element that defines how this region of the layout behaves (alignment, wrapping, resizing etc). The CSS and Javascript of the layout and the regions within it define how the layout is rendered and how it interacts with content and with the user.

Read more about Layout Elements here

Region Elements

These elements define the appearence and behavior of a rectangular area of your web pages. The same Region Element can be used in every place where the same visual appearence and interaction behaviour is needed.

Region Elements can be bound to a list of obejcts and will repeat the contents of the region for each object in the list. Region Elements can also define a data binding scope for everything inside the region.

Each region can contain one of the following:

Read more about Region Elements here

Component Elements

These elements render the majority of the html on the page. You would typically write these as classes that inherit from the Component base class and override virtual methods to output html.

Note that you do not have to use components, you can use one of the template parsing mechanisms instead. Template parsers construct components for you by parsing a template language. Many parsers support syntaxes for data binding and repeating.
Read more about Component Elements here

Package Elements

Packages define a namespace for browser assets, especially CSS classes and Javascript functions. You might want to break your own assets into namespaces if you have a very large and complex application, but this is not the reason why packages exist in this design.

Packages solve the problem of how to publish reusable libraries of plug-in functionallity and have these all integrate without stepping on each other's toes. The packaging system allows third party contributors to build a package that includes layouts, regions, components etc where these things have custom CSS and Javascript associated with them.

Each package has a default namespace that is prepended to CSS class names and is used to encapsulate Javascript functions. The application developer can override the namespace when integrating the package into their solution to ensure that package namespaces do not clash.

As well as creating a Package Element, you can also attach the [PartOf] attribute to add them to a package namespace.

It is recommended that you create an "app" package for your application but this is not required.

Read more about Package Elements here

Module Elements

Modules are a way of grouping browser assets that have the same deployment rules. Essentially the Pages Framework dynamically constructs one CSS and one Javascript resource for each page, for each module, and for the website as a whole. These are generated in memory and served to the browser by the AssetManager class. The HTML pages produced by the framework contain references to any of these assets that are required for the page to work.

When you create Elements such as Regions, Components and Pages, you can add a [DeployedAs] attribute to the class to specify how the assets for this element should be deployed. The default is to inherit from the parent element.

Read more about Module Elements here

Service Elements

Service elements have Http requests routed directly to them and are responsible for constructing the whole response. Services can also produce responses that are not Html, in fact the default format is JSON.

You should use services to handle AJAX calls and form POSTs from your website. You can also use service elements to provide APIs, especially in the case where you are writing a microservice.

This is very different from most other element types which are built into a tree structure of layouts inside regions inside layouts etc. with a page at the top. In the case of pages. the page renders all of the elements in the tree to produce the response.
Read more about Service Elements here

Data Provider Elements

The data provisioning model is very complex internally to make it as easy as possible for the developer. The design goals are based on these principals:

  • We want to modularize for reuse. This means that if I produce something that renders the presentation of an address I want to use the same code nomatter what kind of address it is or where it came from.
  • We want to have good separation of concerns, ie the presentation layer to know nothing about where the data came from and the data layer to know nothing about how the data is presented.
  • Pages need to be able to contain the same type of data multiple times from different sources. For example if I have presentation for a user profile, I might have a page that shows another user's profile and my own profile on the same page, and therefore these two instances of the same presentation need to connect with different instances of the profile data. In this framework this is referred to as "scope", and data scoping is handled by Region Elements.
  • The same data can appear in multiple places on a page, but we don't want to fetch it multiple times because this is inefficient.
  • There are many situations where a sub-tree of presentation elements need to be rendered once for each object in a list of objects in the body of the Html but rendred once only in other parts of the page.
These goals are realized by the following design:
  • The Data Provider Elements know how to retrieve specific kinds of data (optionally in specific scopes).
  • Any element can have one or more [NeedsData] attributes attached that specifies what data it needs. This includes the Data Provider elements.
  • The Region Elements can introduce a new scope for the sub-tree beneath the region.
  • The Region Elements can repeat their contents for each object in a list of objects.
  • Pages perform a one-time resolution of data needs, scopes and data providers. This produces a list of the data sources that need to be run for the page. For each page request the data sources are executed in the context of the request before any rendering takes place. This ensures that data is only retrieved once.
Read more about Data Provider Elements here