mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-14 10:54:50 +08:00
Revising how Orchard restarts the AppDomain
Orchard used to write to the "~/web.config" file to force an AppDomain restart needed in some case of dynamic compilation. Revised the policy to be like this: 1. If full trust, use HttpRuntime.UnloadAppDomain() 2. If Medium Trust, write to "~/bin/HostRestart/marker.txt" 3. If Medium Trust and 2. failed, write to "~/web.config" 4. If Medium Trust and 2.+3. failed, give an error message to the user with appropriate measures to take on the web server. Also removed a now unused "ResetSiteCompilation" method --HG-- branch : dev
This commit is contained in:
@@ -2,8 +2,7 @@
|
||||
|
||||
namespace Orchard.Tests.Environment {
|
||||
public class StubHostEnvironment : HostEnvironment {
|
||||
public override void ResetSiteCompilation() {
|
||||
|
||||
public override void RestartAppDomain() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ namespace Orchard.Commands {
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public override void ResetSiteCompilation() {
|
||||
public override void RestartAppDomain() {
|
||||
throw new OrchardCommandHostRetryException(T("A change of configuration requires the session to be restarted."));
|
||||
}
|
||||
}
|
||||
|
@@ -1,43 +1,89 @@
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Mvc;
|
||||
using Orchard.Services;
|
||||
using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.Environment
|
||||
{
|
||||
public class DefaultHostEnvironment : HostEnvironment
|
||||
{
|
||||
namespace Orchard.Environment {
|
||||
public class DefaultHostEnvironment : HostEnvironment {
|
||||
private const string WebConfigPath = "~/web.config";
|
||||
private const string RefreshHtmlPath = "~/refresh.html";
|
||||
private const string HostRestartPath = "~/bin/HostRestart";
|
||||
private readonly IClock _clock;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public DefaultHostEnvironment(IClock clock, IHttpContextAccessor httpContextAccessor) {
|
||||
_clock = clock;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
T = NullLocalizer.Instance;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public override void ResetSiteCompilation()
|
||||
{
|
||||
// Touch web.config
|
||||
File.SetLastWriteTimeUtc(MapPath("~/web.config"), _clock.UtcNow);
|
||||
public Localizer T { get; set; }
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public override void RestartAppDomain() {
|
||||
if (IsFullTrust) {
|
||||
HttpRuntime.UnloadAppDomain();
|
||||
}
|
||||
else {
|
||||
bool success = TryWriteBinFolder() || TryWriteWebConfig();
|
||||
|
||||
if (!success) {
|
||||
throw new OrchardException(
|
||||
T("Orchard needs to be restarted due to a configuration change, but was unable to do so.\r\n" +
|
||||
"To prevent this issue in the future, a change to the web server configuration is required:\r\n" +
|
||||
"- run the application in a full trust environment, or\r\n" +
|
||||
"- give the application write access to the '{0}' folder, or\r\n" +
|
||||
"- give the application write access to the '{1}' file.",
|
||||
HostRestartPath, WebConfigPath));
|
||||
}
|
||||
}
|
||||
|
||||
// If setting up extensions/modules requires an AppDomain restart, it's very unlikely the
|
||||
// current request can be processed correctly. So, we redirect to the same URL, so that the
|
||||
// new request will come to the newly started AppDomain.
|
||||
var httpContext = _httpContextAccessor.Current();
|
||||
if (httpContext != null)
|
||||
{
|
||||
if (httpContext != null) {
|
||||
// Don't redirect posts...
|
||||
if (httpContext.Request.RequestType == "GET")
|
||||
{
|
||||
if (httpContext.Request.RequestType == "GET") {
|
||||
httpContext.Response.Redirect(HttpContext.Current.Request.ToUrlString(), true /*endResponse*/);
|
||||
}
|
||||
else
|
||||
{
|
||||
httpContext.Response.WriteFile("~/Refresh.html");
|
||||
else {
|
||||
httpContext.Response.WriteFile(RefreshHtmlPath);
|
||||
httpContext.Response.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryWriteWebConfig() {
|
||||
try {
|
||||
// In medium trust, "UnloadAppDomain" is not supported. Touch web.config
|
||||
// to force an AppDomain restart.
|
||||
File.SetLastWriteTimeUtc(MapPath(WebConfigPath), _clock.UtcNow);
|
||||
return true;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryWriteBinFolder() {
|
||||
try {
|
||||
var binMarker = MapPath(HostRestartPath);
|
||||
Directory.CreateDirectory(binMarker);
|
||||
|
||||
using (var stream = File.CreateText(Path.Combine(binMarker, "marker.txt"))) {
|
||||
stream.WriteLine("Restart on '{0}'", _clock.UtcNow);
|
||||
stream.Flush();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -74,11 +74,6 @@ namespace Orchard.Environment.Extensions {
|
||||
Logger.Information("Done loading extensions...");
|
||||
|
||||
// Very last step: Notify the host environment to restart the AppDomain if needed
|
||||
if (context.ResetSiteCompilation) {
|
||||
Logger.Information("Reset site compilation state required.");
|
||||
_hostEnvironment.ResetSiteCompilation();
|
||||
}
|
||||
|
||||
if (context.RestartAppDomain) {
|
||||
Logger.Information("AppDomain restart required.");
|
||||
_hostEnvironment.RestartAppDomain();
|
||||
|
@@ -24,7 +24,6 @@ namespace Orchard.Environment.Extensions {
|
||||
public IList<Action> CopyActions { get; private set; }
|
||||
|
||||
public bool RestartAppDomain { get; set; }
|
||||
public bool ResetSiteCompilation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of extensions (modules) present in the system
|
||||
|
@@ -76,19 +76,9 @@ namespace Orchard.Environment.Extensions.Loaders {
|
||||
}
|
||||
|
||||
public override void ExtensionRemoved(ExtensionLoadingContext ctx, DependencyDescriptor dependency) {
|
||||
// Since a dynamic assembly is not active anymore, we need to notify ASP.NET
|
||||
// that a new site compilation is needed (since ascx files may be referencing
|
||||
// this now removed extension).
|
||||
Logger.Information("ExtensionRemoved: Module \"{0}\" has been removed, forcing site recompilation", dependency.Name);
|
||||
ctx.ResetSiteCompilation = true;
|
||||
}
|
||||
|
||||
public override void ExtensionDeactivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) {
|
||||
// Since a dynamic assembly is not active anymore, we need to notify ASP.NET
|
||||
// that a new site compilation is needed (since ascx files may be referencing
|
||||
// this now removed extension).
|
||||
Logger.Information("ExtensionDeactivated: Module \"{0}\" has been de-activated, forcing site recompilation", extension.Id);
|
||||
ctx.ResetSiteCompilation = true;
|
||||
}
|
||||
|
||||
public override void ExtensionActivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) {
|
||||
|
@@ -17,10 +17,6 @@ namespace Orchard.Environment {
|
||||
return AppDomain.CurrentDomain.GetAssemblies().Any(assembly => new AssemblyName(assembly.FullName).Name == name);
|
||||
}
|
||||
|
||||
public void RestartAppDomain() {
|
||||
ResetSiteCompilation();
|
||||
}
|
||||
|
||||
public abstract void ResetSiteCompilation();
|
||||
public abstract void RestartAppDomain();
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
namespace Orchard.Environment {
|
||||
|
||||
namespace Orchard.Environment {
|
||||
/// <summary>
|
||||
/// Abstraction of the running environment
|
||||
/// </summary>
|
||||
@@ -9,6 +10,5 @@
|
||||
bool IsAssemblyLoaded(string name);
|
||||
|
||||
void RestartAppDomain();
|
||||
void ResetSiteCompilation();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user