Showing posts with label Ektron. Show all posts
Showing posts with label Ektron. Show all posts

Tuesday, January 17, 2012

Best Practices for a .NET Extension or Plug-In


These are best practices that I created for writing a .NET Extension or Plug-In so some of the references and nomenclature are .NET specific, but the principals and ideas can be extended to any programming language or application design.

Best Practices for Writing a Good Extension or Plug-In:
  1. Any extension should have logging features (and ideally support verbose, error, warning messages). Most applications provide some sort of logging capabilities you can use or extend. This is preferred to designing your own simply because you would have to monitor two sets of logs not to mention the additional configuration, and maintenance of adding a second logging mechanism. If you do have to add your own logging, try to leverage an existing logging infrastructure: log4net, Microsoft Enterprise Library.
  2. If possible avoid any additional (and most importantly external) database or service calls. Aside from the performance hit this can add, your introducing potentially volatile resources that will affect the host systems ability to work properly.
  3. Settle on a single purpose or function for your extension. Don't try to make it do several things, and work in several different functions. It's hard to understand, maintain, and a nightmare when 'something' inside the extension/plug in goes bad.
  4. Limit external dependencies. If at all possible you want your extension/plug-in to be entirely self-sufficient. Any information or exchange should be provided by the host system via a state bag, or in the direct actionable items available.
  5. Document as much of the plug-in as possible within the code module. Include references, and be explicit. You should always document, but people tend to forget about extensions and plug-ins. You write them, they get deployed, and then days, months, years later... doom. The more that's in the code when you open it back up the quicker you can fix it.
  6. Handle and dispatch exceptions in almost all cases. If you can't handle the exception, and it needs to be raised to the host system, then make sure your logging (see #1 on this list) records the exception with as much information as possible. In my experience a host system most often reports very little useful information or (as in one case I remember) it reports absolutely nothing.
  7. Design the functionality of the plug in! So many times, people try to write everything inline for a plug-in rather than following the same coding practices that they would in any other application or feature. 
  8. Favor robust naming if your plug-in and if possible the methods, functions, and variables within it. Often when dealing with a plug-in it needs to be self explanitory to the infastructure dude, the end-user, and in almost all cases other people.
    1. Here's a quick example: 
      1. MyCompanyNamePlugIn - SeriouslyThat does that do? 
      2. MyCompanyUpdateCreatedDateOnNewRecordPlugIn - Ok, really simple. Want to guess?
  9. Consider interprocess communication if execution is lengthy, intensive, or will impact the performance of the host system. If the action is lengthy or is going to impact the host system, then consider having your plug-in use a queue or call a service for executing the action. If performance is going to be impacted in an extreme negative, consider external executing with a service-bus or queuing system.
References:
Best Practices for Developing Your First Ektron Site
Best Practices in Plugin Development (WordCamp Seattle)

Resources:
log4net
Microsoft Enterprise Library.

Monday, January 16, 2012

JsRender: Javascript Templating. An Introduction.

What is JsRender?
According to the demos index page JsRender is "Optimized for high-performance pure string-based rendering, without DOM or jQuery dependency".

In simple terms it's a way to apply templates to JSon data and render out content.  If you think about it, it's really a powerful feature, and valuable to anyone that is rendering content in a web browser.

It seems that JsRender became the solution for client side templating with the discontinuation of JQuery's templates, however JsRender is something... better. Aside from having no DOM depedency, it does not even have a JQuery dependency. From Borris Moore's presentation, JsRender is "~20 times faster than jquery.tmpl for simple templates".

At a high-level is supports:
Rendering templates and data into a string (as opposed to anything in the DOM)
Templates as strings, and within script tags
Template registration
Tags within templates, including conditional statements, loops

Here's a basic sample/example of JsRender in action: 
From http://borismoore.github.com/jsrender/demos/step-by-step/01_inserting-data.html












Requires Script references: jQuery, jsrender
Borris Moore offers a complete set of demos, which demonstrate much more: jsrender Demos.

What's JsRender's Future?

