Last active
September 3, 2018 13:12
-
-
Save AThraen/77b856633ff90489b4c46cd9095e45f7 to your computer and use it in GitHub Desktop.
Episerver scheduled job to publish site to Azure Storage Static Websites
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using EPiServer.Core; | |
| using EPiServer.PlugIn; | |
| using EPiServer.Scheduler; | |
| using Microsoft.WindowsAzure.Storage; | |
| using Microsoft.WindowsAzure.Storage.Blob; | |
| using EPiServer; | |
| using EPiServer.ServiceLocation; | |
| using EPiServer.Web.Routing; | |
| using System.Net; | |
| using System.Web.Hosting; | |
| using System.IO; | |
| using System.Web; | |
| using System.Collections.Generic; | |
| using EPiServer.DataAbstraction; | |
| using System.Web.Configuration; | |
| namespace StaticAlloy.StaticSiteGenerator | |
| { | |
| [ScheduledPlugIn(DisplayName = "Generate Static Site")] | |
| public class StaticGeneratorJob : ScheduledJobBase | |
| { | |
| public const string DEFAULTFILENAME = "index.html"; | |
| private bool _stopSignaled; | |
| /// <summary> | |
| /// Called when a user clicks on Stop for a manually started job, or when ASP.NET shuts down. | |
| /// </summary> | |
| public override void Stop() | |
| { | |
| _stopSignaled = true; | |
| } | |
| public StaticGeneratorJob(IContentLoader loader, ContentAssetHelper assethelper, ILanguageBranchRepository languagerepo) | |
| { | |
| _loader = loader; | |
| _assethelper = assethelper; | |
| _languagerepo = languagerepo; | |
| IsStoppable = true; | |
| } | |
| protected CloudStorageAccount account; | |
| protected CloudBlobContainer container; | |
| protected IContentLoader _loader; | |
| protected ContentAssetHelper _assethelper; | |
| protected ILanguageBranchRepository _languagerepo; | |
| protected int TraverseSite(ContentReference n, string language) | |
| { | |
| int cnt = 0; | |
| var u = UrlResolver.Current.GetUrl(n,language); | |
| //Url is null if it's not url adressable (for example block or folder) | |
| if (u != null) | |
| { | |
| var uri = new Uri(u); | |
| var rel = uri.AbsolutePath; | |
| OnStatusChanged(String.Format("Fetching {0}", rel)); | |
| try | |
| { | |
| WebClient wc = new WebClient(); | |
| var data = wc.DownloadData(u); | |
| var name = rel.TrimStart('/'); | |
| if (name.EndsWith("/")) name = name + DEFAULTFILENAME; | |
| var blob = container.GetBlockBlobReference(name); | |
| blob.Properties.ContentType = wc.ResponseHeaders[HttpResponseHeader.ContentType]; | |
| blob.Properties.ContentEncoding = wc.ResponseHeaders[HttpResponseHeader.ContentEncoding]; | |
| blob.Properties.CacheControl = wc.ResponseHeaders[HttpResponseHeader.CacheControl]; | |
| blob.UploadFromByteArray(data, 0, data.Length); | |
| blob.SetProperties(); | |
| cnt++; | |
| } | |
| catch | |
| { | |
| //TODO: Log error | |
| } | |
| } | |
| //Get Content Assets recursively | |
| var l = _assethelper.GetAssetFolder(n); | |
| if (l != null) | |
| { | |
| foreach (var a in _loader.GetDescendents(l.ContentLink)) | |
| { | |
| cnt += TraverseSite(a,language); | |
| } | |
| } | |
| return cnt; | |
| } | |
| public static string[] GetFiles(string path, string searchPattern, SearchOption searchOption) | |
| { | |
| string[] searchPatterns = searchPattern.Split('|'); | |
| List<string> files = new List<string>(); | |
| foreach (string sp in searchPatterns) | |
| files.AddRange(System.IO.Directory.GetFiles(path, sp, searchOption)); | |
| files.Sort(); | |
| return files.ToArray(); | |
| } | |
| public int TraverseFiles(string basefolder,string folder, string pattern, bool recursive) | |
| { | |
| int cnt = 0; | |
| foreach(var f in GetFiles(Path.Combine(basefolder,folder), pattern, (recursive)? SearchOption.AllDirectories:SearchOption.TopDirectoryOnly)) | |
| { | |
| string rel = f.Replace(basefolder, ""); | |
| OnStatusChanged(String.Format("Uploading {0}", rel)); | |
| var blob=container.GetBlockBlobReference(rel); | |
| var mime=MimeMapping.GetMimeMapping(Path.GetFileName(f)); | |
| blob.Properties.ContentType = mime; | |
| blob.UploadFromFile(f); | |
| blob.SetProperties(); | |
| cnt++; | |
| } | |
| return cnt; | |
| } | |
| /// <summary> | |
| /// Called when a scheduled job executes | |
| /// </summary> | |
| /// <returns>A status message to be stored in the database log and visible from admin mode</returns> | |
| public override string Execute() | |
| { | |
| //Call OnStatusChanged to periodically notify progress of job for manually started jobs | |
| OnStatusChanged(String.Format("Starting execution of {0}", this.GetType())); | |
| //Configure Blog storage | |
| account = CloudStorageAccount.Parse(WebConfigurationManager.AppSettings["StaticStorage"]); | |
| container = account.CreateCloudBlobClient().GetContainerReference("$web"); | |
| //Traverse content | |
| int cnt = 0; | |
| foreach (var b in _languagerepo.ListEnabled()) | |
| { | |
| List<ContentReference> lst = new List<ContentReference>(); | |
| lst.Add(ContentReference.StartPage); | |
| lst.AddRange(_loader.GetDescendents(ContentReference.StartPage)); | |
| lst.Add(ContentReference.SiteBlockFolder); | |
| lst.AddRange(_loader.GetDescendents(ContentReference.SiteBlockFolder)); | |
| foreach (var n in lst) | |
| { | |
| cnt += TraverseSite(n, b.LanguageID); | |
| } | |
| } | |
| //Traverse static files and folders | |
| var rootPath = HostingEnvironment.MapPath("~/"); | |
| cnt += TraverseFiles(rootPath, "", "*.txt|*.ico", false); | |
| cnt += TraverseFiles(rootPath, "Static", "*.css|*.js|*.png|*.gif|*.jpg|*.mp4|*.htm|*.html", true); | |
| //For long running jobs periodically check if stop is signaled and if so stop execution | |
| if (_stopSignaled) | |
| { | |
| return "Stop of job was called"; | |
| } | |
| return string.Format("Moved {0} items to static web site storage",cnt); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment