HomeGuidesAPI Reference
Submit Documentation FeedbackJoin Developer CommunityOptimizely GitHubOptimizely NuGetLog In

Reports

The report extensibility that is described in this topic is WebForm-based and only applies to Optimizely Content Management System (CMS) versions 11 and 10.

@model ExistingPagesReportViewModel
     
    @using EPiServer.DataAbstraction
    @using EPiServer.Framework.Web.Resources
     
    @{
      Layout = null;
    }
     
    <!DOCTYPE html>
     
    <html>
    <head>
      <title>@ViewBag.Title</title>
      <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    
      <!-- Shell -->
      @Html.Raw(ClientResources.RenderResources("ShellCore"))
    
      <!-- LightTheme -->
      @Html.Raw(ClientResources.RenderResources("ShellCoreLightTheme"))
     
      <link href="/EPiServer/CMS/App_Themes/Default/Styles/system.css" type="text/css" rel="stylesheet">
      <link href="/EPiServer/CMS/App_Themes/Default/Styles/ToolButton.css" type="text/css" rel="stylesheet">
    </head>
    <body>
      @Html.Raw(Html.ShellInitializationScript())
     
      <div class="epi-contentContainer epi-padding">
        <div class="epi-contentArea">
          <div class="EP-systemImage" style="background-image: url('/App_Themes/Default/Images/ReportCenter/PublishedPages.gif');">
            <h1 class="EP-prefix">
              Existing Pages
            </h1>
            <p class="EP-systemInfo">
              This report displays pages that exists on the site.
            </p>
          </div>
          <div id="FullRegion_ValidationSummary" class="EP-validationSummary" style="color: Black; display: none;">
          </div>
        </div>
            
        @using (Html.BeginForm("ListPages", "ExistingPagesReport", FormMethod.Post))
        {
          <script src="/Util/javascript/episerverscriptmanager.js" type="text/javascript"></script>
          <script src="/EPiServer/CMS/javascript/system.js" type="text/javascript"></script>
          <script src="/EPiServer/CMS/javascript/dialog.js" type="text/javascript"></script>
          <script src="/EPiServer/CMS/javascript/system.aspx" type="text/javascript"></script>
     
          <input type="hidden" id="doExport" name="doExport" value="False">
          <div class="epi-formArea">
            <fieldset>
              <legend>
                Report Criteria
              </legend>
              <div class="epi-size10">
                <label for="pageTypes">
                  Select PageType
                </label>
                <select name="pageType" id="pageType">
                  @foreach (var type in Model.PageTypes.Where(w => w.ID != 1).OrderBy(o => o.Name))
                  {
                    <option value="@type.ID" 
                      @(type.ID.ToString() == Model.SelectedPageType 
                      ? "selected=selected" : "") >
                      @type.Name
                    </option>
                  }
                </select>
              </div>
            </fieldset>
       
            <div class="epitoolbuttonrow">
              <span class="epi-cmsButton">
                <input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-Report" 
                       type="submit" 
                       name="showReport" 
                       id="showReport" 
                       value="Show Report" 
                       onmouseover="EPi.ToolButton.MouseDownHandler(this)" 
                       onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
              </span>
              <span class="epi-cmsButton">
                <input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-Report" 
                       type="submit" 
                       name="exportReport" 
                       id="exportReport" 
                       value="Export Report" 
                       onmouseover="EPi.ToolButton.MouseDownHandler(this)" 
                       onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
              </span>
            </div>
          </div>
        }
     
        @if (Model.Pages != null && Model.Pages.Count > 0)
        {
          <div class="epi-floatLeft epi-marginVertical-small">
            Number of Hits: @Model.Pages.Count
          </div>
          <div class="epi-contentArea epi-clear">
            <div>
              <table class="epi-default epi-default-legacy" 
                     cellspacing="0" 
                     id="FullRegion_MainRegion_ReportView" 
                     style="border-style: None; width: 100%; border-collapse: collapse;">
                <tr>
                  <th scope="col">Page Id</th>
                  <th scope="col">Page Name</th>
                  <th scope="col">Page Url</th>
                  <th scope="col">Published Date</th>
                </tr>
                @foreach (var page in Model.Pages)
                {
                  <tr>
                    <td style="width: 27%;">@page.ContentLink.ID</td>
                    <td>@page.PageName</td>
                    <td>@Url.ContentUrl(page.ContentLink)</td>
                    <td>@(page.StartPublish.HasValue ? page.StartPublish.Value.ToString("yyyy-MM-dd HH:mm") : "Not published")</td>
                  </tr>
                }
              </table>
            </div>
          </div>
        }
      </div>
      <script type="text/javascript">
        document.getElementById("exportReport").onclick = function () 
        {
          document.getElementById("doExport").value = "True";
        };
        document.getElementById("showReport").onclick = function () 
        {
          document.getElementById("doExport").value = "False";
        };
      </script>
    </body>
    </html>

