File: sys\system\configuration\ConfigurationException.cs
Project: ndp\fx\src\System.csproj (System)
//------------------------------------------------------------------------------
// <copyright file="ConfigurationException.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
namespace System.Configuration {
    using System.Configuration.Internal;
    using System.Globalization;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Security;
    using System.Security.Permissions;
    using System.Xml;
    using System.Collections;
    using System.Runtime.Versioning;
 
    // A config exception can contain a filename (of a config file)
    // and a line number (of the location in the file in which a problem was
    // encountered).
    // 
    // Section handlers should throw this exception (or subclasses)
    // together with filename and line nubmer information where possible.
    [Serializable]
    public class ConfigurationException : SystemException {
        private const string    HTTP_PREFIX = "http:";
 
        private string          _filename; 
        private int             _line;     
 
        void Init(string filename, int line) {
            HResult = HResults.Configuration;
            _filename = filename;
            _line = line;
        }
 
        // Default ctor is required for serialization.
        protected ConfigurationException(SerializationInfo info, StreamingContext context) : base(info, context) { 
            Init(info.GetString("filename"), info.GetInt32("line"));
        }
 
        [Obsolete("This class is obsolete, to create a new exception create a System." +
                  "Configuration!System.Configuration.ConfigurationErrorsException")]
        public ConfigurationException() : 
                this(null, null, null, 0) {}
 
        [Obsolete("This class is obsolete, to create a new exception create a System." +
                  "Configuration!System.Configuration.ConfigurationErrorsException")]
        public ConfigurationException(string message) : 
                this(message, null, null, 0) {}
 
        [Obsolete("This class is obsolete, to create a new exception create a System." +
                  "Configuration!System.Configuration.ConfigurationErrorsException")]
        public ConfigurationException(string message, Exception inner) : 
                this(message, inner, null, 0) {}
 
 
        [Obsolete("This class is obsolete, to create a new exception create a System." +
                  "Configuration!System.Configuration.ConfigurationErrorsException")]
        public ConfigurationException(string message, XmlNode node) : 
                this(message, null, GetUnsafeXmlNodeFilename(node), GetXmlNodeLineNumber(node)) {}
 
        [Obsolete("This class is obsolete, to create a new exception create a System." +
                  "Configuration!System.Configuration.ConfigurationErrorsException")]
        public ConfigurationException(string message, Exception inner, XmlNode node) : 
                this(message, inner, GetUnsafeXmlNodeFilename(node), GetXmlNodeLineNumber(node)) {}
 
 
        [Obsolete("This class is obsolete, to create a new exception create a System." +
                  "Configuration!System.Configuration.ConfigurationErrorsException")]
        public ConfigurationException(string message, string filename, int line) :
                this(message, null, filename, line) {}
 
        [Obsolete("This class is obsolete, to create a new exception create a System." +
                  "Configuration!System.Configuration.ConfigurationErrorsException")]
        public ConfigurationException(string message, Exception inner, string filename, int line) : base(message, inner) {
            Init(filename, line);
        }
 
        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context) {
            base.GetObjectData(info, context);
            info.AddValue("filename", _filename);
            info.AddValue("line", _line);
        }
 
        // The message includes the file/line number information.  
        // To get the message without the extra information, use BareMessage.
        public override string Message {
            get {
                string file = Filename;
                if (!string.IsNullOrEmpty(file)) {
                    if (Line != 0) {
                        return BareMessage + " (" + file + " line " + Line.ToString(CultureInfo.InvariantCulture) + ")";
                    }
                    else {
                        return BareMessage + " (" + file + ")";
                    }
                }
                else if (Line != 0) {
                    return BareMessage + " (line " + Line.ToString("G", CultureInfo.InvariantCulture) + ")";
                }
                else {
                    return BareMessage;
                }
            }
        }
 
        public virtual string BareMessage {
            get {
                return base.Message;
            }
        }
 
        public virtual string Filename {
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                return SafeFilename(_filename);
            }
        }
 
        public virtual int Line {
            get {
                return _line;
            }
        }
 
        [Obsolete("This class is obsolete, use System.Configuration!System.Configuration." +
                  "ConfigurationErrorsException.GetFilename instead")]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static string GetXmlNodeFilename(XmlNode node) {
            return SafeFilename(GetUnsafeXmlNodeFilename(node));
        }
 
        [Obsolete("This class is obsolete, use System.Configuration!System.Configuration." +
                  "ConfigurationErrorsException.GetLinenumber instead")]
        public static int GetXmlNodeLineNumber(XmlNode node) {
            IConfigErrorInfo configNode = node as IConfigErrorInfo;
 
            if (configNode != null) {
                return configNode.LineNumber;
            }
            return 0;
        }
 
        [FileIOPermission(SecurityAction.Assert, AllFiles=FileIOPermissionAccess.PathDiscovery)]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private static string FullPathWithAssert(string filename) {
            string fullPath = null;
 
            try {
                fullPath = Path.GetFullPath(filename);
            }
            catch {
            }
 
            return fullPath;
        }
 
        // 
        // Internal Helper to strip a full path to just filename.ext when caller 
        // does not have path discovery to the path (used for sane error handling).
        //
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        internal static string SafeFilename(string filename) {
            if (string.IsNullOrEmpty(filename)) {
                return filename;
            }
 
            // configuration file can be an http URL in IE
            if (filename.StartsWith(HTTP_PREFIX, StringComparison.OrdinalIgnoreCase)) {
                return filename;
            }
 
            //
            // If it is a relative path, return it as is. 
            // This could happen if the exception was constructed from the serialization constructor,
            // and the caller did not have PathDiscoveryPermission for the file.
            //
            try {
                if (!Path.IsPathRooted(filename)) {
                    return filename;
                }
            }
            catch {
                return null;
            }
 
            try {
                // Confirm that it is a full path.
                // GetFullPath will also Demand PathDiscovery for the resulting path
                string fullPath = Path.GetFullPath(filename);
            } 
            catch (SecurityException) {
                // Get just the name of the file without the directory part.
                try {
                    string fullPath = FullPathWithAssert(filename);
                    filename = Path.GetFileName(fullPath);
                }
                catch {
                    filename = null;
                }
            }
            catch {
                filename = null;
            }
 
            return filename;
        }
 
        private static string GetUnsafeXmlNodeFilename(XmlNode node) {
            IConfigErrorInfo configNode = node as IConfigErrorInfo;
 
            if (configNode != null) {
                return configNode.Filename;
            }
 
            return string.Empty;
        }
    }
}