This document discusses how to create scheduled jobs in EPiServer to export usage reports to JSON format. It describes creating a class that inherits from JobBase and is decorated with the ScheduledPlugIn attribute. This class contains code to get usage reports, serialize them to JSON using Newtonsoft.Json, compress the JSON into a zip file using DotNetZip, save it as a MediaData object, and return a success message. Dependencies are also added to the NuGet package.
1. EPiServer Scheduled Jobs
In my previous entry on Creating a episerver package I turned some EPiServer reports into
a nugget package. Now I want to allow the export this data in a format that can be reused, in
this case JSON.
To do this I’m going to create a Scheduled Jobs, which are simple classes that inherit from
JobBase and are decorated with the ScheduledPlugIn attribute.
[ScheduledPlugIn(DisplayName = "Usage Report Collection Job",
Description = "A exports of usage reports in Json”.
SortIndex = 10001)]
public class UsageReportCollectionJob : JobBase
{
public override string Execute()
{
Once we’ve create out class we can place code we wish to execute inside the overridden
Execute method.
2. Create JSON
Before we can create the JSON, we need to install a serialize. However while we do have
multiple options, Newtonsoft’s Json.Net is the sensible choice as it’s already used in
EPiServer. However, we do need to be careful what version we install. For CMS 7.5 and we
can use anything from version 6 but less that version 8.
Install-Package Newtonsoft.Json -Version 6.0.1
Previously I refactor all my reports into a separate service layer, which give me the ability to
call these reports without separately from the ASPX page.
var contentUsage = UsageReportsService.GetContentTypesUsage();
var contentUsageJson = JsonConvert.SerializeObject(contentUsage,
Formatting.Indented)
This means I can call GetContentTypesUsage and retrieve a list of objects, which can be
passed to Json.Net for serialization into JSON. I’ve also chosen to include the
Formatting.Indented, this will increase the readability but at expense of size.
3. Compressing JSON files
While JSON is a more efficient than XML bu it will still benefit from compression. Additional
it will act as a container for multiple files. Again I’ve chosen to use the same compression
library as EPiServer, in this case DotNetZip.
PM> Install-Package DotNetZip -Version 1.9.1.8
DotNetZip allows you to directly add content, with the AddEntry method, allowing us to avoid
the creation a temporary file.
ZipFile loanZip = new ZipFile();
loanZip.AddEntry("content-usage-report.json", contentUsage);
It’s also possible to combine previous steps into one, this is the preferred approach as we’re
no longer creating unnecessary objects.
loanZip.AddEntry("content-usage-report.json",
JsonConvert.SerializeObject(contentUsage,
Formatting.Indented),
Encoding.UTF8);
4. Zip Content Data
Before we can save our file we need to create a new MediaData object, the base class for
any file type stored inside EPiServer. However, it’s our responsibility to create new class for
each file type we wish to store.
[ContentType(GUID = "{1BDDB51F-83AA-4D4B-8664-E40AE58DF2C6}")]
[MediaDescriptor(ExtensionString = ".zip")]
public class ZippedFile : MediaData
{
public virtual string Description { get; set; }
}
The instance of ZippedFile class we’ve created is used an associate with our physical zip file
and can also contain metadata.
var report = contentRepository.GetDefault<ZippedFile>(assetRoot);
report.Name = "content-usage-report.json";
report.Description = "A zipped collection of usage reports";
This approach is similar to that used to store Pages and Blocks and provides a useful
abstraction over the under lying technology.
5. Save the Zip
Now we have the content reference we can write our zip file to it. This is done by creating a
BLOB or Binary Large Object. The blob can then be passes to our zip library via a stream.
The advantage of using BLOB’s is we’re no longer tied to a file system. We could for instance
use Microsoft Azure or Amazon S3 Storage.
var blob = blobFactory.CreateBlob(report.BinaryDataContainer, ".zip");
var stream = blob.OpenWrite();
loanZip.Save(stream);
The final step is to associate the saved Blob with our zip content and then save publish.
Finally, I’m return a message to say the reports has been created and included a URL.
newReport.BinaryData = blob;
var reference = contentRepository.Save(newReport, SaveAction.Publish);
return $"Report Completed <a
href='{urlResolver.GetUrl(reference)}'>Usage Report</a>";
My finial code does differ slightly, for instance I’ve introduced some feature, like name the
report by date and replace previous versions. However these changes don’t alter anything
fundamental, but fill free to check out my code at bit.ly/1PiwIIi
6. Update Nuspec
The next setup is add the additional dependencies, into the package.nuspec, for JSON.Net
and DotNetZip.
<dependencies>
<group targetFramework="net40
<dependency id="Newtonsoft.Json" version="[6.0.1,8)" />
<dependency id="DotNetZip" version="[1.9.1.8, 2)"/>
<dependency id="log4net" version="1.2.10" />
<dependency id="EPiServer.CMS.Core" version="[7.6,9)" />
</group>
</dependencies>
While this step isn’t strictly necessary as we know the EPiServer use these packages, it’s
good practise to included them. As it’s possible that in future release they may be replaced.
Update this package, is a simple as it’s versioned, however it’s vital to check against the
different version of EPiServer. As major release will introduce breaking changes.
7. Run Job Manually
Currently I’m running version 8, but compiling against version 7.6, so this is a real test. So
all I need to do is run this Job it manual. This is possible via the admin screen.
Unfortunately, I’m seeing a error. Which after some research I’ve found is due to changes
to the IContentRepository in version 8. The change was to replace the ILanguageSelector
with a CultureInfo as the methods for selecting the preferred language branch.
8. Fix Error
The solution is simple to release multiple packages targeting at the different versions of
EPiServer. First I’ll create a new branch for each version I require.
Then update the EPiServer to packge, whilst not forgetting to update the nuspec as well.
PM> Update-Package EPiServer.CMS.UI.Core -Version 8.0.0
9. Conclusion
Scheduled Jobs are the first resort for any long running or repeating tasks. With full access
to EPiServer like page, blocks and files. Alternatively, you can use execute other services
like email or even micro services. Finally, you have fine grain control over when this Job
executes from seconds to years.
Next I’ll be bringing this series of entries to a close buy creating something useful with the
JSON.
Additional Resources
http://world.episerver.com/Documentation/Items/Developers-Guide/EPiServer-
CMS/75/Scheduled-jobs/Scheduled-jobs/
http://world.episerver.com/documentation/Items/Developers-Guide/EPiServer-
CMS/8/BLOB-providers/BLOB-storage-and-BLOB-providers/
http://tedgustaf.com/blog/2008/8/create-a-scheduled-job-in-episerver/