Introduction to Gadgets
|
Product version: |
EPiServer CMS 6 RC1 |
|
Document version: |
1.1 |
|
Document last saved: |
|
The dashboard is one of the new features of EPiServer 6 which is also a plug-in area open to partners. Usages include presenting high-level information or provide quick access to common tasks. This document is a tutorial to creating gadgets on the dashboard.
While this document highlights aspects related to gadget development with code examples keep these external resources handy for in depth information:
- QuickChat project, Zipped C# project: Quick and dirty output from this tutorial
- Dynamic DataStore SDK: Documentation and examples on the data store
- Up-to-date info on ASP.NET MVC
Contents
Setup
Starting out with gadgets
Gadget Development, step 1: Showing Information
Gadget Development, step 2: Server Interaction
Gadget Development, step 3: Client side development
Gadget development, step 4: Styles and CSS
Further Information
Checklist: Playing nice on the dashboard
Setup
Start by installing an EPiServer CMS 6 web site using the standard installer. Using the default options you will end up with a web site in c:\EPiServer\Sites\[MySiteName]. In the example below this site was installed in c:\EPiServer\Sites\ExampleEPiServerSite4. While it’s not required for normal operation this tutorial assumes you have installed ASP.NET MVC 1.0.
Develop gadgets in separate project
The module is created as a separate project below the “public” folder of the EPiServer site. As an alternative to creating a separate project you can add you gadget to the existing PublicTemplatest project, please see the Develop gadgets in public templates project section for more information.

Add a unit test project if you like. This tutorial will not cover unit testing.

As you can see in the screen shot when enabling “Show all files” the quick chat module is placed below the development site.
[3_PublicFolder.png]

Modifications to default
Some modifications are recommended to the default MVC application.
1. Remove default controllers and views
Remove the default controllers, views and scripts (HomeController.cs, /Views/Home, etc.) according to the image below. You can always use another project to play with ASP.NET MVC. Please note that if you have added a unit test project you also have to remove all the related test functions from the QuickChat.Test project.

2. Clean up web.config
The web configuration is inherited from the public templates site but if you leave some settings in the module’s web.config you won’t kill intellisense. Copy the root web.config file (not the one in the Views folder) from the QuickChat example zip to your project.
3. Change output path
Open the QuickChat project's properties and change the default build output path of the quick chat project to “..\..\bin\”

4. Add references
Add references to EPiServer.Shell and EPiServer.Data. You will need these later on. You can find a copy of these in the public template’s bin folder.

5. Register module in web.config
Open the public templates’ web.config file and find the episerver.shell configuration section. Add the quick chat module to the /configuration/episerver.shell/modules/ path. This is an excerpt of the added configuration:
<episerver.shell>
<publicModules rootPath="~/public/" autoDiscovery="Minimal">
<!-- QuickChat is assumed to be located in ~/public/QuickChat -->
<add name="QuickChat">
<assemblies>
<add assembly="QuickChat"/>
</assemblies>
</add>
</publicModules>
Develop gadgets in public templates project
While creating gadgets in a separate project as described in the Create gadgets in separate project section often is a good approach it’s also possible create gadgets in the PublicTemplates.csproj project by doing some modifications to configuration and the csproj file.
1. Configuration
The Public Templates needs to be registered in the configuration/episerver.shell/publicModules configuration section. The resourcePath attribute tells the system to look for views (which are described later in this document) in the folder /Views/[ControllerName]/[ActionName].ascx instead of the default location below the modules folder. Also update the add assembly section to any new name chosen for the public templates application.
<episerver.shell>
<publicModules rootPath="~/public/" autoDiscovery="Minimal">
<add name="Public" resourcePath="~/">
<assemblies>
<add assembly="EPiServer.Templates.Public" />
</assemblies>
</add>
2. References
Add references to “System.Web.Mvc”, “EPiServer.Shell” and “EPiServer.Data”.
3. Create Folders
The ASP.NET MVC framework suggests you organize the code in below three folders: “Controllers”, “Models” and “Views”. Add these folders to your project.
4. Visual Studio Integration
ASP.NET MVC includes some wizards to help out in the task of creating controllers and views. These are not enabled in the PublicTemplates.csproj installed with EPiServer CMS but they can be with some manual tweaking of the file. Right-click on the project and “Unload”, then “Edit …” it. Add {603c0e0b-db56-11dc-be95-000d561079b0}; to the list of existing project type guids. Now save, right click “Reload Project”.
<Project>
<PropertyGroup>
<ProjectTypeGuids>{603c0e0b-db56-11dc-be95-000d561079b0};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
Starting out with gadgets
It’s time to create a gadget. Head to the QuickChat project, right click on the “Controllers” directory and “Add Controller”.