(Thanks to Henrik Fransas at NetRelations for this example.)

In Optimizely you can create custom reports and use the built-in reports in the admin view. The following example shows how to create a custom report of existing pages on a website and how to export the report to Excel using EPPlus.

  1. Start by creating a Controller that looks like this:
namespace AlloyExample.Controllers
        {
          [EPiServer.PlugIn.GuiPlugIn(
            Area = EPiServer.PlugIn.PlugInArea.ReportMenu, 
            Url = "~/existingpagesreport",
            Category = "Existing Pages",
            DisplayName = "Pages By PageType")]
          [Authorize(Roles = "Administrators, WebAdmins")]
          public class ExistingPagesReportController : Controller
          {
            public ActionResult Index()
            {
              return View();
            }
          }
        }
This controller is a GuiPlugin which is shown in the report menu and uses the URL */existingpagesreport*. The controller is protected so you have to be part of the administrator group to use it.
  1. For the URL to work, add a route to it in global.asax.cs:
protected override void RegisterRoutes(RouteCollection routes)
        {
          base.RegisterRoutes(routes);
          routes.MapRoute(
            "ExistingPagesReport",
            "existingpagesreport/{action}",
            new { controller = "ExistingPagesReport", action = "Index" });
        }
3. Creat

e a simple view and make sure it shows up in the report center.

  1. Add a ViewModel with the necessary properties:
public class ExistingPagesReportViewModel
        {
          public IEnumerable<PageType> PageTypes { get; set; }
          public PageDataCollection Pages { get; set; }
          public string SelectedPageType { get; set; }
        }
  1. Create a helper class to make a request against Optimizely like this:
public static class ExistingPagesHelper
        {
          public static IEnumerable<PageType> GetAllPageTypes()
          {
            var contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
            return contentTypeRepository.List().OfType<PageType>();
          }
         
          public static void SetPagesForPageTypeName(ExistingPagesReportViewModel model)
          {
            var criterias = new PropertyCriteriaCollection();
            var criteria = new PropertyCriteria();
            criteria.Condition = CompareCondition.Equal;
            criteria.Name = "PageTypeID";
            criteria.Type = PropertyDataType.PageType;
            criteria.Value = model.SelectedPageType;
            criteria.Required = true;
            criterias.Add(criteria);
            var pages = DataFactory.Instance.FindPagesWithCriteria(ContentReference.RootPage, criterias);
            model.Pages = pages;
          }
        }
  1. Update your index action to create an instance of the View model and assign all page types to it:
public ActionResult Index()
        {
          var model = new ExistingPagesReportViewModel 
          { 
            PageTypes = ExistingPagesHelper.GetAllPageTypes() 
          };
          return View(model);
        }
  1. Create a view and add Optimizely's CSS and JavaScript to it to have the same look-and-feel as other built-in reports in Optimizely. The complete view looks like this:
