internal void SaveAs(string filename, ConfigurationSaveMode saveMode, bool forceUpdateAll) {
// Get the updates.
SectionUpdates declarationUpdates = GetConfigDeclarationUpdates(saveMode, forceUpdateAll);
ConfigDefinitionUpdates definitionUpdates;
ArrayList configSourceUpdates;
bool checkedConfigForUpdates = false;
bool requireUpdates = (filename != null);
GetConfigDefinitionUpdates(requireUpdates, saveMode, forceUpdateAll, out definitionUpdates, out configSourceUpdates);
if (filename != null) {
Debug.Assert(filename.Length > 0, "The caller should make sure that filename is not empty");
//
// Verify that the filename is not being used.
//
// Note that if we are using a remote host, all the streamName's in _streamInfoUpdates
// are actually fullpaths on the remote machine. In this case there is no way to
// detect if we have a conflict or not.
if (!Host.IsRemote && _streamInfoUpdates.Contains(filename)) {
throw new ArgumentException(SR.GetString(SR.Filename_in_SaveAs_is_used_already, filename));
}
//
// If there was no config file for this config record,
// record the new stream name and version.
//
if (String.IsNullOrEmpty(ConfigStreamInfo.StreamName)) {
StreamInfo streamInfo = new StreamInfo(null, null, filename);
_streamInfoUpdates.Add(filename, streamInfo);
ConfigStreamInfo.StreamName = filename;
ConfigStreamInfo.StreamVersion = MonitorStream(null, null, ConfigStreamInfo.StreamName);
}
//
// Update the host to redirect filenames
//
UpdateConfigHost.AddStreamname(ConfigStreamInfo.StreamName, filename, Host.IsRemote);
// Redirect also all configSource filenames
foreach (StreamInfo streamInfo in _streamInfoUpdates.Values) {
if (!String.IsNullOrEmpty(streamInfo.SectionName)) {
// Get the new configSource streamName based on the new filename path
string newStreamName = InternalConfigHost.StaticGetStreamNameForConfigSource(
filename, streamInfo.ConfigSource);
// Ask UpdateConfigHost to intercept them.
UpdateConfigHost.AddStreamname(streamInfo.StreamName, newStreamName, Host.IsRemote);
}
}
}
if (!requireUpdates) {
// Check if there are any updates needed for the
// configuration record itself.
requireUpdates = RecordItselfRequiresUpdates;
}
if (declarationUpdates != null || definitionUpdates != null || requireUpdates) {
// Copy the input stream before opening the output stream.
byte[] readBuffer = null;
if (ConfigStreamInfo.HasStream) {
using (Stream streamRead = Host.OpenStreamForRead(ConfigStreamInfo.StreamName)) {
if (streamRead == null) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_has_changed), ConfigStreamInfo.StreamName, 0);
}
readBuffer = new byte[streamRead.Length];
int count = streamRead.Read(readBuffer, 0, (int) streamRead.Length);
if (count != streamRead.Length) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_data_read_count_mismatch));
}
}
}
string changedStreamName = FindChangedConfigurationStream();
if (changedStreamName != null) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_has_changed), changedStreamName, 0);
}
checkedConfigForUpdates = true;
// Write the changes to the output stream.
object writeContext = null;
bool streamOpened = false;
try {
try {
using (Stream streamWrite = Host.OpenStreamForWrite(ConfigStreamInfo.StreamName, null, ref writeContext)) {
streamOpened = true;
using (StreamWriter streamWriter = new StreamWriter(streamWrite)) {
XmlUtilWriter utilWriter = new XmlUtilWriter(streamWriter, true);
if (ConfigStreamInfo.HasStream) {
CopyConfig(declarationUpdates, definitionUpdates, readBuffer,
ConfigStreamInfo.StreamName, NamespaceChangeNeeded, utilWriter);
}
else {
CreateNewConfig(declarationUpdates, definitionUpdates, NamespaceChangeNeeded, utilWriter);
}
}
}
}
catch {
if (streamOpened) {
Host.WriteCompleted(ConfigStreamInfo.StreamName, false, writeContext);
}
throw;
}
}
//
// Guarantee that exceptions contain at least the name of the stream by wrapping them
// in a ConfigurationException.
//
catch (Exception e) {
throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), e, ConfigStreamInfo.StreamName, 0);
}
catch {
throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), null, ConfigStreamInfo.StreamName, 0);
}
Host.WriteCompleted(ConfigStreamInfo.StreamName, true, writeContext);
// Update stream information for the config file
ConfigStreamInfo.HasStream = true;
ConfigStreamInfo.ClearStreamInfos();
ConfigStreamInfo.StreamVersion = MonitorStream(null, null, ConfigStreamInfo.StreamName);
}
if (configSourceUpdates != null) {
// If we haven't checked before, check now
if (!checkedConfigForUpdates) {
string changedStreamName = FindChangedConfigurationStream();
if (changedStreamName != null) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_has_changed), changedStreamName, 0);
}
}
// write updates
foreach (DefinitionUpdate update in configSourceUpdates) {
SaveConfigSource(update);
}
}
// Update state to reflect the changes to the config file
UpdateRecords();
}