#endif
#if NET_2_0
+ [assembly: InternalsVisibleTo ("System.Web, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: AssemblyFileVersion (Consts.FxFileVersion)]
[assembly: SecurityPermission (SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: Debuggable (DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
+2009-07-14 Marek Habersack <mhabersack@novell.com>
+
+ * AssemblyInfo.cs: added InternalsVisibleTo for System.Web
+
2008-04-15 Andreas Nahr <ClassDevelopment@A-SoftTech.com>
* AssemblyInfo.cs: Added missing attributes
+2009-07-14 Marek Habersack <mhabersack@novell.com>
+
+ * System.Configuration.dll.sources: added
+ System.Configuration/ConfigurationSaveEventArgs.cs
+ System.Configuration/ConfigurationSaveEventHandler.cs
+
2008-09-14 Gert Driesen <drieseng@users.sourceforge.net>
* System.Configuration_test.dll.sources: added
System.Configuration/ConfigurationPropertyOptions.cs
System.Configuration/ConfigurationRemoveElement.cs
System.Configuration/ConfigurationSaveMode.cs
+System.Configuration/ConfigurationSaveEventArgs.cs
+System.Configuration/ConfigurationSaveEventHandler.cs
System.Configuration/ConfigurationSection.cs
System.Configuration/ConfigurationSectionCollection.cs
System.Configuration/ConfigurationSectionGroup.cs
+2009-07-14 Marek Habersack <mhabersack@novell.com>
+
+ * ConfigurationSaveEventArgs.cs, ConfigurationSaveEventHandler.cs:
+ added
+
+ * Configuration.cs: added two internal events - SaveStart and
+ SaveEnd. They are used by System.Web's configuration system to
+ suppress application reloads when configuration is modified and
+ saved from within a web application. It is necessary to use events
+ since there is no guarantee the web application will use
+ WebConfigurationManager (and thus WebConfigurationHost) for
+ writing.
+
2009-06-08 Marek Habersack <mhabersack@novell.com>
* ConfigurationLocation.cs: if the path passed to constructor
using System;
using System.Collections;
using System.Collections.Specialized;
+using System.Configuration.Internal;
+using System.ComponentModel;
using System.Reflection;
using System.Xml;
using System.IO;
-using System.Configuration.Internal;
namespace System.Configuration {
public sealed class Configuration
- {
+ {
Configuration parent;
Hashtable elementData = new Hashtable ();
string streamName;
string locationConfigPath;
string locationSubPath;
+ internal static event ConfigurationSaveEventHandler SaveStart;
+ internal static event ConfigurationSaveEventHandler SaveEnd;
+
internal Configuration (Configuration parent, string locationSubPath)
{
this.parent = parent;
public void Save (ConfigurationSaveMode mode, bool forceUpdateAll)
{
+ ConfigurationSaveEventHandler saveStart = SaveStart;
+ ConfigurationSaveEventHandler saveEnd = SaveEnd;
+
object ctx = null;
+ Exception saveEx = null;
Stream stream = system.Host.OpenStreamForWrite (streamName, null, ref ctx);
try {
+ if (saveStart != null)
+ saveStart (this, new ConfigurationSaveEventArgs (streamName, true, null, ctx));
+
Save (stream, mode, forceUpdateAll);
system.Host.WriteCompleted (streamName, true, ctx);
- } catch (Exception) {
+ } catch (Exception ex) {
+ saveEx = ex;
system.Host.WriteCompleted (streamName, false, ctx);
throw;
} finally {
stream.Close ();
+ if (saveEnd != null)
+ saveEnd (this, new ConfigurationSaveEventArgs (streamName, false, saveEx, ctx));
}
}
--- /dev/null
+//
+// System.Configuration.ConfigurationSaveEventArgs.cs
+//
+// Authors:
+// Marek Habersack (mhabersack@novell.com)
+//
+// Copyright (C) 2009 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//
+#if NET_2_0
+using System;
+
+namespace System.Configuration
+{
+ class ConfigurationSaveEventArgs : EventArgs
+ {
+ public string StreamPath { get; private set; }
+ public bool Start { get; private set; }
+ public object Context { get; private set; }
+ public bool Failed { get; private set; }
+ public Exception Exception { get; private set; }
+
+ public ConfigurationSaveEventArgs (string streamPath, bool start, Exception ex, object context)
+ {
+ this.StreamPath = streamPath;
+ this.Start = start;
+ this.Failed = ex != null;
+ this.Exception = ex;
+ this.Context = context;
+ }
+ }
+}
+#endif
\ No newline at end of file
--- /dev/null
+//
+// System.Configuration.ConfigurationSaveEventHandler.cs
+//
+// Authors:
+// Marek Habersack (mhabersack@novell.com)
+//
+// Copyright (C) 2009 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//
+#if NET_2_0
+using System;
+
+namespace System.Configuration
+{
+ internal delegate void ConfigurationSaveEventHandler (Configuration sender, ConfigurationSaveEventArgs args);
+}
+#endif
+
\ No newline at end of file
+2009-07-14 Marek Habersack <mhabersack@novell.com>
+
+ * WebConfigurationManager.cs: added support for suppressing
+ application reload when the main config file is written to from
+ application.
+
+ * WebConfigurationHost.cs: added minimal implementation of
+ WriteCompleted, which checks if there's need to suppress
+ application reload.
+
2009-07-13 Marek Habersack <mhabersack@novell.com>
* ProvidersHelper.cs: InstantiateProvider doesn't have to
public virtual Stream OpenStreamForWrite (string streamName, string templateStreamName, ref object writeContext)
{
+ string rootConfigPath = GetWebConfigFileName (HttpRuntime.AppDomainAppPath);
+ if (String.Compare (streamName, rootConfigPath, StringComparison.OrdinalIgnoreCase) == 0)
+ WebConfigurationManager.SuppressAppReload (true);
return new FileStream (streamName, FileMode.Create, FileAccess.Write);
}
}
public virtual object StartMonitoringStreamForChanges (string streamName, StreamChangeCallback callback)
- {
+ {
throw new NotImplementedException ();
}
throw new ConfigurationErrorsException ("The section can't be defined in this file (the allowed definition context is '" + allowDefinition + "').", errorInfo.Filename, errorInfo.LineNumber);
}
- [MonoTODO("Does nothing")]
public virtual void WriteCompleted (string streamName, bool success, object writeContext)
{
- }
-
- [MonoTODO("Does nothing")]
+ WriteCompleted (streamName, success, writeContext, false);
+ }
+
public virtual void WriteCompleted (string streamName, bool success, object writeContext, bool assertPermissions)
{
+ // There are probably other things to be done here, but for the moment we
+ // just mark the completed write as one that should not cause application
+ // reload. Note that it might already be too late for suppression, since the
+ // FileSystemWatcher monitor might have already delivered the
+ // notification. If the stream has been open using OpenStreamForWrite then
+ // we're safe, though.
+ string rootConfigPath = GetWebConfigFileName (HttpRuntime.AppDomainAppPath);
+ if (String.Compare (streamName, rootConfigPath, StringComparison.OrdinalIgnoreCase) == 0)
+ WebConfigurationManager.SuppressAppReload (true);
}
public virtual bool SupportsChangeNotifications {
public static class WebConfigurationManager
{
#if !TARGET_J2EE
+ static readonly object suppressAppReloadLock = new object ();
+
static IInternalConfigConfigurationFactory configFactory;
static Hashtable configurations = Hashtable.Synchronized (new Hashtable ());
static Hashtable sectionCache = new Hashtable ();
static Hashtable configPaths = Hashtable.Synchronized (new Hashtable ());
+ static bool suppressAppReload;
#else
const string AppSettingsKey = "WebConfigurationManager.AppSettings";
static internal IInternalConfigConfigurationFactory configFactory
}
}
#endif
-
static ArrayList extra_assemblies = null;
static internal ArrayList ExtraAssemblies {
get {
static WebConfigurationManager ()
{
- PropertyInfo prop = typeof(ConfigurationManager).GetProperty ("ConfigurationFactory", BindingFlags.Static | BindingFlags.NonPublic);
- if (prop != null)
- configFactory = prop.GetValue (null, null) as IInternalConfigConfigurationFactory;
-
+ configFactory = ConfigurationManager.ConfigurationFactory;
+ _Configuration.SaveStart += ConfigurationSaveHandler;
+ _Configuration.SaveEnd += ConfigurationSaveHandler;
+
// Part of fix for bug #491531
Type type = Type.GetType ("System.Configuration.CustomizableFileSettingsProvider, System", false);
if (type != null) {
}
}
+ 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);
+ }
+
public static _Configuration OpenMachineConfiguration ()
{
return ConfigurationManager.OpenMachineConfiguration ();
HttpRequest req = ctx != null ? ctx.Request : null;
return req != null ? req.Path : HttpRuntime.AppDomainAppVirtualPath;
}
+
+ internal static bool SuppressAppReload (bool newValue)
+ {
+ bool ret;
+
+ lock (suppressAppReloadLock) {
+ ret = suppressAppReload;
+ suppressAppReload = newValue;
+ }
+ return ret;
+ }
+
internal static void RemoveConfigurationFromCache (HttpContext ctx)
{
configurations.Remove (GetCurrentPath (ctx));
// nothing. We need a context.
}
}
-
#endregion
}
+2009-07-14 Marek Habersack <mhabersack@novell.com>
+
+ * HttpApplicationFactory.cs: OnFileChanged doesn't reload
+ application if reload suppression is active.
+
2009-07-13 Marek Habersack <mhabersack@novell.com>
* HttpApplication.cs: LoadType - wrap call to LoadTypeFromBin in
static void OnFileChanged(object sender, FileSystemEventArgs args)
{
string name = args.Name;
+ bool isConfig = false;
+
if (StrUtils.EndsWith (name, "onfig", true)) {
if (String.Compare (Path.GetFileName (name), "web.config", true) != 0)
return;
+ isConfig = true;
} else if (StrUtils.EndsWith (name, "lobal.asax", true) && String.Compare (name, "global.asax", true) != 0)
return;
FileSystemWatcher watcher = sender as FileSystemWatcher;
if (watcher != null && String.Compare (watcher.Filter, "?eb.?onfig", true) == 0 && Directory.Exists (name))
return;
+
+#if NET_2_0
+ // We re-enable suppression here since WebConfigurationManager will disable
+ // it after save is done. WebConfigurationManager is called twice by
+ // Configuration - just after opening the target file and just after closing
+ // it. For that reason we will receive two change notifications and if we
+ // disabled suppression here, it would reload the application on the second
+ // change notification.
+ if (isConfig && WebConfigurationManager.SuppressAppReload (true))
+ return;
+#endif
lock (watchers_lock) {
if(app_shutdown)