As a product, Borris Moore offered the following road-map for JsRender/JsView on OCTOBER 12, 2011 in this blog post: jQuery Templates and JsViews: The Roadmap

Roadmap summary:
  • jQuery templates
  • : Will remain at Beta1, and be superseded by JsRender templates, and JsViews.
  • JsRender
  • : Soon move to Beta – then on to V1
  • jQueryUI plan to use JsRender. (TBD whether it will migrate to jQuery project in GitHub...)
  • JsViews
  • : Move to Beta (after JsRender) and then on to V1 …
  • May also be used by jQueryUI

My Experiences

Most recently I've been using JsRender to render content from Ektron after designing a series of templates that would render content as JSon (see Designing Data Templates for Content Extraction with Ektron (JSon, XML) (Ektron Designing Content Delivery: Part 2) for more information).

In the past, I've also used it for rendering forms, pages, static content, large tables, dynamically loaded sections of my application. What can I say, it's easy, flexible and it works.

Resources:
jsrender on GitHub
jsrender Demos
JQuery Templates
Borris Moore "JsViews: Next-generation jQuery Templates and Data Link" Presentation
Designing Data Templates for Content Extraction with Ektron (JSon, XML) (Ektron Designing Content Delivery: Part 2

Friday, January 13, 2012

Determine your Ektron Version

Determing your Ektron product version should be simple

Within the website you can view a series of keys within the Web.config file that determines the product version:

<add key="ek_InstallBuild" value="8.0.2.035SP2.01"/>
<add key="ek_ServicePack" value="SP2"/>
<add key="ek_version" value="8.02"/>

You should also note that the Ektron version is available for the end-user to view it within the Ektron work area in the top left hand-corner (see screenshot below):

After searching, it does not appear that the product version is stored within the database for Ektron. There are version columns but this appears to be for versioning data within the application and not for determining the database (or Ektron product) version. This article on the forum seems to back-up these findings: Database Version(2).

Resources:
Database Version(2)

Wednesday, January 11, 2012

Designing a Generic Meta-Data Driven Transformation Template (Ektron Designing Content Delivery: Part 3)

In the previous Ektron Designing Content Delivery post (Designing Data Templates for Content Extraction with Ektron (JSon, XML) (Ektron Designing Content Delivery: Part 2)), I outlined the basics of creating a series of templates for data extraction.

While using Ektron content as data is useful (in particular SmartForm data), there is always a need to render transformed content (as Html, Text, Csv, or other formatted content). In this post, I will outline a method to create a simple Meta-Data driven Ektron template that can use used to transform your data for presentation.

What this is useful for:
  • SmartForm content that needs to be displayed as Html
  • SmartForm content that needs to be transformed (to other Xml, Html, Text, Csv, etc)
  • Any Ektron content that requires transformation before being rendered, and represents stand-alone content.
A high level overview of the rendering process:


Of note: I've also created an Ektron Widget control that follows the same pattern, so that I can render out this content as part of a page-builder page without any additional work by the end user. It pretty much works the same way with the template being a page-builder widget, and the end consumption being a Page-builder page.

Transformation Template:
System/Design Requirements:
1. Support Multiple Xsl/Xslt translations against the content set
2. When not configured properly then display a simple message back for the rendered content.
3. Support different separators/delimiters within the metadata in-case there is a conflict and it needs to be changed or updated.

ASPX:
       
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="MetaDataTransformation.aspx.cs" Inherits="ContentManagement.Site.Shared.Template.Content.SmartForm.MetaDataTransformation" %>
<%@ Register Assembly="Ektron.Cms.Controls" Namespace="Ektron.Cms.Controls" TagPrefix="CMS" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <CMS:ContentBlock ID="ContentBlock1" runat="server" />
    </div>
    </form>
</body>
</html>
       
 

Code-Behind:
using System;
using ContentManagement.Ektron.Content;
using ContentManagement.Ektron.Transformation.Xsl;
using ContentManagement.Site.Shared.Pages;
using MetaData = Ektron.Cms.API.Metadata;
using ContentManagement.Ektron.Transformation;

namespace ContentManagement.Site.Shared.Template.Content.SmartForm
{
    public partial class MetaDataTransformation : AbstractCmsPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            this.ContentBlock1.SetDynamicParameterToIdAndFill(); //prep content block

            Response.Clear();

            WriteCmsDataToHeader(Response);
            Response.ContentType = ContentManagement.Web.ContentTypeDefinition.Html;

            var id = this.ContentBlock1.EkItem.Id; //retrieve the id from the item

var metaData = this.ContentBlock1.GetMetaData().GetItemByName("Transformation"); //Note: This should be content/error content from Ektron. Action badRender = () => Response.Write("Oppps. It looks like this content isn't ready yet. Try back again soon."); if (metaData == null) //meta data not located on this item, so we do not want it to render. badRender(); else { var data = new MetaData(); var metaDataType = data.GetMetadataType(long.Parse(metaData.ID)); var xsltTransformationFromMetaData = this.ContentBlock1.GetMetaData().GetItemByName("Transformation").Value.ToString().Split(new string[1] { metaDataType.Separater }, StringSplitOptions.RemoveEmptyEntries); var transform = XslTransformFactory.Get(); var input = this.ContentBlock1.EkItem.Html; if (xsltTransformationFromMetaData.Length <= 0) //no content, write out a simple error message. badRender(); else if (xsltTransformationFromMetaData.Length == 1) { //apply single transformation, and output directly to response stream transform.Transform( new XmlStringInput(input) , new XslFileInput(TransformationPath.MapPathAndValidate(this, xsltTransformationFromMetaData[0])) , Response.OutputStream , Response.Output.Encoding); } else { //apply multiple translations xsltTransformationFromMetaData.ForEach(trns => input = transform.Transform(new XmlStringInput(input), new XslFileInput(TransformationPath.MapPathAndValidate(this, trns)))); } } Response.End(); } } }


The steps for setup and configuration are pretty simple:
Ektron Configuration
  • Creation of the Meta-Data within Ektron
  • Sample Metadata Transformation within Ektron 8.0.2
  • Apply the Metadata to the Content Folder(s)
  • Metadata applied to the content folder
  • Add Meta-Data Driven Transformation Template to your content
Content Configuration
  • Add the MetaData to the Content
  • Meta Data Transformation on Content (Note: This has two transformations)
  • Set the Template for the Content to the Transformation Template
  • Add the correct meta data transformation template.


Notes
If your planning on using this with any type of volume you will want to cache the output of the transformation.

It's important to note that I am not referring to adding a custom style sheet to an Ektron web control (which you can do, and is extremely flexible) in particular this template will retrieve Ektron content, apply transformations and then write the result of the transformation to the response output. The application (and usage) of this for consumption of Ektron content is quite different. If your developing pages within Ektron, and want to transform the output of the control, using Ektron's own transformation infrastructure is a much better option. Here, I am transforming, and then providing content via a push/pull to other sites for content presentation (and providing an option to present that content fully rendered).

Q & A
Q: How is this different than adding a Cms control to the page and selecting a transformation? 
A: At the end of the day, it's not all that different, but I wanted a way to make this process completely configuration driven so I can set up additional content at will without having to create a page or a template for each set of content. 

In my next posts
1. Designing a wrapper-API for consumption, caching and rendering of Ektron data.
2. Now look what we can do: Render Ektron client-side with data templates and JsRender (for smoking fast response times).
3. My Ektron page templates

Resources:
Designing an Ektron Content Delivery and Provider Mechanism (Part 1)
Designing Data Templates for Content Extraction with Ektron (JSon, XML) (Ektron Designing Content Delivery: Part 2)
Guest Blogger-Cameron Jordan: No More XSLT?!

Tuesday, January 10, 2012

Ektron: Using a SmartForm root element other than <Root>

When creating an Ektron SmartForm you may want to have a root element other than the default <Root> element.

It's pretty easy to do, just follow these simple steps:
1. Select the Group Box option from the menu

2. Set the 'Field Name' on the 'General' tab to the name of the root element.
2. Select the 'Advanced' tab

3. Select 'Use this element as a root tag' from the 'Root Tag' section

4. Select 'OK'

Additional Information:

  • When you add the group box as designate it as the root tag, you cannot place anything outside of the group box. This makes a lot of sense, but know if your moving things around... everything has to be inside of the group box.
  • If you have created this SmartForm previously, this change will cause the underlying data structure be to changed in a way that will remove any previous data. If your making this change on an existing SmartForm, I would recommend creating a new one (by copying and then making the change), and then migrating content from the old SmartForm to the new one.
  • If your using version 8 then you might want to check out my post Smart Form with custom root element blank when editing (Version: 8.02)


Resources:
Data Designer Field Types
Smart Form with custom root element blank when editing (Version: 8.02)

Smart Form with custom root element blank when editing (Version: 8.02)

When creating a SmartForm with a custom root element the SmartForm created correctly without a problem. When going to edit the SmartForm content it appears blank. However, the content is viewable (when not in edit mode), and renders properly.

Investigating the problem, it appears the xml is correctly there, it just won't let you edit it.

Credit for this solution goes entirely to EktronRashmi and was posted on the Ektron forum in his post Smart Form with Custom Root Element Doesn't Allow Editing.

This forum post contained the solution (Smart Form with Custom Root Element Doesn't Allow Editing):
Here's a fix for this issue
edit sitetroot\workrarea\java\ektron.xml.js
go to line # 299 and comment out following IF statement block (5 lines)
if ("<" == xml.substr(0, 1) && xml.substr(xml.length - 7) != "")
{
xml = "" + xml + "";
bRootTagAdded = true;
}

He actually puts a nice screenshot in there as well:

Based upon this article, I completed the following steps to fix the problem:
1. Checked the file out of source control
2. Applied the fix listed in the forum post
3. Checked the file in
4. Deployed to site

References:
Smart Form with Custom Root Element Doesn't Allow Editing
EktronRashmi Profile
Using a Tag Other Than Root

Monday, January 9, 2012

Designing Data Templates for Content Extraction with Ektron (JSon, XML) (Ektron Designing Content Delivery: Part 2)

In my first post Designing an Ektron Content Delivery and Provider Mechanism (Part 1) I outlined the basic steps for designing Ektron for management of the content, with the idea of pushing (or pulling) content from this system to be consumed by a host of other sites (and potentially applications).

This post will focus on designing template for the extraction of information from Ektron so that it may be pushed or pulled for consumption by other systems.

This started with basic research around how to retrieve information from Ektron.
  • 1. API - The application itself supports a fairly extensive API which could certainly be used to interact with information. You can certainly get at your content and manipulate it. However investigation here was pretty easy. The API itself is around retrieval and content management and not around manipulation. The proof of concept certainly worked, but was a lot of work and manual code.
  • 2. Database - Ektron maintains a SQL database, and you can see your content. You could write your own access logic, and get the information you need. However, aside from violating the best practices for Ektron (and making your new infrastructure completely Ektron version dependent), this is a tremendous amount of manual work for little or no benefit. This is possible, but so far beyond practical or reliable.
  • 3. Templates [Selected Solution] - Out of the box Ektron supports templates. For the most part these templates are designed to render content out to the end-user... but... the design is also flexible. At the end of the day this is what Ektron is designed to do, just with a slightly different end-result or consumption. The proof of concept worked, and was easily integrated into the Ektron web-site. In other words: simplicity.
  • 4. Ektron Web-services - Ektron supports a host of web-services for interacting with the application. Designed in a very similar fashion to their API, it works, and is practical. Built on SOAP this is a very viable option. In similar to the API it's design around retrieval and content management and not around manipulation. The proof of concept certainly worked, but was a work to create the transitions from the content type to the rendered types.

In the end the solution that worked best was to design a series of templates. Why? It was easy to do, worked well with Ektron's design and provided a tremendous amount of flexibility. This created some quick benefits to the project:
  • Content could be managed via a url so access via the wrapper API could be directly tied back to the content it represented. In the end, we selected manual alias names for content (as an example: [Group]/[Section]/[Content]/).
  • The type of content to be generated when pulled could be set/managed inside of Ektron, simple by selecting a template (JSon/Xml/Html, etc.) reducing the amount of IT management and overhead.
  • The templates at the end of the day are relatively simple ASPX pages, which require a small amount of development and can be managed as part of the Ektron website for lifecycle and delivery.
  • The paring with Ektron SmartForms makes an extremely flexible offering with control over structure, content, security and delivery.

In the end, I decided on a basic delivery set of Html, Text, Xml, JSon. In order to make the most compelling offering, these were arranged into a simple folder structure:

  • Content
    • SmartForm Translation with MetaData
    • AsJson
    • AsXml
  • Taxonomy
    • SmartForm Translation with MetaData (planned)
    • AsJson
    • AsXml (planned)
    Note: I could do a whole post on what I am doing with Taxonomy separate from rendering content. If anyone is interested let me know.
  • AsJson
  • AsXml
  • AsRaw
  • AsRawCollection

The content templates are exactly what you think: rendering out the actual content. The other base templates render out the entire Ektron content items. However, I built those because it was easy to do, the vast majority of the items built on top of this are around the content and taxonomy templates.

Here's an example of the JSon template for content:
ASPX:
       
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AsJSon.aspx.cs" Inherits="Shared_Template_Content_AsJSon" %>
<%@ Register Assembly="Ektron.Cms.Controls" Namespace="Ektron.Cms.Controls" TagPrefix="CMS" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <CMS:ContentBlock ID="ContentBlock1" runat="server" />
    </div>
    </form>
</body>
</html>
       
 

Code-Behind:
       
public partial class Template_Content_AsJSon : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        this.ContentBlock1.SetDynamicParameterToIdAndFill();

        var document = new XmlDocument();
        document.LoadXml(this.ContentBlock1.EkItem.Html);

        Response.Clear();
        
        Response.ContentType = Web.ContentTypeDefinition.JSon;
        Response.Write(JsonConvert.SerializeXmlNode(document).Replace("@", string.Empty).Replace("#text", "text")); 

        Response.End();
    }
}
       
 

As you can see basic and effective. Content is available to be pulled (or pushed) via a url. Content (as data, html or any other delivery) is easily track able back as a url, rather than by an id or some other abstract storage identifier. Ektron manages the content, security, data storage definitions, and management of the content/delivery mechanism.

In my next posts:
1. Designing a Generic Meta-Data Driven Transformation Template with Ektron
2. Designing a wrapper-API for consumption, caching and rendering of Ektron data
3. Now look what we can do: Render Ektron client-side with data templates and JsRender (for smoking fast response times).

Resources:
Ektron API
Ektron Best Practices
Design without Borders, yet with Structure
JsRender

Friday, January 6, 2012

Ektron: "System.Web.Services.Protocols.SoapException: Credentials must be specified"

When using the Ektron.Services a feature works correctly, but when deployed to a remote machine, the content rendering fails with "System.Web.Services.Protocols.SoapException: Credentials must be specified".


Server Error in '/' Application.
--------------------------------------------------------------------------------

Credentials must be specified
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Web.Services.Protocols.SoapException: Credentials must be specified

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Ouch.

According to this post System.Web.Services.Protocols.SoapException: Credentials must be specified "That code will work from local system but won't work from remote system because of security. Ektron does not allow unauthenticated remote calls. In order to execute WS calls remotely you need to specify username and password of a cms user."

This code will add authentication that will allow the call to complete without a SOAP exception:
Ektron.Services.AuthenticationHeaderValue = new Ektron.Services.AuthenticationHeader();
Ektron.Services.AuthenticationHeaderValue.Username = "admin";
Ektron.Services.AuthenticationHeaderValue.Password = "admin";

This is a great example where you could wrap the authentication into a factory for creation of the service wrapper objects and/or create a fluent extension method that sets credentials for each wrapper object:
var taxonomySvc = TaxonomyFactory.GetService(); OR var taxonomySvc = new Ektron.Services.Taxonomy().WithDefaultCredentials();

However, you should not a couple of things.

In my case, I was working with the Taxonomy classes, and by accident referenced: Ektron.Services.Taxonomy and NOT Ektron.Cms.API.Content.Taxonomy. Apparently they both work the same, and are available (in separate namespaces). According to the same post, the latter (Ektron.Cms.API.Content.Taxonomy) should not require credentials. Which would explain how I came across this problem in the first place.

References:
System.Web.Services.Protocols.SoapException: Credentials must be specified

Thursday, January 5, 2012

Designing an Ektron Content Delivery and Provider Mechanism (Part 1)

As your designing your Ekron Content Management System (CMS) you need to design the level of interaction your enterprise will have with the CMS.

From the design of Ektron you can see it prefers to be the center of your offering. Most of the controls, pages, API and other components are geared towards building a site. In that regard, it seems to be competent.

For the project I am currently working on, the idea is something very different. It's to use Ektron for management of the content, with the idea of pushing (or pulling) content from this system to be consumed by a host of other sites (and potentially applications).

In some regards, Ektron is not designed to do this type of work. The out-of-the-box offering for exporting content supports PDF, and a synronization utility integrated with the product called ESync is designed to move content through the environments, and for content generation. Their marketing literature describes ESync as: "Automate the secure provisioning of web content, code, assets, and templates from development through production. Deploy only the necessary changes, from a single content update to an entire site, speeding time to Web and eliminating site downtime.".

Based upon Ektron's functionality and the desire to use it as a content repository there is a need to:
1. Design a way to generic render XML (SmartForm) content into Html, Text, Csv
2. Design a way to extract content information (SmartForm) into Xml, JSon
3. Design a way to extract html (or Ektron rendered content) in it's native format
4. Develop an Intermediate/Proxy API capable of extracting content on demand, providing caching of that content at the destination, and providing the content when requested.
5.

These deliverables combined with Ektron as a system itself (including the best practices documentation) generated these additional constraints or parameters:
1. The content delivery and provider mechanism should not interact directly with Ektron's data-storage.
2. The system should rely heavily on using the Ektron website for content extraction, and avoid direct interaction with the database, or Ektron APIs where possible.
3. The delivery mechanism should be extremely flexible and should scale with demand.
4. Any development should wrap Ektron, and not involve changing the core application or product.
5. The strategy support upgrading Ektron at any time.

In order to achieve the deliverables and system requirements, I designed a series of extraction templates (to be included within the Ektron site), and an API for use by these templates, and for extraction of the content (in it's various forms).

This is the high-level design:

Each of the sites consuming the content access Ektron's information via the API, and then store the content within one of the caching mechanisms (file/IO, HttpContext caching, RavenDB) and retrieve any missing content on demand.

Since the API capable of retrieving, caching and filtering content it supports on-demand requests, pull-requests from sites. The next goal is to add content-push from Ektron into the caching mechanisms (proactively staging updated content for the sites to consume).

In my next post:
1. Designing Data Templates for Content Extraction with Ektron (JSon, XML)
2. Designing a Generic Meta-Data Driven Transformation Template with Ekron

References:
Ektron
ESync

Tuesday, January 3, 2012

Best Practices for Developing Your First Ektron Site

This is a good presentation on best practices for Ektron.

Key Points:

  • Prefer SmartForms over HTML content - SmartForms provide a structured representation of your content allowing for greater control, and options for content re-use.

  • PageBuilder - The presentation recommends leveraging PageBuilder. My own experiences with PageBuilder have been mixed, but then again I am working with 8.0 and not version 8.5

  • Create an abstraction layer of Ektron - A key point in any application, but most definitively within Ektron. An abstraction layer to avoid directly calling the Ektron assemblies.

  • Have a caching strategy

  • Logging - The presentation recommends using the integrated Microsoft Enterprise Library logging that is already used within Ekton CMS.

  • Configuration - The presentation points out that the Ektron configuration, and your custom configuration should be separated into different configuration files.



Presentation:
Best Practices for Developing Your First Ektron Site