File: System\ServiceModel\FaultException.cs
Web Access
Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
 
using System.Collections.Generic;
using System.Runtime;
using System.Runtime.Serialization;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
 
namespace System.ServiceModel
{
    [Serializable]
    [KnownType(typeof(FaultCodeData))]
    [KnownType(typeof(FaultCodeData[]))]
    [KnownType(typeof(FaultReasonData))]
    [KnownType(typeof(FaultReasonData[]))]
    public class FaultException : CommunicationException
    {
        internal const string Namespace = "http://schemas.xmlsoap.org/Microsoft/WindowsCommunicationFoundation/2005/08/Faults/";
 
        public FaultException()
            : base(SRP.SFxFaultReason)
        {
            Code = DefaultCode;
            Reason = DefaultReason;
        }
 
        public FaultException(string reason)
            : base(reason)
        {
            Code = DefaultCode;
            Reason = CreateReason(reason);
        }
 
        public FaultException(FaultReason reason)
            : base(GetSafeReasonText(reason))
        {
            Code = DefaultCode;
            Reason = EnsureReason(reason);
        }
 
        public FaultException(string reason, FaultCode code)
            : base(reason)
        {
            Code = EnsureCode(code);
            Reason = CreateReason(reason);
        }
 
        public FaultException(FaultReason reason, FaultCode code)
            : base(GetSafeReasonText(reason))
        {
            Code = EnsureCode(code);
            Reason = EnsureReason(reason);
        }
 
        public FaultException(string reason, FaultCode code, string action)
            : base(reason)
        {
            Code = EnsureCode(code);
            Reason = CreateReason(reason);
            Action = action;
        }
 
        internal FaultException(string reason, FaultCode code, string action, Exception innerException)
            : base(reason, innerException)
        {
            Code = EnsureCode(code);
            Reason = CreateReason(reason);
            Action = action;
        }
 
        public FaultException(FaultReason reason, FaultCode code, string action)
            : base(GetSafeReasonText(reason))
        {
            Code = EnsureCode(code);
            Reason = EnsureReason(reason);
            Action = action;
        }
 
        internal FaultException(FaultReason reason, FaultCode code, string action, Exception innerException)
            : base(GetSafeReasonText(reason), innerException)
        {
            Code = EnsureCode(code);
            Reason = EnsureReason(reason);
            Action = action;
        }
 
        public FaultException(MessageFault fault)
            : base(GetSafeReasonText(GetReason(fault)))
        {
            if (fault == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(fault));
            }
 
            Code = EnsureCode(fault.Code);
            Reason = EnsureReason(fault.Reason);
            Fault = fault;
        }
 
        public FaultException(MessageFault fault, string action)
            : base(GetSafeReasonText(GetReason(fault)))
        {
            if (fault == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(fault));
            }
 
            Code = fault.Code;
            Reason = fault.Reason;
            Fault = fault;
            Action = action;
        }
 
#pragma warning disable SYSLIB0051
        protected FaultException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            Code = ReconstructFaultCode(info, "code");
            Reason = ReconstructFaultReason(info, "reason");
            Fault = (MessageFault)info.GetValue("messageFault", typeof(MessageFault));
            Action = info.GetString("action");
        }
