浏览代码

2009-07-15 Marek Habersack <[email protected]>

	* WebConfigurationManager.cs: another approach to suppressing
	application reloads after the app writes to its root web.config
	file. Leaving the previous code in place to get more
	protection. It's a kludge, but it's the best option to avoid
	all the races caused by System.Configuration+FileSystemWatcher
	without rewriting large parts of System.Configuration (and
	System.Web.Configuration). Fixes bug #522017

2009-07-15  Marek Habersack  <[email protected]>

	* Configuration.cs: explicitly flush the stream when writing XML
	data. Part of fix for bug #522017

2009-07-15  Marek Habersack  <[email protected]>

	* HttpApplicationFactory.cs: added internal methods to
	enable/disable specific watchers. Part of fix for bug #522017

svn path=/trunk/mcs/; revision=137951
Marek Habersack 16 年之前
父节点
当前提交
4a2ae0bb4f

+ 5 - 0
mcs/class/System.Configuration/System.Configuration/ChangeLog

@@ -1,3 +1,8 @@
+2009-07-15  Marek Habersack  <[email protected]>
+
+	* Configuration.cs: explicitly flush the stream when writing XML
+	data. Part of fix for bug #522017
+
 2009-07-14  Marek Habersack  <[email protected]>
 
 	* ConfigurationSaveEventArgs.cs, ConfigurationSaveEventHandler.cs:

+ 1 - 0
mcs/class/System.Configuration/System.Configuration/Configuration.cs

@@ -449,6 +449,7 @@ namespace System.Configuration {
 				tw.WriteEndElement ();
 			}
 			finally {
+				tw.Flush ();
 				tw.Close ();
 			}
 		}

+ 10 - 0
mcs/class/System.Web/System.Web.Configuration_2.0/ChangeLog

@@ -1,3 +1,13 @@
+2009-07-15  Marek Habersack  <[email protected]>
+
+	* WebConfigurationManager.cs: another approach to suppressing
+	application reloads after the app writes to its root web.config
+	file. Leaving the previous code in place to get more
+	protection. It's a kludge, but it's the best option to avoid
+	all the races caused by System.Configuration+FileSystemWatcher
+	without rewriting large parts of System.Configuration (and
+	System.Web.Configuration). Fixes bug #522017
+
 2009-07-14  Marek Habersack  <[email protected]>
 
 	* WebConfigurationManager.cs: added support for suppressing

+ 55 - 4
mcs/class/System.Web/System.Web.Configuration_2.0/WebConfigurationManager.cs

@@ -32,6 +32,7 @@
 using System;
 using System.IO;
 using System.Collections;
+using System.Collections.Generic;
 using System.Collections.Specialized;
 using System.Reflection;
 #if MONOWEB_DEP
@@ -42,14 +43,18 @@ using System.Configuration;
 using System.Configuration.Internal;
 using _Configuration = System.Configuration.Configuration;
 using System.Web.Util;