@model ExistingPagesReportViewModel
         
        @using EPiServer.DataAbstraction
        @using EPiServer.Framework.Web.Resources
         
        @{
            Layout = null;
        }
         
        <!DOCTYPE html>
         
        <html>
        <head>
          <title>@ViewBag.Title</title>
          <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
          <!-- Shell -->
          @Html.Raw(ClientResources.RenderResources("ShellCore"))
          <!-- LightTheme -->
          @Html.Raw(ClientResources.RenderResources("ShellCoreLightTheme"))
         
          <link href="/EPiServer/CMS/App_Themes/Default/Styles/system.css" type="text/css" rel="stylesheet">
          <link href="/EPiServer/CMS/App_Themes/Default/Styles/ToolButton.css" type="text/css" rel="stylesheet">
        </head>
        <body>
          @Html.Raw(Html.ShellInitializationScript())
         
          <div class="epi-contentContainer epi-padding">
            <div class="epi-contentArea">
              <div class="EP-systemImage" style="background-image: url('/App_Themes/Default/Images/ReportCenter/PublishedPages.gif');">
                <h1 class="EP-prefix">
                  Existing Pages
                </h1>
                <p class="EP-systemInfo">
                  This report displays pages that exists on the site.
                </p>
              </div>
              <div id="FullRegion_ValidationSummary" class="EP-validationSummary" style="color: Black; display: none;">
              </div>
            </div>
        
            @using (Html.BeginForm("ListPages", "ExistingPagesReport", FormMethod.Post))
            {
              <script src="/Util/javascript/episerverscriptmanager.js" type="text/javascript"></script>
              <script src="/EPiServer/CMS/javascript/system.js" type="text/javascript"></script>
              <script src="/EPiServer/CMS/javascript/dialog.js" type="text/javascript"></script>
              <script src="/EPiServer/CMS/javascript/system.aspx" type="text/javascript"></script>
         
              <input type="hidden" 
                     id="doExport" 
                     name="doExport" 
                     value="False">
              <div class="epi-formArea">
                <fieldset>
                  <legend>
                    Report Criteria
                  </legend>
                  <div class="epi-size10">
                    <label for="pageTypes">Select PageType</label>
                    <select name="pageType" id="pageType">
                      @foreach (var type in Model.PageTypes.Where(w => w.ID != 1).OrderBy(o => o.Name))
                      {
                        <option value="@type.ID" 
                          @(type.ID.ToString() == Model.SelectedPageType ? "selected=selected" : "") >
                          @type.Name
                        </option>
                      }
                    </select>
                  </div>
                </fieldset>
                
                <div class="epitoolbuttonrow">
                  <span class="epi-cmsButton">
                    <input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-Report" 
                           type="submit" 
                           name="showReport" 
                           id="showReport" 
                           value="Show Report" 
                           onmouseover="EPi.ToolButton.MouseDownHandler(this)" 
                           onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
                  </span>
                  <span class="epi-cmsButton">
                    <input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-Report" 
                           type="submit" 
                           name="exportReport" 
                           id="exportReport" 
                           value="Export Report" 
                           onmouseover="EPi.ToolButton.MouseDownHandler(this)" 
                           onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
                  </span>
                </div>
              </div>
            }
         
            @if (Model.Pages != null && Model.Pages.Count > 0)
            {
              <div class="epi-floatLeft epi-marginVertical-small">Number of Hits: @Model.Pages.Count</div>
              <div class="epi-contentArea epi-clear">
                <div>
                  <table class="epi-default epi-default-legacy" 
                    cellspacing="0" 
                    id="FullRegion_MainRegion_ReportView" 
                    style="border-style: None; width: 100%; border-collapse: collapse;">
                    <tr>
                      <th scope="col">Page Id</th>
                      <th scope="col">Page Name</th>
                      <th scope="col">Page Url</th>
                      <th scope="col">Published Date</th>
                    </tr>
                    @foreach (var page in Model.Pages)
                    {
                      <tr>
                        <td style="width: 27%;">@page.ContentLink.ID</td>
                        <td>@page.PageName</td>
                        <td>@Url.ContentUrl(page.ContentLink)</td>
                        <td>@(page.StartPublish.HasValue ? page.StartPublish.Value.ToString("yyyy-MM-dd HH:mm") : "Not published")</td>
                      </tr>
                    }
                  </table>
                </div>
              </div>
            }
          </div>
          <script type="text/javascript">
            document.getElementById("exportReport").onclick = function () 
            {
              document.getElementById("doExport").value = "True";
            };
            document.getElementById("showReport").onclick = function () 
            {
              document.getElementById("doExport").value = "False";
            };
          </script>
        </body>
        </html>
This code has two **Submit** buttons but only one form action; the JavaScript function connected to the click event on the export and search submit buttons updates a hidden value telling the controller to do an export of the data or not.

The action in the controller that handles this looks like this:
[HttpPost]
        public ActionResult ListPages(FormCollection form)
        {
          var model = new ExistingPagesReportViewModel
          {
            PageTypes = ExistingPagesHelper.GetAllPageTypes(),
            SelectedPageType = form["pageType"]
          };
         
          ExistingPagesHelper.SetPagesForPageTypeName(model);
          
          var doExport = false;
         
          if (bool.TryParse(form["doExport"], out doExport) && doExport && model.Pages != null && model.Pages.Count > 0)
          {
            Export(model.Pages, System.Web.HttpContext.Current.Response);
          }
        
          return View("Index", model);
        }
It returns the view if the export values are not **true**.
  1. To export the report to Excel, use EPPlus and create a function in the same class like this:
public void Export(PageDataCollection pagesToExport, HttpResponse response)
        {
          using (var package = new ExcelPackage())
          {
            ExcelWorksheet ws = package.Workbook.Worksheets.Add("pages");
         
            ws.Cells[1, 1].Value = "PageId";
            ws.Cells[1, 2].Value = "PageName";
            ws.Cells[1, 3].Value = "PageUrl";
            ws.Cells[1, 4].Value = "Published Date";
         
            ws.Row(1).Style.Font.Bold = true;
            ws.Row(1).Style.Locked = true;
         
            int row = 2;
         
            foreach (var page in pagesToExport)
            {
              ws.Cells[row, 1].Value = page.ContentLink.ID;
              ws.Cells[row, 2].Value = page.PageName;
              ws.Cells[row, 3].Value = Url.ContentUrl(page.ContentLink);
              ws.Cells[row, 4].Value = page.StartPublish.HasValue ? page.StartPublish.Value.ToString("yyyy-MM-dd HH:mm") : "Not published";
         
              ++row;
            }
         
            response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            response.AddHeader("content-disposition", string.Format("attachment; filename=pages{0}.xlsx", DateTime.Now.ToString("yyyyMMdd")));
            response.BinaryWrite(package.GetAsByteArray());
            response.Flush();
            response.End();
          }
        }