Docs.orchardproject.net How Orchard Works

download Docs.orchardproject.net How Orchard Works

of 8

Transcript of Docs.orchardproject.net How Orchard Works

  • 7/30/2019 Docs.orchardproject.net How Orchard Works

    1/8

    Love this PDF? Add it to your Reading List! 4 joliprint.com/mag

    docs.orchardproject.net

    How Orchard works

    Building a Web CMS (Content ManagementSystem) is unlike building a regular web ap-plication: it is more like building an applica-

    tion container. When designing such a system, it

    is necessary to build extensibility as a rst-classfeature. This can be a challenge as the very opentype of architecture thats necessary to allow forgreat extensibility may compromise the usabilityof the application: everything in the system needsto be composable with unknown future modules,including at the user interface level. Orchestratingall those little parts that dont know about each otherinto a coherent whole is what Orchard is all about.

    This document explains the architectural choices

    we made in Orchard and how they are solving thatparticular problem of getting both exibility and agood user experience.

    Architecture

    Modules

    Core

    Orchard Framework

    ASP.NET MVC NHibernate Autofac Castle

    .NET ASP.NET

    IIS or Windows Azure

    OrchardFoundations

    The Orchard CMS is built on existing frameworksand libraries. Here are a few of the most funda-mental ones:

    ASP.NET MVC: ASP.NET MVC is a modernWeb development framework that encou-rages separation of concerns.

    NHibernate: NHibernate is an object-relatio-nal mapping tool. It handles the persistenceof the Orchard content items to the data-base and considerably simplies the data

    model by removing altogether the concernof persistence from module development.You can see examples of that by looking atthe source code of any core content type, forexample Pages.

    Autofac: Autofac is an IoC container. Or-chard makes heavy use of dependencyinjection. Creating an injectable Orcharddependency is as simple as writing a classthat implements IDependency or a morespecialized interface that itself derives fromIDependency (a marker interface), andconsuming the dependency is as simple astaking a constructor parameter of the righttype. The scope and lifetime of the injecteddependency will be managed by the Or-chard framework. You can see examples ofthat by looking at the source code for IAu-thorizationService, RolesBasedAuthoriza-tionService and XmlRpcHandler.

    Castle Dynamic Proxy: we use Castle fordynamic proxy generation.

    28/06/2012 14:13

    http://doc

    s.orchardproject.net/Documentation/How-Orchard-works

    Page 1

    http://joliprint.com/maghttp://docs.orchardproject.net/http://www.asp.net/mvchttp://nhforge.org/http://code.google.com/p/autofac/http://en.wikipedia.org/wiki/Inversion_of_controlhttp://www.castleproject.org/dynamicproxy/index.htmlhttp://www.castleproject.org/dynamicproxy/index.htmlhttp://en.wikipedia.org/wiki/Inversion_of_controlhttp://code.google.com/p/autofac/http://nhforge.org/http://www.asp.net/mvchttp://docs.orchardproject.net/http://joliprint.com/http://joliprint.com/mag
  • 7/30/2019 Docs.orchardproject.net How Orchard Works

    2/8

    Love this PDF? Add it to your Reading List! 4 joliprint.com/mag

    docs.orchardproject.net

    How Orchard works

    The Orchard application and framework are builton top of these foundational frameworks as addi-tional layers of abstraction. They are in many waysimplementation details and no knowledge of NHi-bernate, Castle, or Autofac should be required towork with Orchard.

    Orchard

    FrameworkThe Orchard framework is the deepest layer ofOrchard. It contains the engine of the applicationor at least the parts that couldnt be isolated intomodules. Those are typically things that even themost fundamental modules will have to rely on. Youcan think of it as the base class library for Orchard.

    Booting Up Orchard

    When an Orchard web application spins up, an Or-chard Host gets created. A host is a singleton at theapp domain level.

    Next, the host will get the Shell for the current tenantusing the ShellContextFactory. Tenants are instancesof the application that are isolated as far as userscan tell but that are running within the same ap-pdomain, improving the site density. The shell is asingleton at the tenant level and could actually besaid to represent the tenant. Its the object that willeffectively provide the tenant-level isolation whilekeeping the module programming model agnosticabout multi-tenancy.

    The shell, once created, will get the list of availableextensions from the ExtensionManager. Extensionsare modules and themes. The default implementa-tion is scanning the modules and themes directoriesfor extensions.

    At the same time, the shell will get the list of settingsfor the tenant from the ShellSettingsManager. The

    default implementation gets the settings from theappropriate subfolder of Appdata but alternativeimplementations can get those from different places.

    For example, we have an Azure implementation thatis using blob storage instead because Appdata is notreliably writable in that environment.

    The shell then gets the CompositionStrategy objectand uses it to prepare the IoC container from the

    list of available extensions for the current host andfrom the settings for the current tenant. The result ofthis is not an IoC container for the shell, it is a Shell-Blueprint, which is a list of dependency, controllerand record blueprints.

    The list of ShellSettings (that are per tenant) and theShellBluePrint are then thrown into ShellContainer-Factory.CreateContainer to get an ILifetimeScope,which is basically enabling the IoC container to bescoped at the tenant level so that modules can get

    injected dependencies that are scoped for the cur-rent tenant without having to do anything specic.

    Dependency Injection

    The standard way of creating injectable dependen-cies in Orchard is to create an interface that derivesfrom IDependency or one of its derived interfacesand then to implement that interface. On the consu-ming side, you can take a parameter of the interfacetype in your constructor. The application frameworkwill discover all dependencies and will take careof instantiating and injecting instances as needed.

    There are three different possible scopes for de-pendencies, and choosing one is done by derivingfrom the right interface:

    Request: a dependency instance is createdfor each new HTTP request and is destroyedonce the request has been processed. Usethis by deriving your interface from IDe-pendency. The object should be reasonably

    28/06/2012 14:13

    http://doc

    s.orchardproject.net/Documentation/How-Orchard-works

    Page 2

    http://joliprint.com/maghttp://docs.orchardproject.net/http://docs.orchardproject.net/http://joliprint.com/http://joliprint.com/mag
  • 7/30/2019 Docs.orchardproject.net How Orchard Works

    3/8

    Love this PDF? Add it to your Reading List! 4 joliprint.com/mag

    docs.orchardproject.net

    How Orchard works

    cheap to create. Object: a new instance is created every

    single time an object takes a dependency onthe interface. Instances are never shared.Use this by deriving from ITransientDepen-dency. The objects must be extremely cheapto create.

    Shell: only one instance is created per shell/tenant. Use this by deriving from ISingle-

    tonDependency. Only use this for objectsthat must maintain a common state for thelifetime of the shell.

    Replacing Existing Dependencies

    It is possible to replace existing dependencies bydecorating your class with the OrchardSuppress-Dependency attribute, that takes the fully-qualiedtype name to replace as an argument.

    Ordering Dependencies

    Some dependencies are not unique but rather areparts of a list. For example, handlers are all activeat the same time. In some cases you will want tomodify the order in which such dependencies getconsumed. This can be done by modifying the ma-nifest for the module, using the Priority propertyof the feature. Here is an example of this:

    Features: Orchard.Widgets.PageLayerHinting:Name: Page Layer Hinting Description: ... Dependen-cies: Orchard.Widgets Category: Widget Priority: -1

    ASP.NET MVC

    Orchard is built on ASP.NET MVC but in order to addthings like theming and tenant isolation, it needsto introduce an additional layer of indirection thatwill present on the ASP.NET MVC side the conceptsthat it expects and that will on the Orchard side splitthings on the level of Orchard concepts.

    For example, when a specic view is requested, ourLayoutAwareViewEngine kicks in. Strictly speaking,its not a new view engine as it is not concernedwith actual rendering, but it contains the logic tond the right view depending on the current themeand then it delegates the rendering work to actualview engines.

    Similarly, we have route providers, model binders

    and controller factories whose work is to act as asingle entry point for ASP.NET MVC and to dispatchthe calls to the properly scoped objects underneath.

    In the case of routes, we can have n providers ofroutes (typically coming from modules) and oneroute publisher that will be what talks to ASP.NETMVC. The same thing goes for model binders andcontroller factories.

    Content Type System

    Contents in Orchard are managed under an actualtype system that is in some ways richer and moredynamic than the underlying .NET type system, inorder to provide the exibility that is necessary ina Web CMS: types must be composed on the y atruntime and reect the concerns of content ma-nagement.

    Types, Parts, and Fields

    Orchard can handle arbitrary content types, inclu-ding some that are dynamically created by the siteadministrator in a code-free manner. Those contenttypes are aggregations of content parts that each dealwith a particular concern. The reason for that is thatmany concerns span more than one content type.

    For example, a blog post, a product and a videoclip might all have a routable address, commentsand tags. For that reason, the routable address,comments and tags are each treated in Orchardas a separate content part. This way, the comment

    28/06/2012 14:13

    http://doc

    s.orchardproject.net/Documentation/How-Orchard-works

    Page 3

    http://joliprint.com/maghttp://docs.orchardproject.net/http://docs.orchardproject.net/http://joliprint.com/http://joliprint.com/mag
  • 7/30/2019 Docs.orchardproject.net How Orchard Works

    4/8

    Love this PDF? Add it to your Reading List! 4 joliprint.com/mag

    docs.orchardproject.net

    How Orchard works

    management module can be developed only onceand apply to arbitrary content types, including thosethat the author of the commenting module did notknow about.

    Parts themselves can have properties and contentelds. Content elds are also reusable in the sameway that parts are: a specic eld type will be typi-cally used by several part and content types. The

    difference between parts and elds resides in thescale at which they operate and in their semantics.

    Fields are a ner grain than parts. For example,a eld type might describe a phone number or acoordinate, whereas a part would typically describea whole concern such as commenting or tagging.

    But the important difference here is semantics: youwant to write a part if it implements an is a rela-tionship, and you would write a eld if it implements

    a has a relationship.

    For example, a shirt is a product and it has a SKUand a price. You wouldnt say that a shirt has a pro-duct or that a shirt is a price or a SKU.

    From that you know that the Shirt content type willbe made of a Product part, and that the Product partwill be made from a Money eld named price anda String eld named SKU.

    Another difference is that you have only one part ofa given type per content type, which makes sensein light of the is a relationship, whereas a partcan have any number of elds of a given type. Ano-ther way of saying that is that elds on a part area dictionary of strings to values of the elds type,whereas the content type is a list of part types (wi-thout names).

    This gives another way of choosing between partand eld: if you think people would want more thanone instance of your object per content type, it needs

    to be a eld.

    Anatomy of a Content Type

    A content type, as weve seen, is built from contentparts. Content parts, code-wise, are typically asso-ciated with:

    a Record, which is a POCO representation ofthe parts data

    a model class that is the actual part and that

    derives from ContentPart where T is therecord type

    a repository. The repository does not needto be implemented by the module authoras Orchard will be able to just use a genericone.

    handlers. Handlers implement IConten-tHandler and are a set of event handlerssuch as OnCreated or OnSaved. Basically,they hook onto the content items lifecycleto perform a number of tasks. They can

    also participate in the actual compositionof the content items from their construc-tors. There is a Filters collection on the baseContentHandler that enable the handler toadd common behavior to the content type.For example, Orchard provides a Storage-Filter that makes it very easy to declarehow persistence of a content part should behandled: just do Filters.Add(StorageFilter.For(myPartRepository)); and Orchard willtake care of persisting to the database thedata from myPartRepository.Another example of a lter is the Activatin-gFilter that is in charge of doing the actualwelding of parts onto a type: calling Filters.Add(new ActivatingFilter(BlogPostDriver.ContentType.Name)); adds thebody content part to blog posts.

    drivers. Drivers are friendlier, more spe-cialized handlers (and as a consequenceless exible) and are associated with aspecic content part type (they derive from`ContentItemDriver where T is a content

    part type). Handlers on the other hand donot have to be specic to a content part type.

    28/06/2012 14:13

    http://doc

    s.orchardproject.net/Documentation/How-Orchard-works

    Page 4

    http://joliprint.com/maghttp://docs.orchardproject.net/http://docs.orchardproject.net/http://joliprint.com/http://joliprint.com/mag
  • 7/30/2019 Docs.orchardproject.net How Orchard Works

    5/8

    Love this PDF? Add it to your Reading List! 4 joliprint.com/mag

    docs.orchardproject.net

    How Orchard works

    Drivers can be seen as controllers for a spe-cic part. They typically build shapes to berendered by the theme engine.

    Content Manager

    All contents are accessed in Orchard through theContentManager object, which is how it becomespossible to use contents of a type you dont know

    in advance.

    ContentManager has methods to query the contentstore, to version contents and to manage their pu-blication status.

    Transactions

    Orchard is automatically creating a transaction foreach HTTP request. That means that all operationsthat happen during a request are part of an am-

    bient transaction. If code during that request abortsthat transaction, all data operations will be rolledback. If the transaction is never explicitly cancelledon the other hand, all operations get committed atthe end of the request without an explicit commit.

    Request Liecycle

    In this section, well take the example of a requestfor a specic blog post.

    When a request comes in for a specic blog post,the application rst looks at the available routesthat have been contributed by the various modulesand nds the blog modules matching route. Theroute can then resolve the request to the blog postcontrollers item action, which will look up the postfrom the content manager. The action then gets aPage Object Model from the content manager (bycalling BuildDisplay) based on the main object forthat request, the post that was retrieved from thecontent manager.

    A blog post has its own controller, but that is not thecase for all content types. For example, dynamic

    content types will be served by the more genericItemController from the Core Routable part. TheDisplay action of the ItemController does almost thesame thing that the blog post controller was doing:it gets the content item from the content managerby slug and then builds the POM from the results.

    The layout view engine will then resolve the rightview depending on the current theme and using the

    models type together with Orchard conventionson view naming.

    Within the view, more dynamic shape creation canhappen, such as zone denitions.

    The actual rendering is done by the theme enginethat is going to nd the right template or shapemethod to render each of the shapes it encountersin the POM, in order of appearance and recursively.

    WidgetsWidgets are content types that have the Widgetcontent part and the widget stereotype. Like anyother content types, they are composed of parts andelds. That means that they can be edited using thesame edition and rendering logic as other contenttypes. They also share the same building blocks,which means that any existing content part can po-tentially be reused as part of a widget almost for free.

    Widgets are added to pages through widget layers.Layers are sets of widgets. They have a name, a rulethat determines what pages of the site they shouldappear on, and a list of widgets and associated zoneplacement and ordering, and settings.

    The rules attached to each of the layers are expressedwith IronRuby expressions. Those expressions canuse any of the IRuleProvider implementations in theapplication. Orchard ships with two out of the boximplementations: url and authenticated.

    28/06/2012 14:13

    http://doc

    s.orchardproject.net/Documentation/How-Orchard-works

    Page 5

    http://joliprint.com/maghttp://docs.orchardproject.net/http://docs.orchardproject.net/http://joliprint.com/http://joliprint.com/mag
  • 7/30/2019 Docs.orchardproject.net How Orchard Works

    6/8

    Love this PDF? Add it to your Reading List! 4 joliprint.com/mag

    docs.orchardproject.net

    How Orchard works

    Site Settings

    A site in Orchard is a content item, which makes itpossible for modules to weld additional parts. Thisis how modules can contribute site settings.

    Site settings are per tenant.

    Event Bus

    Orchard and its modules expose extensibility pointsby creating interfaces for dependencies, implemen-tations of which can then get injected.

    Plugging into an extensibility point is done eitherby implementing its interface, or by implementingan interface that has the same name and the samemethods. In other words, Orchard does not requirestrictly strongly typed interface correspondence,which enables plug-ins to extend an extensibility

    point without taking a dependency on the assemblywhere its dened.

    This is just one implementation of the Orchard eventbus. When an extensibility point calls into injec-ted implementations, a message gets published onthe event bus. One of the objects listening to theevent bus dispatches the messages to the methodsin classes that derive from an interface appropria-tely named.

    Commands

    Many actions on an Orchard site can be performedfrom the command line as well as from the adminUI. These commands are exposed by the methods ofclasses implementing ICommandHandler that aredecorated with a CommandName attribute.

    The Orchard command line tool discovers availablecommands at runtime by simulating the web siteenvironment and inspecting the assemblies usingreection. The environment in which the commands

    run is as close as possible to the actual running site.

    Search and Indexing

    Search and indexing are implemented using Luceneby default, although that default implementationcould be replaced with another indexing engine.

    Caching

    The cache in Orchard relies on the ASP.NET cache,

    but we expose a helper API that can be used througha dependency of type ICache, by calling the Getmethod. Get takes a key and a function that canbe used to generate the cache entrys value if thecache doesnt already contains the requested entry.

    The main advantage of using the Orchard API forcaching is that it works per tenant transparently.

    File Systems

    The le system in Orchard is abstracted so that sto-rage can be directed to the physical le system orto an alternate storage such as Azure blob storage,depending on the environment. The Media moduleis an example of a module that uses that abstractedle system.

    Users and Roles

    Users in Orchard are content items (albeit not rou-table ones) which makes it easy for a prole modulefor example to extend them with additional elds.Roles are a content part that gets welded onto users.

    Permissions

    Every module can expose a set of permissions aswell as how those permissions should be grantedby default to Orchards default roles.

    Tasks

    Modules can schedule tasks by calling CreateTask

    on a dependency of type IScheduledTaskManager.The task can then be executed by implementing

    28/06/2012 14:13

    http://doc

    s.orchardproject.net/Documentation/How-Orchard-works

    Page 6

    http://joliprint.com/maghttp://docs.orchardproject.net/http://docs.orchardproject.net/http://joliprint.com/http://joliprint.com/mag
  • 7/30/2019 Docs.orchardproject.net How Orchard Works

    7/8

    Love this PDF? Add it to your Reading List! 4 joliprint.com/mag

    docs.orchardproject.net

    How Orchard works

    IScheduledTaskHandler. The Process method canexamine the task type name and decide whetherto handle it.

    Tasks are being run on a separate thread that comesfrom the ASP.NET thread pool.

    Notifcations

    Modules can surface messages to the admin UI bygetting a dependency on INotier and calling oneof its methods. Multiple notications can be createdas part of any request.

    Localization

    Localization of the application and its modules isdone by wrapping string resources in a call to theT method: .See Using the localization helpers for more details

    and guidelines. Orchards resource manager canload localized resource strings from PO les locatedin specic places in the application.

    Content item localization is done through a differentmechanism: localized versions of a content item arephysically separate content items that are linkedtogether by a special part.

    The current culture to use is determined by theculture manager. The default implementation re-turns the culture that has been congured in sitesettings, but an alternate implementation could get itfrom the user prole or from the browsers settings.

    Logging

    Logging is done through a dependency of type IL-ogger. Different implementations can send the logentries to various storage types. Orchard comes withan implementation that uses Castle.Core.Loggingfor logging.

    Orchard Core

    The Orchard.Core assembly contains a set of mo-dules that are necessary for Orchard to run. Othermodules can safely take dependencies on thesemodules that will always be available.

    Examples of core modules are feeds, navigation or

    routable.

    Modules

    The default distribution of Orchard comes witha number of built-in modules such as blogging orpages, but third party modules are being built aswell.

    A module is just an ASP.NET MVC area with a ma-

    nifest.txt le that is extending Orchard.

    A module typically contains event handlers, contenttypes and their default rendering templates as wellas some admin UI.

    Modules can be dynamically compiled from sourcecode every time a change is made to their csproj leor to one of the les that the csproj le references.This enables a notepad style of development thatdoes no require explicit compilation by the develo-per or even the use of an IDE such as Visual Studio.

    Themes

    It is a basic design principle in Orchard that allthe HTML that it produces can be replaced fromthemes, including markup produced by modules.Conventions dene what les must go where in thethemes le hierarchy.

    The whole rendering mechanism in Orchard is

    based on shapes. The theme engines job is to ndthe current theme and given that theme determine

    28/06/2012 14:13

    http://doc

    s.orchardproject.net/Documentation/How-Orchard-works

    Page 7

    http://joliprint.com/maghttp://docs.orchardproject.net/http://docs.orchardproject.net/Documentation/Using-the-localization-helpershttp://api.castleproject.org/html/N_Castle_Core_Logging.htmhttp://api.castleproject.org/html/N_Castle_Core_Logging.htmhttp://docs.orchardproject.net/Documentation/Using-the-localization-helpershttp://docs.orchardproject.net/http://joliprint.com/http://joliprint.com/mag
  • 7/30/2019 Docs.orchardproject.net How Orchard Works

    8/8

    Love this PDF? Add it to your Reading List! 4 joliprint.com/mag

    docs.orchardproject.net

    How Orchard works

    what the best way to render each shape is. Eachshape can have a default rendering that may bedened by a module as a template in the viewsfolder or as a shape method in code. That defaultrendering may be overridden by the current theme.The theme does that by having its own version ofa template for that shape or its own shape methodfor that shape.

    Themes can have a parent, which enables child the-mes to be specializations or adaptations of a parenttheme. Orchard comes with a base theme called theTheme Machine that has been designed to make iteasy to use as a parent theme.

    Themes can contain code in much the same waymodules do: they can have their own csproj le andbenet from dynamic compilation. This enables the-mes to dene shape methods, but also to exposeadmin UI for any settings they may have.

    The selection of the current theme is done by classesimplementing IThemeSelector, which return atheme name and a priority for any request. Thisallows many selectors to contribute to the choiceof the theme. Orchard comes with four implemen-tations of IThemeSelector:

    SiteThemeSelector selects the theme that iscurrently congured for the tenant or sitewith a low priority.

    AdminThemeSelector takes over and re-turns the admin theme with a high prioritywhenever the current URL is an admin URL.

    PreviewThemeSelector overrides the sitescurrent theme with the theme being pre-viewed if the current user is the one thatinitiated the theme preview.

    SafeModeThemeSelector is the only selectoravailable when the application is in safemode, which happens typically duringsetup. It has a very low priority.

    An example of a theme selector might be one thatpromotes a mobile theme when the user agent isrecognized to belong to a mobile device.

    28/06/2012 14:13

    http://doc

    s.orchardproject.net/Documentation/How-Orchard-works

    Page 8

    http://joliprint.com/maghttp://docs.orchardproject.net/http://docs.orchardproject.net/http://joliprint.com/http://joliprint.com/mag