#pragma warning restore SYSLIB0051
 
        public string Action { get; }
 
        public FaultCode Code { get; }
 
        private static FaultReason DefaultReason
        {
            get { return new FaultReason(SRP.SFxFaultReason); }
        }
 
        private static FaultCode DefaultCode
        {
            get { return new FaultCode("Sender"); }
        }
 
        public override string Message
        {
            get { return GetSafeReasonText(Reason); }
        }
 
        public FaultReason Reason { get; }
 
        internal MessageFault Fault { get; }
 
        internal void AddFaultCodeObjectData(SerializationInfo info, string key, FaultCode code)
        {
            info.AddValue(key, FaultCodeData.GetObjectData(code));
        }
 
        internal void AddFaultReasonObjectData(SerializationInfo info, string key, FaultReason reason)
        {
            info.AddValue(key, FaultReasonData.GetObjectData(reason));
        }
 
        public static FaultException CreateFault(MessageFault messageFault, params Type[] faultDetailTypes)
        {
            return CreateFault(messageFault, null, faultDetailTypes);
        }
 
        public static FaultException CreateFault(MessageFault messageFault, string action, params Type[] faultDetailTypes)
        {
            if (messageFault == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(messageFault));
            }
 
            if (faultDetailTypes == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(faultDetailTypes));
            }
            DataContractSerializerFaultFormatter faultFormatter = new DataContractSerializerFaultFormatter(faultDetailTypes);
            return faultFormatter.Deserialize(messageFault, action);
        }
 
        public virtual MessageFault CreateMessageFault()
        {
            if (Fault != null)
            {
                return Fault;
            }
            else
            {
                return MessageFault.CreateFault(Code, Reason);
            }
        }
 
        private static FaultReason CreateReason(string reason)
        {
            return (reason != null) ? new FaultReason(reason) : DefaultReason;
        }
 
        [System.Obsolete]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            AddFaultCodeObjectData(info, "code", Code);
            AddFaultReasonObjectData(info, "reason", Reason);
            info.AddValue("messageFault", Fault);
            info.AddValue("action", Action);
        }
 
        private static FaultReason GetReason(MessageFault fault)
        {
            if (fault == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(fault));
            }
            return fault.Reason;
        }
 
        internal static string GetSafeReasonText(MessageFault messageFault)
        {
            if (messageFault == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(messageFault));
            }
 
            return GetSafeReasonText(messageFault.Reason);
        }
 
        internal static string GetSafeReasonText(FaultReason reason)
        {
            if (reason == null)
            {
                return SRP.SFxUnknownFaultNullReason0;
            }
 
            try
            {
                return reason.GetMatchingTranslation(Globalization.CultureInfo.CurrentCulture).Text;
            }
            catch (ArgumentException)
            {
                if (reason.Translations.Count == 0)
                {
                    return SRP.SFxUnknownFaultZeroReasons0;
                }
                else
                {
                    return SRP.Format(SRP.SFxUnknownFaultNoMatchingTranslation1, reason.Translations[0].Text);
                }
            }
        }
 
        private static FaultCode EnsureCode(FaultCode code)
        {
            return (code != null) ? code : DefaultCode;
        }
 
        private static FaultReason EnsureReason(FaultReason reason)
        {
            return (reason != null) ? reason : DefaultReason;
        }
 
        internal FaultCode ReconstructFaultCode(SerializationInfo info, string key)
        {
            FaultCodeData[] data = (FaultCodeData[])info.GetValue(key, typeof(FaultCodeData[]));
            return FaultCodeData.Construct(data);
        }
 
        internal FaultReason ReconstructFaultReason(SerializationInfo info, string key)
        {
            FaultReasonData[] data = (FaultReasonData[])info.GetValue(key, typeof(FaultReasonData[]));
            return FaultReasonData.Construct(data);
        }
 
        [Serializable]
        internal class FaultCodeData
        {
            private string name;
            private string ns;
 
            internal static FaultCode Construct(FaultCodeData[] nodes)
            {
                FaultCode code = null;
                for (int i = nodes.Length - 1; i >= 0; i--)
                {
                    code = new FaultCode(nodes[i].name, nodes[i].ns, code);
                }
 
                return code;
            }
 
            internal static FaultCodeData[] GetObjectData(FaultCode code)
            {
                FaultCodeData[] array = new FaultCodeData[GetDepth(code)];
 
                for (int i = 0; i < array.Length; i++)
                {
                    array[i] = new FaultCodeData();
                    array[i].name = code.Name;
                    array[i].ns = code.Namespace;
                    code = code.SubCode;
                }
 
                Fx.Assert(code == null, "FaultException.FaultCodeData.GetObjectData: (code != null)");
                return array;
            }
 
            private static int GetDepth(FaultCode code)
            {
                int depth = 0;
 
                while (code != null)
                {
                    depth++;
                    code = code.SubCode;
                }
 
                return depth;
            }
        }
 
        [Serializable]
        internal class FaultReasonData
        {
            private string xmlLang;
            private string text;
 
            internal static FaultReason Construct(FaultReasonData[] nodes)
            {
                FaultReasonText[] reasons = new FaultReasonText[nodes.Length];
 
                for (int i = 0; i < nodes.Length; i++)
                {
                    reasons[i] = new FaultReasonText(nodes[i].text, nodes[i].xmlLang);
                }
 
                return new FaultReason(reasons);
            }
 
            internal static FaultReasonData[] GetObjectData(FaultReason reason)
            {
                SynchronizedReadOnlyCollection<FaultReasonText> translations = reason.Translations;
                FaultReasonData[] array = new FaultReasonData[translations.Count];
 
                for (int i = 0; i < translations.Count; i++)
                {
                    array[i] = new FaultReasonData();
                    array[i].xmlLang = translations[i].XmlLang;
                    array[i].text = translations[i].Text;
                }
 
                return array;
            }
        }
    }
 
    [Serializable]
    [KnownType("GetKnownTypes")]
    public class FaultException<TDetail> : FaultException
    {
        public FaultException(TDetail detail)
            : base()
        {
            Detail = detail;
        }
 
        public FaultException(TDetail detail, string reason)
            : base(reason)
        {
            Detail = detail;
        }
 
        public FaultException(TDetail detail, FaultReason reason)
            : base(reason)
        {
            Detail = detail;
        }
 
        public FaultException(TDetail detail, string reason, FaultCode code)
            : base(reason, code)
        {
            Detail = detail;
        }
 
        public FaultException(TDetail detail, FaultReason reason, FaultCode code)
            : base(reason, code)
        {
            Detail = detail;
        }
 
        public FaultException(TDetail detail, string reason, FaultCode code, string action)
            : base(reason, code, action)
        {
            Detail = detail;
        }
 
        public FaultException(TDetail detail, FaultReason reason, FaultCode code, string action)
            : base(reason, code, action)
        {
            Detail = detail;
        }
 
#pragma warning disable SYSLIB0051
        protected FaultException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            Detail = (TDetail)info.GetValue("detail", typeof(TDetail));
        }
#pragma warning restore SYSLIB0051
 
        public TDetail Detail { get; }
 
        public override MessageFault CreateMessageFault()
        {
            return MessageFault.CreateFault(Code, Reason, Detail);
        }
 
        [System.Obsolete]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("detail", Detail);
        }
 
        public override string ToString()
        {
            return SRP.Format(SRP.SFxFaultExceptionToString3, GetType(), Message, Detail != null ? Detail.ToString() : string.Empty);
        }
 
        private static Type[] s_knownTypes = new Type[] { typeof(TDetail) };
        internal static IEnumerable<Type> GetKnownTypes()
        {
            return s_knownTypes;
        }
    }
}