mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-23 04:43:35 +08:00
Implementing the Warmup module
- Global.asax.cs looks for static pages in ~\App_Data\Warmup - Orchard.Warmup module contains methods to generate those pages based on scheduled times, and content publishing --HG-- branch : dev
This commit is contained in:
@@ -169,6 +169,8 @@
|
||||
<Compile Include="Users\ShellSettingsUtility.cs" />
|
||||
<Compile Include="Values.cs" />
|
||||
<Compile Include="Users\Services\MembershipServiceTests.cs" />
|
||||
<Compile Include="Warmup\WebDownloaderTests.cs" />
|
||||
<Compile Include="Warmup\WarmupUpdaterTests.cs" />
|
||||
<Compile Include="Widgets\RuleEngine\UrlRuleProviderTest.cs" />
|
||||
<Compile Include="Widgets\Services\WidgetsServiceTest.cs" />
|
||||
<Compile Include="Widgets\WidgetsTests.cs" />
|
||||
@@ -254,6 +256,10 @@
|
||||
<Project>{79AED36E-ABD0-4747-93D3-8722B042454B}</Project>
|
||||
<Name>Orchard.Users</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Orchard.Web\Modules\Orchard.WarmUp\Orchard.Warmup.csproj">
|
||||
<Project>{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}</Project>
|
||||
<Name>Orchard.Warmup</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Orchard.Web\Modules\Orchard.Widgets\Orchard.Widgets.csproj">
|
||||
<Project>{194D3CCC-1153-474D-8176-FDE8D7D0D0BD}</Project>
|
||||
<Name>Orchard.Widgets</Name>
|
||||
|
281
src/Orchard.Tests.Modules/Warmup/WarmupUpdaterTests.cs
Normal file
281
src/Orchard.Tests.Modules/Warmup/WarmupUpdaterTests.cs
Normal file
@@ -0,0 +1,281 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Xml;
|
||||
using Autofac;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Environment.Warmup;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.LockFile;
|
||||
using Orchard.Services;
|
||||
using Orchard.Tests.FileSystems.AppData;
|
||||
using Orchard.Tests.Stubs;
|
||||
using Orchard.Tests.UI.Navigation;
|
||||
using Orchard.Warmup.Models;
|
||||
using Orchard.Warmup.Services;
|
||||
|
||||
namespace Orchard.Tests.Modules.Warmup {
|
||||
public class WarmupUpdaterTests {
|
||||
protected IContainer _container;
|
||||
private IWarmupUpdater _warmupUpdater;
|
||||
private IAppDataFolder _appDataFolder;
|
||||
private ILockFileManager _lockFileManager;
|
||||
private StubClock _clock;
|
||||
private Mock<IWebDownloader> _webDownloader;
|
||||
private IOrchardServices _orchardServices;
|
||||
private WarmupSettingsPart _settings;
|
||||
|
||||
private readonly string _basePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
|
||||
private string _warmupFilename, _lockFilename;
|
||||
private const string WarmupFolder = "Warmup";
|
||||
|
||||
[TestFixtureTearDown]
|
||||
public void Clean() {
|
||||
if (Directory.Exists(_basePath)) {
|
||||
Directory.Delete(_basePath, true);
|
||||
}
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
if (Directory.Exists(_basePath)) {
|
||||
Directory.Delete(_basePath, true);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(_basePath);
|
||||
_appDataFolder = AppDataFolderTests.CreateAppDataFolder(_basePath);
|
||||
_webDownloader = new Mock<IWebDownloader>();
|
||||
_orchardServices = new StubOrchardServices();
|
||||
((StubWorkContextAccessor.WorkContextImpl.StubSite) _orchardServices.WorkContext.CurrentSite).BaseUrl = "http://orchardproject.net";
|
||||
|
||||
_settings = new WarmupSettingsPart { Record = new WarmupSettingsPartRecord() };
|
||||
_orchardServices.WorkContext.CurrentSite.ContentItem.Weld(_settings);
|
||||
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterInstance(_appDataFolder).As<IAppDataFolder>();
|
||||
builder.RegisterInstance(_orchardServices).As<IOrchardServices>();
|
||||
builder.RegisterType<DefaultLockFileManager>().As<ILockFileManager>();
|
||||
builder.RegisterType<WarmupUpdater>().As<IWarmupUpdater>();
|
||||
builder.RegisterType<StubClock>().As<IClock>();
|
||||
builder.RegisterInstance(_clock = new StubClock()).As<IClock>();
|
||||
builder.RegisterInstance(_webDownloader.Object).As<IWebDownloader>();
|
||||
_container = builder.Build();
|
||||
|
||||
_lockFileManager = _container.Resolve<ILockFileManager>();
|
||||
_warmupUpdater = _container.Resolve<IWarmupUpdater>();
|
||||
|
||||
_warmupFilename = _appDataFolder.Combine(WarmupFolder, "warmup.txt");
|
||||
_lockFilename = _appDataFolder.Combine(WarmupFolder, "warmup.txt.lock");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldDoNothingWhenNoUrlsAreSpecified() {
|
||||
_warmupUpdater.EnsureGenerate();
|
||||
Assert.That(_appDataFolder.ListFiles(WarmupFolder).Count(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StampFileShouldBeDeletedToForceAnUpdate() {
|
||||
_appDataFolder.CreateFile(_warmupFilename, "");
|
||||
_warmupUpdater.Generate();
|
||||
Assert.That(_appDataFolder.ListFiles(WarmupFolder).Count(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenerateShouldNotRunIfLocked() {
|
||||
_appDataFolder.CreateFile(_warmupFilename, "");
|
||||
ILockFile lockFile = null;
|
||||
_lockFileManager.TryAcquireLock(_lockFilename, ref lockFile);
|
||||
using(lockFile) {
|
||||
_warmupUpdater.Generate();
|
||||
// warmup file + lock file
|
||||
Assert.That(_appDataFolder.ListFiles(WarmupFolder).Count(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
_warmupUpdater.Generate();
|
||||
Assert.That(_appDataFolder.ListFiles(WarmupFolder).Count(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldDownloadConfiguredUrls() {
|
||||
_settings.Urls = @" /
|
||||
/About";
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://orchardproject.net/"))
|
||||
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://orchardproject.net/About"))
|
||||
.Returns(new DownloadResult { Content = "Bar", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_warmupUpdater.Generate();
|
||||
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
|
||||
|
||||
// warmup + content files
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, "warmup.txt")));
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/"))));
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About"))));
|
||||
|
||||
var homepageContent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/")));
|
||||
var aboutcontent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About")));
|
||||
|
||||
Assert.That(homepageContent, Is.EqualTo("Foo"));
|
||||
Assert.That(aboutcontent, Is.EqualTo("Bar"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldCreateFilesForOkStatusOnly() {
|
||||
_settings.Urls = @" /
|
||||
/About";
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://orchardproject.net/"))
|
||||
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://orchardproject.net/About"))
|
||||
.Returns(new DownloadResult { Content = "Bar", StatusCode = HttpStatusCode.NotFound });
|
||||
|
||||
_warmupUpdater.Generate();
|
||||
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
|
||||
|
||||
// warmup + content file
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, "warmup.txt")));
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/"))));
|
||||
Assert.That(files, Has.None.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About"))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldProcessValidRequestsOnly() {
|
||||
_settings.Urls = @" /
|
||||
<>@\\";
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://orchardproject.net/"))
|
||||
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_warmupUpdater.Generate();
|
||||
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
|
||||
|
||||
// warmup + content file
|
||||
Assert.That(files.Count, Is.EqualTo(2));
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, "warmup.txt")));
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/"))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WarmupFileShouldContainUtcNow() {
|
||||
_settings.Urls = @"/";
|
||||
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://orchardproject.net/"))
|
||||
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_warmupUpdater.Generate();
|
||||
|
||||
var warmupContent = _appDataFolder.ReadFile(_warmupFilename);
|
||||
Assert.That(warmupContent, Is.EqualTo(XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldNotProcessIfDelayHasNotExpired() {
|
||||
_settings.Urls = @"/";
|
||||
_settings.Delay = 90;
|
||||
_settings.Scheduled = true;
|
||||
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://orchardproject.net/"))
|
||||
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://orchardproject.net/About"))
|
||||
.Returns(new DownloadResult { Content = "Bar", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_warmupUpdater.Generate();
|
||||
|
||||
var warmupContent = _appDataFolder.ReadFile(_warmupFilename);
|
||||
Assert.That(warmupContent, Is.EqualTo(XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)));
|
||||
|
||||
_settings.Urls = @" /
|
||||
/About";
|
||||
_clock.Advance(TimeSpan.FromMinutes(89));
|
||||
_warmupUpdater.EnsureGenerate();
|
||||
|
||||
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
|
||||
Assert.That(files, Has.None.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About"))));
|
||||
|
||||
warmupContent = _appDataFolder.ReadFile(_warmupFilename);
|
||||
Assert.That(warmupContent, Is.Not.EqualTo(XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldProcessIfDelayHasExpired() {
|
||||
_settings.Urls = @"/";
|
||||
_settings.Delay = 90;
|
||||
_settings.Scheduled = true;
|
||||
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://orchardproject.net/"))
|
||||
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://orchardproject.net/About"))
|
||||
.Returns(new DownloadResult { Content = "Bar", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_warmupUpdater.Generate();
|
||||
|
||||
var warmupContent = _appDataFolder.ReadFile(_warmupFilename);
|
||||
Assert.That(warmupContent, Is.EqualTo(XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)));
|
||||
|
||||
_settings.Urls = @" /
|
||||
/About";
|
||||
_clock.Advance(TimeSpan.FromMinutes(91));
|
||||
_warmupUpdater.EnsureGenerate();
|
||||
|
||||
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About"))));
|
||||
|
||||
warmupContent = _appDataFolder.ReadFile(_warmupFilename);
|
||||
Assert.That(warmupContent, Is.EqualTo(XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldGenerateNonWwwVersions() {
|
||||
_settings.Urls = @" /
|
||||
/About";
|
||||
|
||||
((StubWorkContextAccessor.WorkContextImpl.StubSite)_orchardServices.WorkContext.CurrentSite).BaseUrl = "http://www.orchardproject.net";
|
||||
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://www.orchardproject.net/"))
|
||||
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_webDownloader
|
||||
.Setup(w => w.Download("http://www.orchardproject.net/About"))
|
||||
.Returns(new DownloadResult { Content = "Bar", StatusCode = HttpStatusCode.OK });
|
||||
|
||||
_warmupUpdater.Generate();
|
||||
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
|
||||
|
||||
// warmup + content files
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, "warmup.txt")));
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://www.orchardproject.net/"))));
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://www.orchardproject.net/About"))));
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/"))));
|
||||
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About"))));
|
||||
|
||||
var homepageContent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/")));
|
||||
var aboutcontent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About")));
|
||||
|
||||
var wwwhomepageContent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://www.orchardproject.net/")));
|
||||
var wwwaboutcontent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://www.orchardproject.net/About")));
|
||||
|
||||
Assert.That(homepageContent, Is.EqualTo("Foo"));
|
||||
Assert.That(wwwhomepageContent, Is.EqualTo("Foo"));
|
||||
Assert.That(aboutcontent, Is.EqualTo("Bar"));
|
||||
Assert.That(wwwaboutcontent, Is.EqualTo("Bar"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
37
src/Orchard.Tests.Modules/Warmup/WebDownloaderTests.cs
Normal file
37
src/Orchard.Tests.Modules/Warmup/WebDownloaderTests.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Net;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Warmup.Services;
|
||||
|
||||
namespace Orchard.Tests.Modules.Warmup {
|
||||
public class WebDownloaderTests {
|
||||
private readonly IWebDownloader _webDownloader = new WebDownloader();
|
||||
|
||||
[Test]
|
||||
public void ShouldReturnNullWhenUrlIsEmpty() {
|
||||
Assert.That(_webDownloader.Download(null), Is.Null);
|
||||
Assert.That(_webDownloader.Download(""), Is.Null);
|
||||
Assert.That(_webDownloader.Download(" "), Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldReturnNullWhenUrlIsInvalid() {
|
||||
Assert.That(_webDownloader.Download("froutfrout|yepyep"), Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StatusCodeShouldBe404ForUnexistingResources() {
|
||||
var download = _webDownloader.Download("http://www.microsoft.com/yepyep");
|
||||
Assert.That(download, Is.Not.Null);
|
||||
Assert.That(download.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
|
||||
Assert.That(download.Content, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StatusCodeShouldBe200ForValidRequests() {
|
||||
var download = _webDownloader.Download("http://www.microsoft.com/");
|
||||
Assert.That(download, Is.Not.Null);
|
||||
Assert.That(download.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||
Assert.That(download.Content, Is.Not.Empty);
|
||||
}
|
||||
}
|
||||
}
|
28
src/Orchard.Tests/Environment/WarmUp/WarmUpUtilityTests.cs
Normal file
28
src/Orchard.Tests/Environment/WarmUp/WarmUpUtilityTests.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Environment.Warmup;
|
||||
|
||||
namespace Orchard.Tests.Environment.Warmup {
|
||||
[TestFixture]
|
||||
public class WarmUpUtilityTests {
|
||||
|
||||
[Test]
|
||||
public void EmptyStringsAreNotAllowed() {
|
||||
Assert.Throws<ArgumentException>(() => WarmupUtility.EncodeUrl(""));
|
||||
Assert.Throws<ArgumentException>(() => WarmupUtility.EncodeUrl(null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EncodedUrlsShouldBeValidFilenames() {
|
||||
Assert.That(WarmupUtility.EncodeUrl("http://www.microsoft.com"), Is.EqualTo("http_3A_2F_2Fwww_2Emicrosoft_2Ecom"));
|
||||
Assert.That(WarmupUtility.EncodeUrl("http://www.microsoft.com/foo?bar=baz"), Is.EqualTo("http_3A_2F_2Fwww_2Emicrosoft_2Ecom_2Ffoo_3Fbar_3Dbaz"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EncodedUrlsShouldPreserveQueryStrings() {
|
||||
Assert.That(WarmupUtility.EncodeUrl("http://www.microsoft.com/foo?bar=baz"), Is.StringContaining("bar"));
|
||||
Assert.That(WarmupUtility.EncodeUrl("http://www.microsoft.com/foo?bar=baz"), Is.StringContaining("baz"));
|
||||
Assert.That(WarmupUtility.EncodeUrl("http://www.microsoft.com/foo?bar=baz"), Is.StringContaining("foo"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -239,6 +239,7 @@
|
||||
<Compile Include="Environment\RunningShellTableTests.cs" />
|
||||
<Compile Include="Environment\StubHostEnvironment.cs" />
|
||||
<Compile Include="Environment\Utility\Build.cs" />
|
||||
<Compile Include="Environment\WarmUp\WarmUpUtilityTests.cs" />
|
||||
<Compile Include="FileSystems\AppData\AppDataFolderTests.cs" />
|
||||
<Compile Include="Environment\Configuration\DefaultTenantManagerTests.cs" />
|
||||
<Compile Include="Environment\DefaultCompositionStrategyTests.cs" />
|
||||
|
@@ -71,10 +71,12 @@ namespace Orchard.Tests.Stubs {
|
||||
set { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public int PageSize {
|
||||
public int PageSize{
|
||||
get { throw new NotImplementedException(); }
|
||||
set { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public string BaseUrl { get; set;}
|
||||
}
|
||||
|
||||
public class StubUser : IUser {
|
||||
|
@@ -140,8 +140,15 @@ namespace Orchard.Tests.UI.Navigation {
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
private WorkContext _workContext;
|
||||
public WorkContext WorkContext {
|
||||
get { return new StubWorkContextAccessor(_lifetimeScope).GetContext(); }
|
||||
get {
|
||||
if(_workContext == null) {
|
||||
_workContext = new StubWorkContextAccessor(_lifetimeScope).GetContext();
|
||||
}
|
||||
|
||||
return _workContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -64,27 +64,26 @@ namespace Orchard.Core.Settings.Controllers {
|
||||
var site = _siteService.GetSiteSettings();
|
||||
dynamic model = Services.ContentManager.UpdateEditor(site, this, groupInfoId);
|
||||
|
||||
GroupInfo groupInfo = null;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(groupInfoId)) {
|
||||
if (model == null) {
|
||||
Services.TransactionManager.Cancel();
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
var groupInfo = Services.ContentManager.GetEditorGroupInfo(site, groupInfoId);
|
||||
groupInfo = Services.ContentManager.GetEditorGroupInfo(site, groupInfoId);
|
||||
if (groupInfo == null) {
|
||||
Services.TransactionManager.Cancel();
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
if (!ModelState.IsValid) {
|
||||
Services.TransactionManager.Cancel();
|
||||
model.GroupInfo = groupInfo;
|
||||
|
||||
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
|
||||
return View((object) model);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if (!ModelState.IsValid) {
|
||||
Services.TransactionManager.Cancel();
|
||||
model.GroupInfo = groupInfo;
|
||||
|
||||
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
|
||||
return View((object)model);
|
||||
}
|
||||
|
||||
|
@@ -1,9 +1,11 @@
|
||||
using JetBrains.Annotations;
|
||||
using System.Net;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
using Orchard.Core.Settings.Models;
|
||||
using Orchard.Core.Settings.ViewModels;
|
||||
using Orchard.Localization.Services;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Settings;
|
||||
using System;
|
||||
using Orchard.Security;
|
||||
@@ -16,16 +18,24 @@ namespace Orchard.Core.Settings.Drivers {
|
||||
private readonly ISiteService _siteService;
|
||||
private readonly ICultureManager _cultureManager;
|
||||
private readonly IMembershipService _membershipService;
|
||||
private readonly INotifier _notifier;
|
||||
|
||||
public SiteSettingsPartDriver(ISiteService siteService, ICultureManager cultureManager, IMembershipService membershipService, INotifier notifier) {
|
||||
public SiteSettingsPartDriver(
|
||||
ISiteService siteService,
|
||||
ICultureManager cultureManager,
|
||||
IMembershipService membershipService,
|
||||
INotifier notifier) {
|
||||
_siteService = siteService;
|
||||
_cultureManager = cultureManager;
|
||||
_membershipService = membershipService;
|
||||
_notifier = notifier;
|
||||
|
||||
T = NullLocalizer.Instance;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
protected override string Prefix { get { return "SiteSettings"; } }
|
||||
|
||||
@@ -48,6 +58,8 @@ namespace Orchard.Core.Settings.Drivers {
|
||||
SiteCultures = _cultureManager.ListCultures()
|
||||
};
|
||||
|
||||
var previousBaseUrl = model.Site.BaseUrl;
|
||||
|
||||
updater.TryUpdateModel(model, Prefix, null, null);
|
||||
|
||||
// ensures the super user is fully empty
|
||||
@@ -62,6 +74,27 @@ namespace Orchard.Core.Settings.Drivers {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ensure the base url is absolute if provided
|
||||
if (!String.IsNullOrWhiteSpace(model.Site.BaseUrl)) {
|
||||
if (!model.Site.BaseUrl.ToLower().StartsWith("http")) {
|
||||
updater.AddModelError("BaseUrl", T("The base url must be absolute."));
|
||||
}
|
||||
// if the base url has been modified, try to ping it
|
||||
else if (!String.Equals(previousBaseUrl, model.Site.BaseUrl, StringComparison.OrdinalIgnoreCase)) {
|
||||
try {
|
||||
var request = WebRequest.Create(model.Site.BaseUrl) as HttpWebRequest;
|
||||
if (request != null) {
|
||||
using (request.GetResponse() as HttpWebResponse) {}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
_notifier.Warning(T("The base url you entered could not be requested from current location."));
|
||||
Logger.Warning(e, "Could not query base url: {0}", model.Site.BaseUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ContentShape("Parts_Settings_SiteSettingsPart",
|
||||
() => shapeHelper.EditorTemplate(TemplateName: "Parts.Settings.SiteSettingsPart", Model: model, Prefix: Prefix));
|
||||
}
|
||||
|
@@ -95,5 +95,14 @@ namespace Orchard.Core.Settings {
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int UpdateFrom1() {
|
||||
SchemaBuilder.AlterTable("SiteSettingsPartRecord",
|
||||
table => table
|
||||
.AddColumn<string>("BaseUrl", c => c.WithLength(255))
|
||||
);
|
||||
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using Orchard.ContentManagement;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Settings;
|
||||
|
||||
namespace Orchard.Core.Settings.Models {
|
||||
@@ -42,5 +43,11 @@ namespace Orchard.Core.Settings.Models {
|
||||
get { return Record.PageSize; }
|
||||
set { Record.PageSize = value; }
|
||||
}
|
||||
|
||||
[StringLength(255)]
|
||||
public string BaseUrl {
|
||||
get { return Record.BaseUrl; }
|
||||
set { Record.BaseUrl = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Orchard.ContentManagement.Records;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Settings;
|
||||
|
||||
namespace Orchard.Core.Settings.Models {
|
||||
@@ -24,5 +25,8 @@ namespace Orchard.Core.Settings.Models {
|
||||
public virtual ResourceDebugMode ResourceDebugMode { get; set; }
|
||||
|
||||
public virtual int PageSize { get; set; }
|
||||
|
||||
[StringLength(255)]
|
||||
public virtual string BaseUrl { get; set; }
|
||||
}
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Core.Settings.Models;
|
||||
using Orchard.Settings;
|
||||
|
||||
@@ -8,7 +7,6 @@ namespace Orchard.Core.Settings.ViewModels {
|
||||
public class SiteSettingsPartViewModel {
|
||||
public SiteSettingsPart Site { get; set; }
|
||||
public IEnumerable<string> SiteCultures { get; set; }
|
||||
|
||||
|
||||
[HiddenInput(DisplayValue = false)]
|
||||
public int Id {
|
||||
@@ -16,33 +14,38 @@ namespace Orchard.Core.Settings.ViewModels {
|
||||
}
|
||||
|
||||
public string PageTitleSeparator {
|
||||
get { return Site.Record.PageTitleSeparator; }
|
||||
set { Site.Record.PageTitleSeparator = value; }
|
||||
get { return Site.PageTitleSeparator; }
|
||||
set { Site.PageTitleSeparator = value; }
|
||||
}
|
||||
|
||||
public string SiteName {
|
||||
get { return Site.Record.SiteName; }
|
||||
set { Site.Record.SiteName = value; }
|
||||
get { return Site.SiteName; }
|
||||
set { Site.SiteName = value; }
|
||||
}
|
||||
|
||||
public string SiteCulture {
|
||||
get { return Site.Record.SiteCulture; }
|
||||
set { Site.Record.SiteCulture = value; }
|
||||
get { return Site.SiteCulture; }
|
||||
set { Site.SiteCulture = value; }
|
||||
}
|
||||
|
||||
public string SuperUser {
|
||||
get { return Site.As<SiteSettingsPart>().Record.SuperUser; }
|
||||
set { Site.As<SiteSettingsPart>().Record.SuperUser = value; }
|
||||
get { return Site.SuperUser; }
|
||||
set { Site.SuperUser = value; }
|
||||
}
|
||||
|
||||
public ResourceDebugMode ResourceDebugMode {
|
||||
get { return Site.As<SiteSettingsPart>().ResourceDebugMode; }
|
||||
set { Site.As<SiteSettingsPart>().ResourceDebugMode = value; }
|
||||
get { return Site.ResourceDebugMode; }
|
||||
set { Site.ResourceDebugMode = value; }
|
||||
}
|
||||
|
||||
public int PageSize {
|
||||
get { return Site.As<SiteSettingsPart>().PageSize; }
|
||||
set { Site.As<SiteSettingsPart>().PageSize = value; }
|
||||
get { return Site.PageSize; }
|
||||
set { Site.PageSize = value; }
|
||||
}
|
||||
|
||||
public string BaseUrl {
|
||||
get { return Site.BaseUrl; }
|
||||
set { Site.BaseUrl = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -38,7 +38,13 @@
|
||||
</div>
|
||||
<div>
|
||||
<label for="DefaultPageSize">@T("Default number of items per page")</label>
|
||||
@Html.TextBoxFor(m => m.PageSize, new { @class = "textMedium" })
|
||||
@Html.TextBoxFor(m => m.PageSize, new { @class = "text-small" })
|
||||
<span class="hint">@T("Determines the default number of items that are shown per page.")</span>
|
||||
</div>
|
||||
<div>
|
||||
<label for="@Html.FieldIdFor(m => m.BaseUrl)">@T("Base url ")</label>
|
||||
@Html.TextBoxFor(m => m.BaseUrl, new { @class = "textMedium" })
|
||||
<span class="hint">@T("Enter the fully qualified base url of your website.")</span>
|
||||
<span class="hint">@T("e.g., http://localhost:30320/orchardlocal, http://www.yourdomain.com")</span>
|
||||
</div>
|
||||
</fieldset>
|
@@ -1,35 +1,106 @@
|
||||
using System.Web;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Autofac;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Warmup;
|
||||
using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.Web {
|
||||
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
|
||||
// visit http://go.microsoft.com/?LinkId=9394801
|
||||
|
||||
public class MvcApplication : HttpApplication {
|
||||
private static IOrchardHost _host;
|
||||
private static StartupResult _startupResult;
|
||||
private static EventWaitHandle _waitHandle;
|
||||
|
||||
public static void RegisterRoutes(RouteCollection routes) {
|
||||
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
|
||||
}
|
||||
|
||||
protected void Application_Start() {
|
||||
RegisterRoutes(RouteTable.Routes);
|
||||
LaunchStartupThread();
|
||||
}
|
||||
|
||||
_host = OrchardStarter.CreateHost(MvcSingletons);
|
||||
_host.Initialize();
|
||||
/// <summary>
|
||||
/// Initializes Orchard's Host in a separate thread
|
||||
/// </summary>
|
||||
private static void LaunchStartupThread() {
|
||||
_startupResult = new StartupResult();
|
||||
_waitHandle = new AutoResetEvent(false);
|
||||
|
||||
ThreadPool.QueueUserWorkItem(
|
||||
state => {
|
||||
try {
|
||||
RegisterRoutes(RouteTable.Routes);
|
||||
var host = OrchardStarter.CreateHost(MvcSingletons);
|
||||
host.Initialize();
|
||||
_startupResult.Host = host;
|
||||
}
|
||||
catch (Exception e) {
|
||||
_startupResult.Error = e;
|
||||
}
|
||||
finally {
|
||||
_waitHandle.Set();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void Application_BeginRequest() {
|
||||
Context.Items["originalHttpContext"] = Context;
|
||||
// Host is still starting up?
|
||||
if (_startupResult.Host == null && _startupResult.Error == null) {
|
||||
|
||||
_host.BeginRequest();
|
||||
// use the url as it was requested by the client
|
||||
// the real url might be different if it has been translated (proxy, load balancing, ...)
|
||||
var url = Request.ToUrlString();
|
||||
var virtualFileCopy = "~/App_Data/WarmUp/" + WarmupUtility.EncodeUrl(url.Trim('/'));
|
||||
var localCopy = HostingEnvironment.MapPath(virtualFileCopy);
|
||||
|
||||
if (File.Exists(localCopy)) {
|
||||
|
||||
// result should not be cached, even on proxies
|
||||
Context.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
|
||||
Context.Response.Cache.SetValidUntilExpires(false);
|
||||
Context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
|
||||
Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
|
||||
Context.Response.Cache.SetNoStore();
|
||||
|
||||
Context.Response.ContentType = "text/html";
|
||||
|
||||
Context.Response.WriteFile(localCopy);
|
||||
Context.Response.End();
|
||||
}
|
||||
else {
|
||||
// there is no local copy and the host is not running
|
||||
// wait for the host to initialize
|
||||
_waitHandle.WaitOne();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (_startupResult.Error != null) {
|
||||
// Host startup resulted in an error
|
||||
|
||||
// Throw error once, and restart launch (machine state may have changed
|
||||
// so we need to simulate a "restart".
|
||||
var error = _startupResult.Error;
|
||||
LaunchStartupThread();
|
||||
throw error;
|
||||
}
|
||||
|
||||
Context.Items["originalHttpContext"] = Context;
|
||||
_startupResult.Host.BeginRequest();
|
||||
}
|
||||
}
|
||||
|
||||
protected void Application_EndRequest() {
|
||||
_host.EndRequest();
|
||||
// Only notify if the host has started up
|
||||
if (_startupResult.Host != null) {
|
||||
_startupResult.Host.EndRequest();
|
||||
}
|
||||
}
|
||||
|
||||
static void MvcSingletons(ContainerBuilder builder) {
|
||||
@@ -37,6 +108,5 @@ namespace Orchard.Web {
|
||||
builder.Register(ctx => ModelBinders.Binders).SingleInstance();
|
||||
builder.Register(ctx => ViewEngines.Engines).SingleInstance();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -182,6 +182,10 @@ namespace Orchard.Setup {
|
||||
get { return SiteSettingsPartRecord.DefaultPageSize; }
|
||||
set { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public string BaseUrl {
|
||||
get { return ""; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
src/Orchard.Web/Modules/Orchard.Warmup/AdminMenu.cs
Normal file
17
src/Orchard.Web/Modules/Orchard.Warmup/AdminMenu.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
using Orchard.UI.Navigation;
|
||||
|
||||
namespace Orchard.Warmup {
|
||||
public class AdminMenu : INavigationProvider {
|
||||
public Localizer T { get; set; }
|
||||
public string MenuName { get { return "admin"; } }
|
||||
|
||||
public void GetNavigation(NavigationBuilder builder) {
|
||||
builder
|
||||
.Add(T("Settings"), menu => menu
|
||||
.Add(T("Warmup" ), "10.0", item => item.Action("Index", "Admin", new { area = "Orchard.Warmup" }).Permission(StandardPermissions.SiteOwner))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
using Orchard.Commands;
|
||||
using Orchard.Warmup.Services;
|
||||
|
||||
namespace Orchard.Warmup.Commands {
|
||||
public class WarmupCommands : DefaultOrchardCommandHandler {
|
||||
private readonly IWarmupUpdater _warmupUpdater;
|
||||
|
||||
[OrchardSwitch]
|
||||
public bool Force { get; set; }
|
||||
|
||||
public WarmupCommands(IWarmupUpdater warmupUpdater) {
|
||||
_warmupUpdater = warmupUpdater;
|
||||
}
|
||||
|
||||
[CommandName("warmup generate")]
|
||||
[CommandHelp("warmup generate [/Force:true] \r\n\t Generates all the static pages for the warmup feature.")]
|
||||
[OrchardSwitches("Force")]
|
||||
public string Generate() {
|
||||
if(Force) {
|
||||
_warmupUpdater.Generate();
|
||||
}
|
||||
else {
|
||||
_warmupUpdater.EnsureGenerate();
|
||||
}
|
||||
|
||||
return "Generation finished";
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
using System.Web.Mvc;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Core.Contents.Controllers;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
using Orchard.Warmup.Models;
|
||||
using Orchard.UI.Notify;
|
||||
using Orchard.Warmup.Services;
|
||||
|
||||
namespace Orchard.Warmup.Controllers {
|
||||
public class AdminController : Controller, IUpdateModel {
|
||||
private readonly IWarmupUpdater _warmupUpdater;
|
||||
|
||||
public AdminController(IOrchardServices services, IWarmupUpdater warmupUpdater) {
|
||||
_warmupUpdater = warmupUpdater;
|
||||
Services = services;
|
||||
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public IOrchardServices Services { get; set; }
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public ActionResult Index() {
|
||||
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage settings")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var warmupPart = Services.WorkContext.CurrentSite.As<WarmupSettingsPart>();
|
||||
return View(warmupPart);
|
||||
}
|
||||
|
||||
[FormValueRequired("submit")]
|
||||
[HttpPost, ActionName("Index")]
|
||||
public ActionResult IndexPost() {
|
||||
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage settings")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var warmupPart = Services.WorkContext.CurrentSite.As<WarmupSettingsPart>();
|
||||
|
||||
if(TryUpdateModel(warmupPart)) {
|
||||
Services.Notifier.Information(T("Warmup updated successfully."));
|
||||
}
|
||||
|
||||
if (warmupPart.Scheduled) {
|
||||
if (warmupPart.Delay <= 0) {
|
||||
AddModelError("Delay", T("Delay must be greater than zero."));
|
||||
}
|
||||
}
|
||||
|
||||
return View(warmupPart);
|
||||
}
|
||||
|
||||
[FormValueRequired("submit.Generate")]
|
||||
[HttpPost, ActionName("Index")]
|
||||
public ActionResult IndexPostGenerate() {
|
||||
var result = IndexPost();
|
||||
|
||||
if (ModelState.IsValid) {
|
||||
_warmupUpdater.Generate();
|
||||
Services.Notifier.Information(T("Static pages have been generated."));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
|
||||
return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
|
||||
}
|
||||
|
||||
void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
|
||||
ModelState.AddModelError(key, errorMessage.ToString());
|
||||
}
|
||||
|
||||
public void AddModelError(string key, LocalizedString errorMessage) {
|
||||
ModelState.AddModelError(key, errorMessage.ToString());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Warmup.Models;
|
||||
using Orchard.Warmup.Services;
|
||||
|
||||
namespace Orchard.Warmup.Handlers {
|
||||
/// <summary>
|
||||
/// Intercepts the ContentHandler events to create warmup static pages
|
||||
/// whenever some content is published
|
||||
/// </summary>
|
||||
public class WarmupContentHandler : ContentHandler {
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
private readonly IWarmupUpdater _warmupUpdater;
|
||||
|
||||
public WarmupContentHandler(IOrchardServices orchardServices, IWarmupUpdater warmupUpdater) {
|
||||
_orchardServices = orchardServices;
|
||||
_warmupUpdater = warmupUpdater;
|
||||
|
||||
OnPublished<ContentPart>(Generate);
|
||||
}
|
||||
|
||||
void Generate(PublishContentContext context, ContentPart part) {
|
||||
if(_orchardServices.WorkContext.CurrentSite.As<WarmupSettingsPart>().OnPublish) {
|
||||
_warmupUpdater.Generate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Data;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.Warmup.Models;
|
||||
|
||||
namespace Orchard.Warmup.Handlers {
|
||||
[UsedImplicitly]
|
||||
public class WarmupSettingsPartHandler : ContentHandler {
|
||||
public WarmupSettingsPartHandler(IRepository<WarmupSettingsPartRecord> repository) {
|
||||
Filters.Add(new ActivatingFilter<WarmupSettingsPart>("Site"));
|
||||
Filters.Add(StorageFilter.For(repository));
|
||||
}
|
||||
}
|
||||
}
|
18
src/Orchard.Web/Modules/Orchard.Warmup/Migrations.cs
Normal file
18
src/Orchard.Web/Modules/Orchard.Warmup/Migrations.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Orchard.Data.Migration;
|
||||
|
||||
namespace Orchard.Warmup {
|
||||
public class Migrations : DataMigrationImpl {
|
||||
public int Create() {
|
||||
SchemaBuilder.CreateTable("WarmupSettingsPartRecord",
|
||||
table => table
|
||||
.ContentPartRecord()
|
||||
.Column<string>("Urls", column => column.Unlimited())
|
||||
.Column<bool>("Scheduled")
|
||||
.Column<int>("Delay")
|
||||
.Column<bool>("OnPublish")
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
using Orchard.ContentManagement;
|
||||
|
||||
namespace Orchard.Warmup.Models {
|
||||
public class WarmupSettingsPart : ContentPart<WarmupSettingsPartRecord> {
|
||||
|
||||
public string Urls {
|
||||
get { return Record.Urls; }
|
||||
set { Record.Urls = value; }
|
||||
}
|
||||
|
||||
public bool Scheduled {
|
||||
get { return Record.Scheduled; }
|
||||
set { Record.Scheduled = value; }
|
||||
}
|
||||
|
||||
public int Delay {
|
||||
get { return Record.Delay; }
|
||||
set { Record.Delay = value; }
|
||||
}
|
||||
|
||||
public bool OnPublish {
|
||||
get { return Record.OnPublish; }
|
||||
set { Record.OnPublish = value; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data.Conventions;
|
||||
|
||||
namespace Orchard.Warmup.Models {
|
||||
public class WarmupSettingsPartRecord : ContentPartRecord {
|
||||
public WarmupSettingsPartRecord() {
|
||||
Delay = 90;
|
||||
}
|
||||
|
||||
[StringLengthMax]
|
||||
public virtual string Urls { get; set; }
|
||||
public virtual bool Scheduled { get; set; }
|
||||
public virtual int Delay { get; set; }
|
||||
public virtual bool OnPublish { get; set; }
|
||||
}
|
||||
}
|
12
src/Orchard.Web/Modules/Orchard.Warmup/Module.txt
Normal file
12
src/Orchard.Web/Modules/Orchard.Warmup/Module.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Name: Orchard.Warmup
|
||||
AntiForgery: enabled
|
||||
Author: The Orchard Team
|
||||
Website: http://orchardproject.net
|
||||
Version: 1.0
|
||||
OrchardVersion: 1.0
|
||||
Description: Provides a mecanism to generate a static version of pages for being used during application warm up.
|
||||
Features:
|
||||
Orchard.Warmup:
|
||||
Description: Generates the static version of specific pages periodically.
|
||||
Name: Warmup
|
||||
Category: Hosting
|
142
src/Orchard.Web/Modules/Orchard.Warmup/Orchard.Warmup.csproj
Normal file
142
src/Orchard.Web/Modules/Orchard.Warmup/Orchard.Warmup.csproj
Normal file
@@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}</ProjectGuid>
|
||||
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Orchard.Warmup</RootNamespace>
|
||||
<AssemblyName>Orchard.Warmup</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<MvcBuildViews>false</MvcBuildViews>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation />
|
||||
<TargetFrameworkProfile />
|
||||
<UseIISExpress>false</UseIISExpress>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Abstractions" />
|
||||
<Reference Include="System.Web.Routing" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Web.config" />
|
||||
<Content Include="Views\Web.config" />
|
||||
<Content Include="Scripts\Web.config" />
|
||||
<Content Include="Styles\Web.config" />
|
||||
<Content Include="Properties\AssemblyInfo.cs" />
|
||||
<Content Include="Module.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
|
||||
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
|
||||
<Name>Orchard.Framework</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Core\Orchard.Core.csproj">
|
||||
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
|
||||
<Name>Orchard.Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AdminMenu.cs" />
|
||||
<Compile Include="Commands\WarmupCommands.cs" />
|
||||
<Compile Include="Controllers\AdminController.cs" />
|
||||
<Compile Include="Handlers\WarmupContentHandler.cs" />
|
||||
<Compile Include="Handlers\WarmupSettingsPartHandler.cs" />
|
||||
<Compile Include="Migrations.cs" />
|
||||
<Compile Include="Models\WarmupSettingsPart.cs" />
|
||||
<Compile Include="Models\WarmupSettingsPartRecord.cs" />
|
||||
<Compile Include="Services\WebDownloader.cs" />
|
||||
<Compile Include="Services\IWarmupUpdater.cs" />
|
||||
<Compile Include="Services\IWebDownloader.cs" />
|
||||
<Compile Include="Services\SettingsBanner.cs" />
|
||||
<Compile Include="Services\WarmupTask.cs" />
|
||||
<Compile Include="Services\WarmupUpdater.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<Content Include="Views\EditorTemplates\Parts.Warmup.SiteSettings.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Placement.info" />
|
||||
<Content Include="Views\Admin\Index.cshtml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target> -->
|
||||
<Target Name="AfterBuild" DependsOnTargets="AfterBuildCompiler">
|
||||
<PropertyGroup>
|
||||
<AreasManifestDir>$(ProjectDir)\..\Manifests</AreasManifestDir>
|
||||
</PropertyGroup>
|
||||
<!-- If this is an area child project, uncomment the following line:
|
||||
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Child" AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)" ContentFiles="@(Content)" />
|
||||
-->
|
||||
<!-- If this is an area parent project, uncomment the following lines:
|
||||
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Parent" AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)" ContentFiles="@(Content)" />
|
||||
<CopyAreaManifests ManifestPath="$(AreasManifestDir)" CrossCopy="false" RenameViews="true" />
|
||||
-->
|
||||
</Target>
|
||||
<Target Name="AfterBuildCompiler" Condition="'$(MvcBuildViews)'=='true'">
|
||||
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)\..\$(ProjectName)" />
|
||||
</Target>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>False</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>45979</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>
|
||||
</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>True</UseCustomServer>
|
||||
<CustomServerUrl>http://orchard.codeplex.com</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
3
src/Orchard.Web/Modules/Orchard.Warmup/Placement.info
Normal file
3
src/Orchard.Web/Modules/Orchard.Warmup/Placement.info
Normal file
@@ -0,0 +1,3 @@
|
||||
<Placement>
|
||||
<Place Parts_Warmup_SiteSettings="Content:10"/>
|
||||
</Placement>
|
@@ -0,0 +1,34 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Orchard.Warmup")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyProduct("Orchard")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("3484b5d3-de81-4a46-bfa6-c1d02a029184")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
21
src/Orchard.Web/Modules/Orchard.Warmup/Scripts/Web.config
Normal file
21
src/Orchard.Web/Modules/Orchard.Warmup/Scripts/Web.config
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<!-- iis6 - for any request in this location, return via managed static file handler -->
|
||||
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<handlers accessPolicy="Script,Read">
|
||||
<!--
|
||||
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||
-->
|
||||
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
@@ -0,0 +1,13 @@
|
||||
namespace Orchard.Warmup.Services {
|
||||
public interface IWarmupUpdater : IDependency {
|
||||
/// <summary>
|
||||
/// Forces a regeneration of all static pages
|
||||
/// </summary>
|
||||
void Generate();
|
||||
|
||||
/// <summary>
|
||||
/// Generates static pages if needed
|
||||
/// </summary>
|
||||
void EnsureGenerate();
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
|
||||
using System.Net;
|
||||
|
||||
namespace Orchard.Warmup.Services {
|
||||
public class DownloadResult {
|
||||
public HttpStatusCode StatusCode { get; set; }
|
||||
public string Content { get; set; }
|
||||
}
|
||||
|
||||
public interface IWebDownloader : IDependency {
|
||||
DownloadResult Download(string url);
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Localization;
|
||||
using Orchard.UI.Admin.Notification;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.Warmup.Services {
|
||||
public class SettingsBanner: INotificationProvider {
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
|
||||
public SettingsBanner(IOrchardServices orchardServices) {
|
||||
_orchardServices = orchardServices;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public IEnumerable<NotifyEntry> GetNotifications() {
|
||||
if ( string.IsNullOrWhiteSpace(_orchardServices.WorkContext.CurrentSite.BaseUrl)) {
|
||||
yield return new NotifyEntry { Message = T("The Warmup feature needs the Base Url site setting to be set." ), Type = NotifyType.Warning };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Tasks;
|
||||
using Orchard.Warmup.Models;
|
||||
|
||||
namespace Orchard.Warmup.Services {
|
||||
public class WarmupTask : IBackgroundTask {
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
private readonly IWarmupUpdater _warmupUpdater;
|
||||
|
||||
public WarmupTask(IOrchardServices orchardServices, IWarmupUpdater warmupUpdater) {
|
||||
_orchardServices = orchardServices;
|
||||
_warmupUpdater = warmupUpdater;
|
||||
}
|
||||
|
||||
public void Sweep() {
|
||||
var part = _orchardServices.WorkContext.CurrentSite.As<WarmupSettingsPart>();
|
||||
|
||||
if (!part.Scheduled) {
|
||||
return;
|
||||
}
|
||||
|
||||
_warmupUpdater.EnsureGenerate();
|
||||
}
|
||||
}
|
||||
}
|
151
src/Orchard.Web/Modules/Orchard.Warmup/Services/WarmupUpdater.cs
Normal file
151
src/Orchard.Web/Modules/Orchard.Warmup/Services/WarmupUpdater.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Environment.Warmup;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.FileSystems.LockFile;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Services;
|
||||
using Orchard.Warmup.Models;
|
||||
|
||||
namespace Orchard.Warmup.Services {
|
||||
public class WarmupUpdater : IWarmupUpdater {
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
private readonly ILockFileManager _lockFileManager;
|
||||
private readonly IClock _clock;
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
private readonly IWebDownloader _webDownloader;
|
||||
private const string BaseFolder = "Warmup";
|
||||
private const string WarmupFilename = "warmup.txt";
|
||||
private readonly string _lockFilename;
|
||||
|
||||
public WarmupUpdater(
|
||||
IOrchardServices orchardServices,
|
||||
ILockFileManager lockFileManager,
|
||||
IClock clock,
|
||||
IAppDataFolder appDataFolder,
|
||||
IWebDownloader webDownloader) {
|
||||
_orchardServices = orchardServices;
|
||||
_lockFileManager = lockFileManager;
|
||||
_clock = clock;
|
||||
_appDataFolder = appDataFolder;
|
||||
_webDownloader = webDownloader;
|
||||
_lockFilename = _appDataFolder.Combine(BaseFolder, WarmupFilename + ".lock");
|
||||
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void EnsureGenerate() {
|
||||
var baseUrl = _orchardServices.WorkContext.CurrentSite.BaseUrl;
|
||||
var part = _orchardServices.WorkContext.CurrentSite.As<WarmupSettingsPart>();
|
||||
|
||||
// do nothing while the base url setting is not defined, or if there is no page defined
|
||||
if (String.IsNullOrWhiteSpace(baseUrl) || String.IsNullOrWhiteSpace(part.Urls)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent multiple appdomains from rebuilding the static page concurrently (e.g., command line)
|
||||
ILockFile lockFile = null;
|
||||
if (!_lockFileManager.TryAcquireLock(_lockFilename, ref lockFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
using (lockFile) {
|
||||
|
||||
// check if we need to regenerate the pages by reading the last time it has been done
|
||||
// 1- if the warmup file doesn't exists, generate the pages
|
||||
// 2- otherwise, if the scheduled generation option is on, check if the delay is over
|
||||
var warmupPath = _appDataFolder.Combine(BaseFolder, WarmupFilename);
|
||||
if(_appDataFolder.FileExists(warmupPath)) {
|
||||
try {
|
||||
var warmupContent = _appDataFolder.ReadFile(warmupPath);
|
||||
var expired = XmlConvert.ToDateTimeOffset(warmupContent).AddMinutes(part.Delay);
|
||||
if (expired > _clock.UtcNow) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// invalid file, delete continue processing
|
||||
_appDataFolder.DeleteFile(warmupPath);
|
||||
}
|
||||
}
|
||||
|
||||
// delete existing static page files
|
||||
foreach (var filename in _appDataFolder.ListFiles(BaseFolder)) {
|
||||
var prefix = _appDataFolder.Combine(BaseFolder, "http");
|
||||
|
||||
// delete only static page files
|
||||
if (!filename.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
_appDataFolder.DeleteFile(filename);
|
||||
}
|
||||
catch(Exception e) {
|
||||
// ignore files which could not be deleted
|
||||
Logger.Error(e, "Could not delete file {0}", filename);
|
||||
}
|
||||
}
|
||||
|
||||
// loop over every relative url to generate the contents
|
||||
using (var urlReader = new StringReader(part.Urls)) {
|
||||
string relativeUrl;
|
||||
while (null != (relativeUrl = urlReader.ReadLine())) {
|
||||
string url = null;
|
||||
relativeUrl = relativeUrl.Trim();
|
||||
|
||||
try {
|
||||
url = VirtualPathUtility.RemoveTrailingSlash(baseUrl) + relativeUrl;
|
||||
var download = _webDownloader.Download(url);
|
||||
|
||||
if (download != null && download.StatusCode == HttpStatusCode.OK) {
|
||||
var filename = WarmupUtility.EncodeUrl(url);
|
||||
var path = _appDataFolder.Combine(BaseFolder, filename);
|
||||
_appDataFolder.CreateFile(path, download.Content);
|
||||
|
||||
// if the base url contains http://www, then also render the www-less one
|
||||
|
||||
if (url.StartsWith("http://www.", StringComparison.OrdinalIgnoreCase)) {
|
||||
url = "http://" + url.Substring("http://www.".Length);
|
||||
filename = WarmupUtility.EncodeUrl(url);
|
||||
path = _appDataFolder.Combine(BaseFolder, filename);
|
||||
_appDataFolder.CreateFile(path, download.Content);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "Could not extract warmup page content for: ", url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally write the time the generation has been executed
|
||||
_appDataFolder.CreateFile(warmupPath, XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc));
|
||||
}
|
||||
}
|
||||
|
||||
public void Generate() {
|
||||
// prevent multiple appdomains from rebuilding the static page concurrently (e.g., command line)
|
||||
ILockFile lockFile = null;
|
||||
if (!_lockFileManager.TryAcquireLock(_lockFilename, ref lockFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
using (lockFile) {
|
||||
var warmupPath = _appDataFolder.Combine(BaseFolder, WarmupFilename);
|
||||
if (_appDataFolder.FileExists(warmupPath)) {
|
||||
_appDataFolder.DeleteFile(warmupPath);
|
||||
}
|
||||
}
|
||||
|
||||
EnsureGenerate();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Warmup.Services {
|
||||
public class WebDownloader : IWebDownloader {
|
||||
public WebDownloader() {
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public DownloadResult Download(string url) {
|
||||
if(String.IsNullOrWhiteSpace(url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
var request = WebRequest.Create(url) as HttpWebRequest;
|
||||
if (request != null) {
|
||||
using (var response = request.GetResponse() as HttpWebResponse) {
|
||||
if (response != null) {
|
||||
using (var stream = response.GetResponseStream()) {
|
||||
if (stream != null) {
|
||||
using (var sr = new StreamReader(stream)) {
|
||||
return new DownloadResult {Content = sr.ReadToEnd(), StatusCode = response.StatusCode};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (WebException e) {
|
||||
if(e.Response as HttpWebResponse != null) {
|
||||
return new DownloadResult { StatusCode = ((HttpWebResponse)e.Response).StatusCode };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch(Exception e) {
|
||||
Logger.Error(e, "An error occured while downloading url: {0}", url);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
src/Orchard.Web/Modules/Orchard.Warmup/Styles/Web.config
Normal file
21
src/Orchard.Web/Modules/Orchard.Warmup/Styles/Web.config
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<!-- iis6 - for any request in this location, return via managed static file handler -->
|
||||
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<handlers accessPolicy="Script,Read">
|
||||
<!--
|
||||
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||
-->
|
||||
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
@@ -0,0 +1,37 @@
|
||||
@model Orchard.Warmup.Models.WarmupSettingsPart
|
||||
@using Orchard.Utility.Extensions;
|
||||
@using Orchard.Warmup.Models;
|
||||
|
||||
@{ Layout.Title = T("Warmup").ToString(); }
|
||||
|
||||
@using (Html.BeginFormAntiForgeryPost()) {
|
||||
@Html.ValidationSummary()
|
||||
|
||||
<fieldset>
|
||||
<div>
|
||||
<label for="@Html.FieldIdFor(m => m.Urls)">@T("Urls for which static warmup pages will be generated")</label>
|
||||
@Html.TextAreaFor(m => m.Urls, new { @class = "textMedium" })
|
||||
<span class="hint">@T("This must be a set of relative paths, e.g., /, /About")</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<div>
|
||||
@Html.EditorFor(m => m.Scheduled)
|
||||
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Scheduled)">@T("Generate warmup pages periodically")</label>
|
||||
</div>
|
||||
<div data-controllerid="@Html.FieldIdFor(m => m.Scheduled)">
|
||||
@T("Every")
|
||||
@Html.TextBoxFor(m => m.Delay, new { @class = "text-small" })
|
||||
@T("minutes")
|
||||
@Html.ValidationMessage("Delay", "*")
|
||||
</div>
|
||||
<div>
|
||||
@Html.EditorFor(m => m.OnPublish)
|
||||
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.OnPublish)">@T("Generate warmup pages each time some content is published")</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<button class="primaryAction" name="submit" value="@T("Save")" type="submit">@T("Save")</button>
|
||||
<button class="primaryAction" name="submit.Generate" value="@T("Save and generate")" type="submit">@T("Save and generate")</button>
|
||||
</fieldset>
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
@model Orchard.Warmup.Models.WarmupSettingsPartRecord
|
||||
@using Orchard.Utility.Extensions;
|
||||
@using Orchard.Warmup.Models;
|
||||
|
||||
<fieldset>
|
||||
<legend>@T("Warmup")</legend>
|
||||
|
||||
<div>
|
||||
<label for="@Html.FieldIdFor(m => m.Urls)">@T("Urls for which static warm up pages will be generated")</label>
|
||||
@Html.TextAreaFor(m => m.Urls, new { @class = "textMedium" })
|
||||
@Html.ValidationMessage("Urls", "*")
|
||||
<span class="hint">@T("This must be a set of virtual paths, e.g., ~/, ~/About")</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@Html.EditorFor(m => m.Scheduled)
|
||||
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Scheduled)">@T("Generate warmup pages periodically")</label>
|
||||
</div>
|
||||
<div data-controllerid="@Html.FieldIdFor(m => m.Scheduled)>
|
||||
<label for="@Html.FieldIdFor(m => m.Urls)">@T("Delay to generate pages")</label>
|
||||
@Html.TextBoxFor(m => m.Delay, new { @class = "" }) @T("minutes")
|
||||
@Html.ValidationMessage("Delay", "*")
|
||||
</div>
|
||||
<div>
|
||||
@Html.EditorFor(m => m.OnPublish)
|
||||
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.OnPublish)">@T("Generate warmup pages each time some content is published")</label>
|
||||
</div>
|
||||
</fieldset>
|
41
src/Orchard.Web/Modules/Orchard.Warmup/Views/Web.config
Normal file
41
src/Orchard.Web/Modules/Orchard.Warmup/Views/Web.config
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
</httpHandlers>
|
||||
|
||||
<!--
|
||||
Enabling request validation in view pages would cause validation to occur
|
||||
after the input has already been processed by the controller. By default
|
||||
MVC performs request validation before a controller processes the input.
|
||||
To change this behavior apply the ValidateInputAttribute to a
|
||||
controller or action.
|
||||
-->
|
||||
<pages
|
||||
validateRequest="false"
|
||||
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"
|
||||
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"
|
||||
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<controls>
|
||||
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" namespace="System.Web.Mvc" tagPrefix="mvc" />
|
||||
</controls>
|
||||
</pages>
|
||||
</system.web>
|
||||
|
||||
<system.webServer>
|
||||
<validation validateIntegratedModeConfiguration="false"/>
|
||||
<handlers>
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
|
||||
<bindingRedirect oldVersion="2.0.0.0" newVersion="3.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
39
src/Orchard.Web/Modules/Orchard.Warmup/Web.config
Normal file
39
src/Orchard.Web/Modules/Orchard.Warmup/Web.config
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
|
||||
<configSections>
|
||||
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
|
||||
<remove name="host" />
|
||||
<remove name="pages" />
|
||||
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
|
||||
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
|
||||
<system.web.webPages.razor>
|
||||
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<pages pageBaseType="Orchard.Mvc.ViewEngines.Razor.WebViewPage">
|
||||
<namespaces>
|
||||
<add namespace="System.Web.Mvc" />
|
||||
<add namespace="System.Web.Mvc.Ajax" />
|
||||
<add namespace="System.Web.Mvc.Html" />
|
||||
<add namespace="System.Web.Routing" />
|
||||
<add namespace="System.Linq"/>
|
||||
<add namespace="System.Collections.Generic"/>
|
||||
<add namespace="Orchard.Mvc.Html"/>
|
||||
</namespaces>
|
||||
</pages>
|
||||
</system.web.webPages.razor>
|
||||
|
||||
<system.web>
|
||||
<compilation targetFramework="4.0">
|
||||
<assemblies>
|
||||
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
|
||||
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
</assemblies>
|
||||
</compilation>
|
||||
</system.web>
|
||||
|
||||
</configuration>
|
@@ -18,6 +18,7 @@
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation />
|
||||
<TargetFrameworkProfile />
|
||||
<UseIISExpress>false</UseIISExpress>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -48,11 +49,68 @@
|
||||
<ItemGroup>
|
||||
<Content Include="Scripts\jquery-1.5.1.js" />
|
||||
<Content Include="Scripts\jquery-1.5.1.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.blind.js" />
|
||||
<Content Include="Scripts\jquery.effects.blind.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.bounce.js" />
|
||||
<Content Include="Scripts\jquery.effects.bounce.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.clip.js" />
|
||||
<Content Include="Scripts\jquery.effects.clip.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.core.js" />
|
||||
<Content Include="Scripts\jquery.effects.core.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.drop.js" />
|
||||
<Content Include="Scripts\jquery.effects.drop.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.explode.js" />
|
||||
<Content Include="Scripts\jquery.effects.explode.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.fade.js" />
|
||||
<Content Include="Scripts\jquery.effects.fade.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.fold.js" />
|
||||
<Content Include="Scripts\jquery.effects.fold.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.highlight.js" />
|
||||
<Content Include="Scripts\jquery.effects.highlight.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.pulsate.js" />
|
||||
<Content Include="Scripts\jquery.effects.pulsate.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.scale.js" />
|
||||
<Content Include="Scripts\jquery.effects.scale.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.shake.js" />
|
||||
<Content Include="Scripts\jquery.effects.shake.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.slide.js" />
|
||||
<Content Include="Scripts\jquery.effects.slide.min.js" />
|
||||
<Content Include="Scripts\jquery.effects.transfer.js" />
|
||||
<Content Include="Scripts\jquery.effects.transfer.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.accordion.js" />
|
||||
<Content Include="Scripts\jquery.ui.accordion.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.autocomplete.js" />
|
||||
<Content Include="Scripts\jquery.ui.autocomplete.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.button.js" />
|
||||
<Content Include="Scripts\jquery.ui.button.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.core.js" />
|
||||
<Content Include="Scripts\jquery.ui.core.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.datepicker.js" />
|
||||
<Content Include="Scripts\jquery.ui.datepicker.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.dialog.js" />
|
||||
<Content Include="Scripts\jquery.ui.dialog.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.draggable.js" />
|
||||
<Content Include="Scripts\jquery.ui.draggable.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.droppable.js" />
|
||||
<Content Include="Scripts\jquery.ui.droppable.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.mouse.js" />
|
||||
<Content Include="Scripts\jquery.ui.mouse.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.position.js" />
|
||||
<Content Include="Scripts\jquery.ui.position.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.progressbar.js" />
|
||||
<Content Include="Scripts\jquery.ui.progressbar.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.resizable.js" />
|
||||
<Content Include="Scripts\jquery.ui.resizable.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.selectable.js" />
|
||||
<Content Include="Scripts\jquery.ui.selectable.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.slider.js" />
|
||||
<Content Include="Scripts\jquery.ui.slider.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.sortable.js" />
|
||||
<Content Include="Scripts\jquery.ui.sortable.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.tabs.js" />
|
||||
<Content Include="Scripts\jquery.ui.tabs.min.js" />
|
||||
<Content Include="Scripts\jquery.ui.widget.js" />
|
||||
<Content Include="Scripts\jquery.ui.widget.min.js" />
|
||||
<Content Include="Scripts\jquery.utils.js" />
|
||||
<Content Include="Scripts\ui.timepickr.js" />
|
||||
<Content Include="Styles\images\ui-bg_flat_0_aaaaaa_40x100.png" />
|
||||
|
@@ -18,6 +18,7 @@
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation />
|
||||
<TargetFrameworkProfile />
|
||||
<UseIISExpress>true</UseIISExpress>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -199,8 +200,7 @@
|
||||
<AutoAssignPort>False</AutoAssignPort>
|
||||
<DevelopmentServerPort>30320</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/OrchardLocal</DevelopmentServerVPath>
|
||||
<IISUrl>
|
||||
</IISUrl>
|
||||
<IISUrl>http://localhost:30320/OrchardLocal</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
@@ -112,6 +112,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Recipes", "Orchard.
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.ImportExport", "Orchard.Web\Modules\Orchard.ImportExport\Orchard.ImportExport.csproj", "{FE5C5947-D2D5-42C5-992A-13D672946135}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Warmup", "Orchard.Web\Modules\Orchard.WarmUp\Orchard.Warmup.csproj", "{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
CodeCoverage|Any CPU = CodeCoverage|Any CPU
|
||||
@@ -595,6 +597,13 @@ Global
|
||||
{FE5C5947-D2D5-42C5-992A-13D672946135}.FxCop|Any CPU.Build.0 = Release|Any CPU
|
||||
{FE5C5947-D2D5-42C5-992A-13D672946135}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FE5C5947-D2D5-42C5-992A-13D672946135}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}.CodeCoverage|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}.Coverage|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}.FxCop|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -634,6 +643,7 @@ Global
|
||||
{43D0EC0B-1955-4566-8D31-7B9102DA1703} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}
|
||||
{FC1D74E8-7A4D-48F4-83DE-95C6173780C4} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}
|
||||
{FE5C5947-D2D5-42C5-992A-13D672946135} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}
|
||||
{9CD5C81F-5828-4384-8474-2E2BE71D5EDD} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5}
|
||||
{ABC826D4-2FA1-4F2F-87DE-E6095F653810} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA}
|
||||
{F112851D-B023-4746-B6B1-8D2E5AD8F7AA} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA}
|
||||
{6CB3EB30-F725-45C0-9742-42599BA8E8D2} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA}
|
||||
|
8
src/Orchard/Environment/Warmup/StartupResult.cs
Normal file
8
src/Orchard/Environment/Warmup/StartupResult.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Orchard.Environment.Warmup {
|
||||
public class StartupResult {
|
||||
public IOrchardHost Host { get; set; }
|
||||
public Exception Error { get; set; }
|
||||
}
|
||||
}
|
19
src/Orchard/Environment/Warmup/WarmupUtility.cs
Normal file
19
src/Orchard/Environment/Warmup/WarmupUtility.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Orchard.Environment.Warmup {
|
||||
public static class WarmupUtility {
|
||||
private const string EncodingPattern = "[^a-z0-9]";
|
||||
|
||||
public static string EncodeUrl(string url) {
|
||||
if(String.IsNullOrWhiteSpace(url)) {
|
||||
throw new ArgumentException("url can't be empty");
|
||||
}
|
||||
|
||||
return Regex.Replace(url.ToLower(), EncodingPattern, m => "_" + Encoding.UTF8.GetBytes(m.Value).Select(b => b.ToString("X")).Aggregate((a, b) => a + b));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -58,8 +58,7 @@ namespace Orchard.FileSystems.LockFile {
|
||||
var content = _appDataFolder.ReadFile(path);
|
||||
|
||||
DateTime creationUtc;
|
||||
if (DateTime.TryParse(content, out creationUtc))
|
||||
{
|
||||
if (DateTime.TryParse(content, out creationUtc)) {
|
||||
// if expired the file is not removed
|
||||
// it should be automatically as there is a finalizer in LockFile
|
||||
// or the next taker can do it, unless it also fails, again
|
||||
|
@@ -183,6 +183,8 @@
|
||||
<Compile Include="Environment\IAssemblyLoader.cs" />
|
||||
<Compile Include="Environment\HostComponentsConfigModule.cs" />
|
||||
<Compile Include="Environment\ViewsBackgroundCompilation.cs" />
|
||||
<Compile Include="Environment\Warmup\StartupResult.cs" />
|
||||
<Compile Include="Environment\Warmup\WarmupUtility.cs" />
|
||||
<Compile Include="Environment\WorkContextImplementation.cs" />
|
||||
<Compile Include="Environment\WorkContextModule.cs" />
|
||||
<Compile Include="Environment\WorkContextProperty.cs" />
|
||||
|
@@ -13,5 +13,6 @@ namespace Orchard.Settings {
|
||||
string SiteCulture { get; set; }
|
||||
ResourceDebugMode ResourceDebugMode { get; set; }
|
||||
int PageSize { get; set; }
|
||||
string BaseUrl { get; }
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user