Wednesday, December 6, 2017

Sitecore's Jobs.aspx Admin Page for Sitecore v6.6 to v7.1


Up until the release of Sitecore 7.2 Update-6 Sitecore was missing an out-of-the-box Jobs Viewer tool - which resulted in community developers rolling their own and sharing to the rest of us.

Here are links to some of the community-driven implementations:

https://www.geekhive.com/buzz/post/2015/04/sitecore-job-viewer/

https://briancaos.wordpress.com/2014/11/11/sitecore-job-viewer-see-what-sitecore-is-doing-behind-your-back/ 

https://marketplace.sitecore.net/en/Modules/V/View_Sitecore_Jobs.aspx 

https://sitecoreblog.marklowe.ch/2014/06/view-running-sitecore-background-jobs/ 

One feature that separated Sitecore's Jobs.aspx page from the community-driven implementations was its ability to auto-refresh and essentially view jobs running in real-time without the need for a refresh button. 

It also looked very nice! :)

I wanted to use THIS Jobs.aspx page on older versions of Sitecore I still maintained, so I started decompiling the Sitecore.Kernel, SitecoreClient, and Sitecore.ExperienceContentManagement.Administration binaries from v8.1 in an attempt to consolidate all the code into one Jobs.aspx page - no additional dll required.