+using System.Threading;
 
 namespace System.Web.Configuration {
 
 	public static class WebConfigurationManager
 	{
-#if !TARGET_J2EE
+		const int SAVE_LOCATIONS_CHECK_INTERVAL = 6000; // milliseconds
+		
 		static readonly object suppressAppReloadLock = new object ();
+		static readonly object saveLocationsCacheLock = new object ();
 		
+#if !TARGET_J2EE
 		static IInternalConfigConfigurationFactory configFactory;
 		static Hashtable configurations = Hashtable.Synchronized (new Hashtable ());
 		static Hashtable sectionCache = new Hashtable ();
@@ -57,6 +62,7 @@ namespace System.Web.Configuration {
 		static bool suppressAppReload;
 #else
 		const string AppSettingsKey = "WebConfigurationManager.AppSettings";
+		
 		static internal IInternalConfigConfigurationFactory configFactory
 		{
 			get{
@@ -142,6 +148,9 @@ namespace System.Web.Configuration {
 			}
 		}
 #endif
+		static Dictionary <string, DateTime> saveLocationsCache;
+		static Timer saveLocationsTimer;
+		
 		static ArrayList extra_assemblies = null;
 		static internal ArrayList ExtraAssemblies {
 			get {
@@ -176,11 +185,53 @@ namespace System.Web.Configuration {
 			}
 		}
 
+		static void ReenableWatcherOnConfigLocation (object state)
+		{
+			string path = state as string;
+			if (String.IsNullOrEmpty (path))
+				return;
+
+			DateTime lastWrite;
+			lock (saveLocationsCacheLock) {
+				if (!saveLocationsCache.TryGetValue (path, out lastWrite))
+					lastWrite = DateTime.MinValue;
+			}
+
+			DateTime now = DateTime.Now;
+			if (lastWrite == DateTime.MinValue || now.Subtract (lastWrite).TotalMilliseconds >= SAVE_LOCATIONS_CHECK_INTERVAL) {
+				saveLocationsTimer.Dispose ();
+				saveLocationsTimer = null;
+				HttpApplicationFactory.EnableWatcher (VirtualPathUtility.RemoveTrailingSlash (HttpRuntime.AppDomainAppPath), "?eb.?onfig");
+			} else
+				saveLocationsTimer.Change (SAVE_LOCATIONS_CHECK_INTERVAL, SAVE_LOCATIONS_CHECK_INTERVAL);
+		}
+		
 		static void ConfigurationSaveHandler (_Configuration sender, ConfigurationSaveEventArgs args)
 		{
-			string rootConfigPath = WebConfigurationHost.GetWebConfigFileName (HttpRuntime.AppDomainAppPath);
-			if (String.Compare (args.StreamPath, rootConfigPath, StringComparison.OrdinalIgnoreCase) == 0)
-				SuppressAppReload (args.Start);
+			lock (suppressAppReloadLock) {
+				string rootConfigPath = WebConfigurationHost.GetWebConfigFileName (HttpRuntime.AppDomainAppPath);
+				if (String.Compare (args.StreamPath, rootConfigPath, StringComparison.OrdinalIgnoreCase) == 0) {
+					SuppressAppReload (args.Start);
+					if (args.Start) {
+						HttpApplicationFactory.DisableWatcher (VirtualPathUtility.RemoveTrailingSlash (HttpRuntime.AppDomainAppPath), "?eb.?onfig");
+
+						lock (saveLocationsCacheLock) {
+							if (saveLocationsCache == null)
+								saveLocationsCache = new Dictionary <string, DateTime> (StringComparer.Ordinal);
+							if (saveLocationsCache.ContainsKey (rootConfigPath))
+								saveLocationsCache [rootConfigPath] = DateTime.Now;
+							else
+								saveLocationsCache.Add (rootConfigPath, DateTime.Now);
+
+							if (saveLocationsTimer == null)
+								saveLocationsTimer = new Timer (ReenableWatcherOnConfigLocation,
+												rootConfigPath,
+												SAVE_LOCATIONS_CHECK_INTERVAL,
+												SAVE_LOCATIONS_CHECK_INTERVAL);
+						}
+					}
+				}
+			}
 		}
 		
 		public static _Configuration OpenMachineConfiguration ()

+ 5 - 0
mcs/class/System.Web/System.Web/ChangeLog

@@ -1,3 +1,8 @@
+2009-07-15  Marek Habersack  <[email protected]>
+
+	* HttpApplicationFactory.cs: added internal methods to
+	enable/disable specific watchers. Part of fix for bug #522017
+
 2009-07-14 Gonzalo Paniagua Javier <[email protected]>
 
 	* ApplicationShutdownReason.cs: add new 3.5 value.

+ 28 - 0
mcs/class/System.Web/System.Web/HttpApplicationFactory.cs

@@ -701,6 +701,34 @@ namespace System.Web {
 			}
 		}
 
+		internal static void DisableWatcher (string virtualPath, string filter)
+		{
+			EnableWatcherEvents (virtualPath, filter, false);
+		}
+
+		internal static void EnableWatcher (string virtualPath, string filter)
+		{
+			EnableWatcherEvents (virtualPath, filter, true);
+		}
+		
+		static void EnableWatcherEvents (string virtualPath, string filter, bool enable)
+		{
+			lock (watchers_lock) {
+				foreach (FileSystemWatcher watcher in watchers) {
+					if (
+#if NET_2_0
+						String.Compare (watcher.Path, virtualPath, StringComparison.Ordinal) != 0 || String.Compare (watcher.Filter, filter, StringComparison.Ordinal) != 0
+#else
+						String.Compare (watcher.Path, virtualPath) != 0 || String.Compare (watcher.Filter, filter) != 0
+#endif
+					)
+						continue;
+					
+					watcher.EnableRaisingEvents = enable;
+				}
+			}
+		}
+		
 		internal static void EnableWatchers ()
 		{
 			lock (watchers_lock) {