Add the gadget attribute to the controller template created for you. To reduce Time-to-dashboard we change the return statement to return html content directly (we’ll change this soon).
using System.Web.Mvc;
using EPiServer.Shell.Gadgets;
namespace QuickChat.Controllers
{
[Gadget]
public class QuickChatController : Controller
{
public ActionResult Index()
{
return Content("<strong>Some</strong>thing!");
}
}
}
Now compile and switch over to the dashboard. Click on the (+) symbol of QuickChat in “Add Gadgets…” to add this new gadget. Now that we’ve got “Something” out on the dashboard we can move on to more serious business.

A tiny bit of background
Dashboard gadgets are developed using the MVC model. From the point of view of processing a server request this model can be described like this:
Incoming Request » Controller Action » View » Outgoing Response
The “Controller Action” and “View” represents code that is developed to provide functionality. The arrows (») represent pluggable points provided by the ASP.NET MVC framework.
In a typical ASP.NET MVC application the flow spans over a complete page request. However, in the case of our dashboard gadgets this is slightly different:
Incoming Request » Dashboard Controller Action » Dashboard View
foreach (gadget on userDashboard)
{
Partial Request » Controller Action » View
} » Outgoing Response
Dashboard gadgets uses the same principles as a typical MVC application but only renders a portion of the dashboard.
Gadget Development, step 1: Showing Information
With something now presented on the dashboard and a little background behind us we can let the coding begin.
Models
Add a class Message to the Models directory of the quick chat project.
using System;
namespace QuickChat.Models
{
public class Message
{
public string Text { get; set; }
public string From { get; set; }
public DateTime Sent { get; set; }
}
}
The model represents another pillar of the MVC architecture. This describes the data we interact with using the controller and show in our views.
Controller
Going back to the QuickChatController and use EPiServer.Data to retrieve messages from the database (take a look at the EPiServer Framework Reference SDK for in-depth information about the Dynamic Data Store):
[Gadget]
public class QuickChatController : Controller
{
// since the controller is created for each request
// we can assign a store as a variable
static QuickChatController()
{
DynamicDataStoreFactory.Instance.CreateStore(typeof(Message));
}
public ActionResult Index()
{
DynamicDataStore store = DynamicDataStoreFactory.Instance.GetStore(typeof(Message));
// select all messages for the last 5 minutes
var fiveMinutesAgo = DateTime.Now.AddMinutes(-5);
var messages = from m in store.Items<Message>()
where m.Sent > fiveMinutesAgo
select m;
// pass the messages to the view
return View(messages.ToList());
}}
The code will select all recent messages and pass them to the “Index” view for display.
Views
Create an MVC partial view in the quick chat project.

