Currently I am evaluating Orchard (http://www.orchardproject.net/) for few of my project needs. In this blog, I will document some of my notes.
Orchard is -
Orchard is -
- a project based on ASP.NET MVC framework that provides reusable components to bring different modules together.
- can also be used as a Content Management System
- provides 3 recipes
- Recipes are pre-configured options, settings and features
- default recipe
- core recipe - core orchard framework with most of the CMS options turned off
- blog recipe - for publishing blogs. It has all the basic features of blogging like tagging, comments, spam filters, rss feeds, remote publishing, users, roles and permissions
- Themes
- Defines layout(*.cshtml) and styles(*.css). They can also contain scripts folders.
- Styles defined in themes have higher priority over styles defined in modules
- At any time only one theme is current but others can be active. This means that the active ones priority can be increased in case of certain requests to be used in place of the current theme. For ex, if request starts with admin, admin theme is given higher priority over current theme. The code that does that is called Theme Selector.
- A theme can have a base theme.
- Orchard will first look into the current theme then the base theme (if it exists) and finally the module.
- We can set a base theme by adding BaseTheme with the theme name in Theme.txt.
- Each theme has a Theme.txt file which is the metadata about the theme.
- Theme contains a bunch of views inside the Views folder. Similar to MVC, it contains a Layout.cshtml that defines the structure of the page. Most of the containers (divs) on the page are inside c# code blocks. The code blocks are usually if statements checking whether a container needs to be displayed or not. This layout files only determines the content for the body tags. The head tags are defined in another file called document.cshtml.
- Styles (css files) can be included using Style.Include()
- Javascript files can be included by using -
- Script.Require(name) - in this case we provide a name. This name is registered inside a manifest. For ex, jquery is registered inside Orchard.jQuery's ResourceManifest file. This file defines the actual jquery file associated with this name.
- Script.Include(filename) - The system will look for the file in Scripts folder inside the Theme. web.config will need to be copied over from Styles folder to scripts folder since this web.config tells the system that content in this folder is static and can be served as files. Scripts are added just before the end body tag. We can control where the script tags appear by calling AtHead() or AtFoot() after the calls to Script.Include() or Script.Require().
- Orchard's blog recipe security model
- every user has a role
- a role is a collection of permissions
- permissions are only allowed not denied
- permissions have dependencies. Having one permission might mean enabling other permissions as well.
- So to deal with this, we can have each permission to have Allowed and Effective flag. Allowed is true means someone specifically gave rights for this permission. So if allowed is true, effective is true by default. Effective however can also be true due to some other permission being true in order to deal with dependencies.
- Widgets
- Special type of content types.
- Widgets can be of many types. Few examples are Container widget, HTML widget, Menu widget, Projection Widget
- Zones
- Defines where the widget needs to be displayed
- Zones are defined in Layout.cshtml and Theme.txt. If we remove a zone from Theme.txt, we will not see it on dashboard. However, its still in Layout.cshtml so any widget associated with it will still be visible.
- Example of zones are Header, Navigation, Content, AsideFirst, AsideSecond
- Layers
- Defines when the widget will be displayed
- Each layer can be on or off at any given time. If on, widget will be visible.
- The on or off is governed by Layer Rule which can be configured.
- In default recipe we usually have 5 layers in default, authenticated, anonymous, disabled and the homepage layer.
- Modules
- Orchard is made of Core framework and modules.
- Core framework is stored in the Core folder. Core modules are all part of one project with each module in a separate folder. Core project is pre-compiled so it only contains styles, views and manifest files. It doesnt contain code.
- Each module is an MVC area which can contain Manifest file (like Module.txt), Routes, Controllers, Actions, Views, Drivers, Handlers, Migrations. An orchard module is dynamically compiled not pre-compiled i.e you dont have to build. Ex. of modules are Pages, Blogs, jQuery etc
- Module's manifest file (Module.txt) consists of manifest information such as dependencies, name, version, antiforgery, category etc
- On the module dashboard, we can enable and disable modules.
- If the module exposes a widget for ex. the search module exposes a search widget, we can customize the widget settings from the widgets dashboard page and set zone and layers.
- Content
- Content Types
- Modules expose content types like Page, Blog Post, Widget, Menu, Layer, User, Site, Query etc
- Instance of a content type is called content item
- Content Type = Name + Content Part + Content Field
- Content Fields - fields are specific pieces of information for ex, text, datetime, boolean etc. Their job is to store and display values and they dont add any behavior. For ex, you can add a text or boolean field on all the page content types.
- Content Parts
- Reusable piece of information and behavior. For ex. Tags are parts that can be used on both posts and pages.
- Modules can expose Content Parts also.
- Only one of each part can exist on a content type.
- A Page content type can have a name (Blog), some fields (like text description etc) and some parts like Body, Stars, Tags, Title, Common etc.
- Shapes
- A rendered page is a bunch of different shapes grouped together.
- Shapes are dynamic object models that serve as a ViewModel for individual pieces of a rendered page. Built on c# dynamic type and utilize the clay library.
- Dynamic because they are composed at runtime.
- Shapes can contain child shapes.
- Shapes are matched to a corresponding templates (razor views).
- Shapes can exist without templates.
- Layout is a shape. To this shape, widgets (which are also shape) added dynamically to properties on the Layout shape where the zone name was matching.
- @Display method is used to render shapes into templates
- It declares zones for other shapes to render into
- When rendering a shape, orchard has to locate the correct template. Similar to earlier, orchard will first look in current theme, then in the base theme (if it exists) and then in the module (if module is publishing a shape).
- Model is a dynamic object so properties can be added on runtime and hence intellisense is also not available.
- The Layout shape (Layout.cshtml) defines few top level zones (Header, Footer, Content, Navigation etc). @Zone is basically calling @Display to render these shapes. These shapes can then internally have defined other shapes. If say Header is defined, a dynamic property is added to layout shape. If its not defined, nothing gets added. If Header is defined, we call the @Zone method to and pass the Model.Header to it so that it can get displayed. Header internally might call on to other widgets which will then call on for their respective shape rendering.
- Zones and widgets are also shapes.
- Placement.info
- Is an XML file which is used to define the placement of shapes. It can be placed inside Module or Themes. And just like everywhere else, Themes have the highest priority.
- It can consist of only 2 tags
- Place - this tells the location of shape and has the following format <Place ShapeName="ZoneName:Position"/>
- Match - provides scope. 3 Scope levels - ContentType, DisplayType, Path. For ex. if you have a line like <Place ShapeName="ZoneName:Position"/> inside <Match ContentType="Blog">, it means that place the shape shapename in zone ZoneName at position Position only if its inside a Blog content type.
- Designer tool to enable tracing of shapes is a must have tool.
- We can copy a template being used from one folder into our theme folder and can customize it to any which way we want.
- How to modify template - By using the tracing tool first figure out the template being used to display that particular piece of HTML. Once you know the template, you have 2 options. One is to directly modify the template and other is to copy the template in your themes folder and modify it.
- How to modify placement -
- Command
- Can access orchard command prompt by running Orchard.Web/bin/Orchard.exe
- Help - Typing 'help commands' will show all the commands available at that particular point
- Enabling features - 'feature enable <feature>' for ex. 'feature enable Orchard.CodeGeneration'
- Creating module - 'codegen module <modulename> /IncludeInSolution:true'
- Creating data migration - 'codegen datamigration Pluralsight.Movies'
- Migrations
- Provides an abstraction for managing database changes in code instead of SQL
- Allows for easy versioning of schema, data and orchard content metadata changes
- Latest version number is stored in Orchard_Framework_DataMigrationRecord table
- Migrations is a class that inherits from DataMigrationImpl
- Drivers
- Drivers make Content Parts available to Orchard
- For each part there is a driver which derives from ContentDriver<T> where T is the Content Part Type
- Drivers provide UI for edit and update of the content part
- Drivers also provides Shapes to be displayed on the UI
- When a content item is to be edited, the request comest to a controller. Lets say the request has to edit a TitlePart and a BodyPart. So the controller transfers this to TitlePartDriver and BodyPartDriver.
- Content Handlers
- Content Handlers are classes that derive from ContentHandler class
- provides extension points for lifecycle events of content items
- many lifecycle events - activated, creating/created, publishing/published, removing/removed etc
- handlers are registered when site starts or a module is enabled
- we can register events for any Content Item, Type or Part
- handlers also exposes ContentFilters collection. ContentFilters are similar to ActionFilters. The only difference is that ContentFilter applies to ContentItems instead of request.
- StorageFilter provides repository for ContentPartRecords
- ActivatingFilter programmatically attaches ContentParts to ContentTypes