Here's the result:

  <%@ Page language="c#" EnableEventValidation="false" AutoEventWireup="true" Inherits="Sitecore.sitecore.admin.AdminPage" %>   
  <script runat="server">   
   protected override void OnInit(EventArgs e)   
   {   
   base.CheckSecurity(true); //Required!   
   base.OnInit(e);   
   }   
  void Page_Load(object sender, System.EventArgs e)   
  {   
       Sitecore.Jobs.JobManager.GetJobs();   
     StringBuilder stringBuilder = new StringBuilder();   
     Type type = typeof(Sitecore.Jobs.JobManager);   
     this.ShowRefreshStatus(stringBuilder);   
     System.Reflection.FieldInfo field = type.GetField("_runningJobs", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);   
     if (field != null)   
     {   
      this.ShowJobs(stringBuilder, "Running jobs", ((Sitecore.Collections.SafeDictionary<Sitecore.Handle, Sitecore.Jobs.Job>)field.GetValue(null)).Values.ToArray<Sitecore.Jobs.Job>());   
     }   
     System.Reflection.FieldInfo fieldInfo = type.GetField("_queuedJobs", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);   
     if (fieldInfo != null)   
     {   
      this.ShowJobs(stringBuilder, "Queued jobs", ((Sitecore.Collections.JobCollection)fieldInfo.GetValue(null)).ToArray<Sitecore.Jobs.Job>());   
     }   
     System.Reflection.FieldInfo field1 = type.GetField("_finishedJobs", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);   
     if (field1 != null)   
     {   
      this.ShowJobs(stringBuilder, "Finished jobs", ((Sitecore.Collections.JobCollection)field1.GetValue(null)).Reverse<Sitecore.Jobs.Job>().ToArray<Sitecore.Jobs.Job>());   
     }   
     this.lt.Text = stringBuilder.ToString();   
  }   
  protected virtual void ShowJobs(StringBuilder stringBuilder, string name, ICollection<Sitecore.Jobs.Job> enumerable)   
    {   
     stringBuilder.AppendLine(string.Concat("<h1>", name, ":</h1><br />"));   
     if (enumerable.Count <= 0)   
     {   
      stringBuilder.AppendLine("<b>No jobs</b><br />");   
     }   
     else   
     {   
      stringBuilder.AppendLine("<table class='jobs-table'>");   
      stringBuilder.AppendLine("<thead><tr><td class='counter'>No</td><td class='add-time'>Added</td><td class='title'>Title</td><td class='progress'>Progress</td><td class='priority'>Priority</td></tr></thead>");   
      int num = 1;   
      foreach (Sitecore.Jobs.Job job in enumerable)   
      {   
       long total = job.Status.Total;   
       TimeSpan localTime = TimeSpan.Zero;   
       string str = (localTime.Hours == 0 ? string.Empty : string.Concat(localTime.Hours, "h "));   
       string str1 = (localTime.Minutes == 0 ? string.Empty : string.Concat(localTime.Minutes, "m "));   
       stringBuilder.AppendLine("<tr>");   
       stringBuilder.AppendLine(string.Concat("<td class='counter'>", num, "</td>"));   
       object[] longTimeString = new object[] { "<td class='add-time'>", null, null, null, null, null, null };   
       DateTime dateTime = job.QueueTime.ToLocalTime();   
       longTimeString[1] = dateTime.ToLongTimeString();   
       longTimeString[2] = " (";   
       longTimeString[3] = str;   
       longTimeString[4] = str1;   
       longTimeString[5] = localTime.Seconds;   
       longTimeString[6] = "s ago)</td>";   
       stringBuilder.AppendLine(string.Concat(longTimeString));   
       stringBuilder.AppendLine(string.Concat("<td class='title'>", job.Name, "</td>"));   
       StringBuilder stringBuilder1 = stringBuilder;   
       object[] processed = new object[] { "<td class='progress'>", job.Status.Processed   
              , null, null };   
       processed[2] = (total > (long)0 ? string.Concat(" of ", total) : string.Empty);   
       processed[3] = "</td>";   
       stringBuilder1.AppendLine(string.Concat(processed));   
       stringBuilder.AppendLine(string.Concat("<td class='priority'>", job.Options.Priority, "</td>"));   
       stringBuilder.AppendLine("</tr>");   
       num++;   
      }   
      stringBuilder.AppendLine("</table>");   
     }   
     stringBuilder.AppendLine("<br /><hr />");   
    }   
    protected virtual void ShowRefreshStatus(StringBuilder stringBuilder)   
    {   
     int num;   
     string str;   
     string item = base.Request.QueryString["refresh"];   
     int.TryParse(item, out num);   
     object[] objArray = new object[1];   
     DateTime now = DateTime.Now;   
     objArray[0] = now.ToString(System.Globalization.CultureInfo.InvariantCulture);   
     stringBuilder.Append(Sitecore.StringExtensions.StringExtensions.FormatWith("Last updated: {0}. ", objArray));   
     int[] numArray = new int[] { 1, 2, 5, 10, 20, 30, 60 };   
     stringBuilder.Append(string.Format("Refresh each <a href='jobs.aspx' class='refresh-link {0}'>No Refresh</a>", (num == 0 ? "refresh-selected" : string.Empty)));   
     int[] numArray1 = numArray;   
     for (int i = 0; i < (int)numArray1.Length; i++)   
     {   
      int num1 = numArray1[i];   
      str = (num == num1 ? "refresh-selected" : string.Empty);   
      string str1 = string.Format(", <a href='jobs.aspx?refresh={0}' class='refresh-link {1}'>{0} sec</a>", num1, str);   
      stringBuilder.Append(str1);   
     }   
     stringBuilder.Append("<br /><br />");   
    }   
  </script>    
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >   
  <html xmlns="http://www.w3.org/1999/xhtml">   
   <head runat="server">   
    <title>Jobs Viewer</title>   
    <link rel="Stylesheet" type="text/css" href="/sitecore/shell/themes/standard/default/WebFramework.css" />   
    <link rel="Stylesheet" type="text/css" href="./default.css" />   
    <style type="text/css">   
     .jobs-table {   
      border: solid 1px grey;    
      border-spacing: 2px;   
      border-collapse: separate;   
      width: 100%;   
     }   
     .jobs-table td {   
      padding: 2px;   
     }   
     .jobs-table thead {   
      font-weight: bold;   
     }   
     .jobs-table .counter {   
      width: 25px;   
      text-align: right;   
     }     
     .jobs-table .add-time {   
      width: 150px;   
     }     
     .jobs-table .title {   
      word-break: break-all;   
     }    
     .jobs-table .progress {   
      width: 50px;   
      text-align: center;   
     }    
     .jobs-table .priority {   
      width: 80px;   
     }        
    </style>   
   </head>   
   <body>   
    <form id="Form1" runat="server" class="wf-container">   
     <div class="wf-content">   
      <h1>   
       <a href="/sitecore/admin/">Administration Tools</a> - Jobs Viewer   
      </h1>   
      <br />   
      <asp:Literal runat="server" ID="lt"></asp:Literal>   
      <script type="text/javascript">   
       function getQueryString() {   
        var result = {}, queryString = location.search.substring(1), re = /([^&=]+)=([^&]*)/g, m;   
        while (m = re.exec(queryString)) {   
         result[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);   
        }   
        return result;   
       }   
       var str = getQueryString()["refresh"];   
       if (str != undefined) {   
        c = parseInt(str) * 1000;   
        setTimeout("document.location.href = document.location.href;", c);   
       }   
      </script>   
     </div>   
    </form>   
   </body>   
  </html>   

Here is the Sitecore's Jobs Viewer admin tool working on a clean Sitecore 7.0 site:


Simply copy the code above into a new Jobs.aspx file and drop it into your site's /sitecore/admin folder.

I've confirmed this working on versions as far back as Sitecore versions 6.6.

Enjoy!

0 comments:

Post a Comment