The wizard can be conjured by right-clicking in the controller action and choosing “Add view…” (requires ASP.NET MVC 1.0 to be installed).
When the view is located in Views/QuickChat/Index.ascx in the quick chat project it will be automatically selected to show the messages.
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IList<QuickChat.Models.Message>>" %>
<%@ Import Namespace="QuickChat.Models" %>
<div class="epi-defaultPadding">
<ul>
<% foreach (Message m in Model) { %>
<li><%= m.From %>: <%= m.Text %></li>
<% } %>
</ul>
Number of messages: <%= Model.Count %>
</div>
The view shows messages passed to it by the controller which is just about enough when adhering to the MVC pattern.
Gadget Development, step 2: Server Interaction
So far we have created a gadget that shows messages in the database but there is no way to put the messages in. That is precisely what is going to be fixed.
Posting messages to the controller
The most convenient option for posting information from the dashboard is using AJAX. This release includes an extension method that helps out doing this:
<%@ Import Namespace="EPiServer.Shell.Web.Mvc.Html" %>
<div class="epi-defaultPadding">...</div>
<hr />
<% Html.BeginGadgetForm("Save"); %>
<input name="text" />
<%= Html.AcceptButton() %>
<% Html.EndForm(); %>
The new improvement of the view renders a form with a text input field and a submit button. Since we used a “gadget form” the form will be serialized and posted using jQuery.ajax. The results of the “Save” action will replace any existing content in the gadget.
Taking care of posted messages in the controller
The controller accepts the posted message and stores it in the store. The view that is returned will take the place of the existing view in the gadget area. The mapping of the posted message string to input parameters is a feature of ASP.NET MVC. Refer to the blogosphere for documentation on form posting scenarios.
public ActionResult Save(string text)
{
DynamicDataStore store = DynamicDataStoreFactory.Instance.GetStore(typeof(Message));
// store the posted message
Message message = new Message();
message.Text = text;
message.From = User.Identity.Name;
message.Sent = DateTime.Now;
store.Save(message);
var messages = GetRecentMessages();
return View("Index", messages);
}
IList<Message> GetRecentMessages()
{
DynamicDataStore store = DynamicDataStoreFactory.Instance.GetStore(typeof(Message));
return (from m in store.Items<Message>()
where m.Sent > DateTime.Now.AddMinutes(-1)
orderby m.Sent
select m).ToList();
}
Gadget Development, step 3: Client side development
While server development is great it’s what you do on the client that makes your projects shine.
You may have noticed that the chat gadget at this point still isn’t very interactive. While you get updates when refreshing the page, or posting messages it’s just sits there in between.
Defining resources
First of all is getting out on the dashboard with all the other gadgets. The recommended way of doing this is using an attribute on the controller, as below:
[Gadget]
[EPiServer.Shell.Web.ScriptResource("Content/QuickChat.js")]
public class QuickChatController : Controller
{
}
This will declare a java script file located in the Content directory of the quick chat module which will be loaded with the dashboard. The script is loaded every time the dashboard is displayed, regardless if there are any quick chat gadgets or not, so takes care to put stable code in the javascript file.
While the script is executed each time the dashboard loads the way to associate with a gadget instance are client script init methods:
[Gadget(ClientScriptInitMethod = "quickchat.init")]
[EPiServer.Shell.Web.ScriptResource("Scripts/QuickChat.js")]
public class QuickChatController : Controller
Client scripts
The script resource attribute assumes a JavaScript method “quickchat.init” is present on the client. Let’s take a look on this method in the quickchat.js file:
(function($) {
// using this pattern helps keeping your privates private
quickchat = {};
quickchat.init = function(e, gadget) {
setInterval(function() {
// while this reloads the view on an interval
// it might cause problems to people actually
// wanting to chat since it will clear
// the text field
gadget.loadView("Index");
}, 5000);
};
})(epiJQuery);
The init method is invoked by the dashboard and starts updating the gadget every five seconds. While this represents an easy way to update the gadget regularly it’s not particularly suited for a chat since it will steal focus from the text box.
Gadget development, step 4 - Styles and CSS
The best way to get your own style sheets out on the dashboard is defining them for your gadget as in this snippet:
[Gadget(ClientScriptInitMethod = "quickchat.init")]
[EPiServer.Shell.Web.CssResource("Content/QuickChat.css")]
public class QuickChatController : Controller
By using the attribute on the gadget controller and creating a css file in the Styles folder of your gadget proejct you can define styles specific to your gadget. There are also shared styles you can use to get a consistent look and feel. This is described in a later section of this document.
Download the Quick Chat Gadget code sample in zip format.
Further Information
Styling
The CSS styles used on the Dashboard resets many of the default styling of elements added by the browser and in some cases adds an own default style. This styling may however not be enough (it’s rather none styled) so to the rescue comes some additional convenient classes. Further documentation about styling and the Dashboard/OnlineCenter will be available shortly.
- epi-contentArea, set on a container element, any type, for content you want to be affected.
- epi-formArea, set on a container element of any type, does not only apply to form element.
epi-contentArea
At the moment the epi-contentArea class gives you a “Dashboard default” look on tables, lists and heading and link colors, but will probably affect more in the final release. An example:
<div>
<h2>Two handy CSS classes</h2>
<ul>
<li>epi-contentArea</li>
<li>epi-contentForm</li>
</ul>
<table>
<caption>Table caption</caption>
<thead>
<tr>
<th scope="col">Heading One</th>
<th scope="col">Heading Two</th>
<th scope="col">Heading Three</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data A</td>
<td>Lorem ipsum</td>
<td>Dolor sit amet</td>
</tr>
<tr>
<td>Data B</td>
<td>Lorem Ipsum</td>
<td>Dolor sit amet</td>
</tr>
</tbody>
</table>
</div>
The above code would look like this without the use of epi-contentArea class:

Adding the epi-contentArea class to the container div will change the appearance.
<div class="epi-contentArea">

In most cases epi-contentArea will suit fine, but in some scenarios you might want one table to look like above without affecting any other child elements. In such a case you could use epi-default or epi-simple (no borders or margins) classes directly on the table element like:
<table class="epi-default">
Forms and epi-formArea
Form elements like fieldset, legend, input, textarea, etc will by default have a very minimalistic styling.
<form action="#" onsubmit="return false;">
<fieldset>
<legend>Styling forms</legend>
<p>The parent child relation of labels and inputs is discussed below.</p>
<fieldset>
<legend>Love CSS?</legend>
<label>
<input type="radio" name="radio1"
checked="checked" value="1" />Yes
</label>
<label>
<input type="radio"
name="radio2" value="2" />No
</label>
</fieldset>
<div>
<label>
<span>Please explain why</span>
<input type="text" value="" />
</label>
</div>
</fieldset>
</form>
The above code will show up as:

Setting the epi-formArea class on the form element gives this:

There are also some sizing classes that could be used individually on inputs, selects, labels or containers for labels.
- epi-size3 (Not on labels or containers for labels)
- epi-size10
- epi-size15
- epi-size20
- epi-size25
- epi-size30 (Not on labels or containers for labels)
Note: Does not work on select element in IE at the moment. They will still take width of content.
By setting an input element inside a label the label automatically will be associated with the input without having to set the “id” attribute on the input (and the “for” attribute on the label). This is perfectly valid HTML and we easily avoid having the same id twice in a page, which the use of two gadgets of the same kind in a page would result in.
The parent child relation also results in some nifty alignment possibilities of labels and form fields:
<form action="#" onsubmit="return false;" class="epi-formArea">
<fieldset>
<legend>Styling form</legend>
<div class="epi-size10">
<label>
<span>Label one</span>
<input class="epi-size3" type="text" />
</label>
</div>
<div class="epi-size10">
<label>
<span>Label two</span>
<input type="text" class="epi-size15" />
</label>
</div>
<div class="epi-size10">
<label>
<span>A really long label which will break row</span>
<select class="epi-size15">
<option>Option One</option>
<option>Option Two</option>
</select>
</label>
</div>
<div class="epi-size10">
<label>
<span>Label four</span>
<input type="text" class="epi-size30" />
</label>
</div>
</fieldset>
</form>
You may have noticed that the QuickChat gadget uses the CSS class “epi-defaultPadding”. This particular class gives padding consistent with other gadgets on the dashboard.
EPiServer currently also promotes the following CSS classes for usage on the dashboard:
Paddings etc:
- epi-defaultPadding
- epi-defaultPaddingHorizontal
- epi-defaultPaddingVertical
- epi-smallPadding
- epi-smallPaddingHorizontal
- epi-smallPaddingVertical
- epi-noDisplay
- epi-noBorder
- epi-noMargin
- epi-buttonRow
Adding options in the gadget menu
Dashboard gadgets support actions accessed through the gadget menu on each gadget. This example retrieved from the RSS gadget exemplifies how an action is hooked into the gadget menu:
/// <summary>
/// Returns the configuration view for the Gadget.
/// </summary>
/// <param name="gadgetId">The gadget id.</param>
[GadgetAction(TextResourceKey = "Edit", ResourceType = typeof(EPiServer.Shell.UI.Views.Shared.SharedResources))]
public ActionResult Configure(Guid gadgetId)
{
Settings rssSettings = LoadSettings(gadgetId);
return View(rssSettings);
}
Multiple languages
When it comes to translating the UI screens of your gadgets you are free to use the technology you prefer. The EPiServer CMS lang model or ASP.NET local resources are two options.
For translating the gadget names you will need to instruct the dashboard on how to retrieve the localized text. This is done in the gadget attribute:
[Gadget(Name = "RSS Feed Reader", ClientScriptInitMethod = "epi.rssReader.init", ResourceType = typeof(RssResources), NameResourceKey = "Title")]
This will instruct the dashboard to look for a static property named Title on the RssResources class. One way to generate this property is using the resx designer in Visual Studio.
Checklist: Playing nice on the dashboard
Making a gadget means sharing a common workspace with others. Take a moment to review this list before publishing your gadget to a wider audience:
- “Namespace” your CSS classes
- Namespace and encapsulate your JavaScript methods to avoid polluting global namespace
- Don’t override other gadget’s styles
- Don’t assume other gadgets will stay the same
- Never assume there is only one gadget of your kind (affects element id:s)
- Prefer documented CSS classes for a consistent look and feel over time
- Avoid long-running operation (such as reports or RSS operations) from your default action