Wcf System.Exception.Data不会在DataContract上序列化?

Wcf System.Exception.Data不会在DataContract上序列化?,wcf,enterprise-library,servicecontract,faultcontract,Wcf,Enterprise Library,Servicecontract,Faultcontract,我有一些使用dataContracts的WCF服务,我想我希望通过data属性中的custom Dictionarydata传递一个异常,但是当我在抛出之前在此数组中添加任何数据时,我在自定义ServiceBehavior的ErrorHandler中得到以下错误: 使用数据合同名称 'ArrayOfKeyValueOfAnyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' 这是预料不到的。添加任何不需要的类型 静态已知

我有一些使用dataContracts的WCF服务,我想我希望通过data属性中的custom Dictionarydata传递一个异常,但是当我在抛出之前在此数组中添加任何数据时,我在自定义ServiceBehavior的ErrorHandler中得到以下错误:

使用数据合同名称 'ArrayOfKeyValueOfAnyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' 这是预料不到的。添加任何不需要的类型 静态已知到已知的列表 类型-例如,通过使用 KnownTypeAttribute属性或由 将它们添加到已知类型列表中 传递给DataContractSerializer

我是否总是需要创建一个带有注释为DataContract的Dictionary属性的自定义异常并抛出它?使用ErrorHandler的想法是避免在每个服务方法中处理异常,我是否仍然需要向这些方法添加更多注释?我错过了什么

作为参考,这是我的FaultErrorHandler类:

public class FaultErrorHandler : BehaviorExtensionElement, IErrorHandler, IServiceBehavior
    {
        public bool HandleError(Exception error)
        {
            if (!Logger.IsLoggingEnabled()) return true;
            var logEntry = new LogEntry
            {
                EventId = 100,
                Severity = TraceEventType.Error,
                Priority = 1,
                Title = "WCF Failure",
                Message = string.Format("Error occurred: {0}", error)
            };
            logEntry.Categories.Add("MiddleTier");

            Logger.Write(logEntry);
            return true;
        }

        public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
        {
            var faultException = new FaultException<Exception>( error, new FaultReason(string.Format("System error occurred, exception: {0}", error)));
            var faultMessage = faultException.CreateMessageFault();
            fault = Message.CreateMessage(version, faultMessage, Schema.WebServiceStandard);
        }

        public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher chanDisp in serviceHostBase.ChannelDispatchers)
            {
                chanDisp.ErrorHandlers.Add(this);
            };
        }

        public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
        }

        public override Type BehaviorType
        {
            get { return typeof(FaultErrorHandler); }
        }

        protected override object CreateBehavior()
        {
            return new FaultErrorHandler();
        }
    }

System.Exception实现ISerializable,序列化程序与字典的处理方式相同-它可以[反]序列化,但您需要告诉序列化程序哪些类型将被[反]序列化。在发生异常的情况下,您无法更改类声明,因此如果您想使此场景正常工作,您需要在服务契约中为将用于数据属性的两个类(使用内部类型
System.Collections.ListDictionaryInternal
)添加已知类型(使用[ServiceKnownType])对于要添加到数据字典中的任何类型。下面的代码展示了如何做到这一点(尽管我真的不建议这样做,但您应该定义一些DTO类型来处理需要返回的信息,以避免必须处理Exception类的内部实现细节)

public class StackOverflow_6552443
{
    [DataContract]
    [KnownType("GetKnownTypes")]
    public class MyDCWithException
    {
        [DataMember]
        public Exception myException;

        public static MyDCWithException GetInstance()
        {
            MyDCWithException result = new MyDCWithException();
            result.myException = new ArgumentException("Invalid value");
            result.myException.Data["someData"] = new Dictionary<string, object>
            {
                { "One", 1 },
                { "Two", 2 },
                { "Three", 3 },
            };
            return result;
        }

        public static Type[] GetKnownTypes()
        {
            List<Type> result = new List<Type>();
            result.Add(typeof(ArgumentException));
            result.Add(typeof(Dictionary<string, object>));
            result.Add(typeof(IDictionary).Assembly.GetType("System.Collections.ListDictionaryInternal"));
            return result.ToArray();
        }
    }
    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        MyDCWithException GetDCWithException();
    }
    public class Service : ITest
    {
        public MyDCWithException GetDCWithException()
        {
            return MyDCWithException.GetInstance();
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
        host.Open();
        Console.WriteLine("Host opened");

        ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
        ITest proxy = factory.CreateChannel();

        Console.WriteLine(proxy.GetDCWithException());

        ((IClientChannel)proxy).Close();
        factory.Close();

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
公共类StackOverflow_6552443
{
[数据合同]
[KnownType(“GetKnownType”)]
公共类MyDCWithException
{
[数据成员]
公共例外;
公共静态MyDCWithException GetInstance()
{
MyDCWithException结果=新的MyDCWithException();
result.myException=新ArgumentException(“无效值”);
result.myException.Data[“someData”]=新字典
{
{“一”,1},
{“两个”,2},
{“三”,3},
};
返回结果;
}
公共静态类型[]GetKnownTypes()
{
列表结果=新列表();
添加(typeof(ArgumentException));
结果。添加(字典的类型);
Add(typeof(IDictionary.Assembly.GetType(“System.Collections.ListDictionaryInternal”);
返回result.ToArray();
}
}
[服务合同]
公共接口测试
{
[经营合同]
MyDCWithException GetDCWithException();
}
公共类服务:ITest
{
公共MyDCWithException GetDCWithException()
{
返回MyDCWithException.GetInstance();
}
}
公共静态无效测试()
{
string baseAddress=“http://“+Environment.MachineName+”:8000/服务”;
ServiceHost主机=新ServiceHost(类型(服务),新Uri(基地址));
AddServiceEndpoint(typeof(ITest),new BasicHttpBinding(),“”);
host.Open();
Console.WriteLine(“主机已打开”);
ChannelFactory工厂=新的ChannelFactory(新的BasicHttpBinding(),新的EndpointAddress(baseAddress));
ITest proxy=factory.CreateChannel();
Console.WriteLine(proxy.GetDCWithException());
((IClientChannel)代理).Close();
工厂关闭();
控制台。写入(“按ENTER键关闭主机”);
Console.ReadLine();
host.Close();
}
}

System.Exception实现ISerializable,序列化程序处理ISerializable的方式与字典处理的方式相同-它可以[反]序列化,但您需要告诉序列化程序哪些类型将[反]序列化序列化。在发生异常的情况下,您无法更改类声明,因此如果要使此场景正常工作,您需要在服务契约中为将用于数据属性的两个类(使用内部类型
System.Collections.ListDictionaryInternal
)添加已知类型(使用[ServiceKnownType])下面的代码展示了如何做到这一点(尽管我真的不建议这样做,但您应该定义一些DTO类型来处理需要返回的信息,以避免必须处理异常类的内部实现细节)

public class StackOverflow_6552443
{
    [DataContract]
    [KnownType("GetKnownTypes")]
    public class MyDCWithException
    {
        [DataMember]
        public Exception myException;

        public static MyDCWithException GetInstance()
        {
            MyDCWithException result = new MyDCWithException();
            result.myException = new ArgumentException("Invalid value");
            result.myException.Data["someData"] = new Dictionary<string, object>
            {
                { "One", 1 },
                { "Two", 2 },
                { "Three", 3 },
            };
            return result;
        }

        public static Type[] GetKnownTypes()
        {
            List<Type> result = new List<Type>();
            result.Add(typeof(ArgumentException));
            result.Add(typeof(Dictionary<string, object>));
            result.Add(typeof(IDictionary).Assembly.GetType("System.Collections.ListDictionaryInternal"));
            return result.ToArray();
        }
    }
    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        MyDCWithException GetDCWithException();
    }
    public class Service : ITest
    {
        public MyDCWithException GetDCWithException()
        {
            return MyDCWithException.GetInstance();
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
        host.Open();
        Console.WriteLine("Host opened");

        ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
        ITest proxy = factory.CreateChannel();

        Console.WriteLine(proxy.GetDCWithException());

        ((IClientChannel)proxy).Close();
        factory.Close();

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
公共类StackOverflow_6552443
{
[数据合同]
[KnownType(“GetKnownType”)]
公共类MyDCWithException
{
[数据成员]
公共例外;
公共静态MyDCWithException GetInstance()
{
MyDCWithException结果=新的MyDCWithException();
result.myException=新ArgumentException(“无效值”);
result.myException.Data[“someData”]=新字典
{
{“一”,1},
{“两个”,2},
{“三”,3},
};
返回结果;
}
公共静态类型[]GetKnownTypes()
{
列表结果=新列表();
添加(typeof(ArgumentException));
结果。添加(字典的类型);
Add(typeof(IDictionary.Assembly.GetType(“System.Collections.ListDictionaryInternal”);
返回result.ToArray();
}
}
[服务合同]
公共接口测试
{
[经营合同]
MyDCWithException GetDCWithException();
}
公务舱服务
public class StackOverflow_6552443
{
    [DataContract]
    [KnownType("GetKnownTypes")]
    public class MyDCWithException
    {
        [DataMember]
        public Exception myException;

        public static MyDCWithException GetInstance()
        {
            MyDCWithException result = new MyDCWithException();
            result.myException = new ArgumentException("Invalid value");
            result.myException.Data["someData"] = new Dictionary<string, object>
            {
                { "One", 1 },
                { "Two", 2 },
                { "Three", 3 },
            };
            return result;
        }

        public static Type[] GetKnownTypes()
        {
            List<Type> result = new List<Type>();
            result.Add(typeof(ArgumentException));
            result.Add(typeof(Dictionary<string, object>));
            result.Add(typeof(IDictionary).Assembly.GetType("System.Collections.ListDictionaryInternal"));
            return result.ToArray();
        }
    }
    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        MyDCWithException GetDCWithException();
    }
    public class Service : ITest
    {
        public MyDCWithException GetDCWithException()
        {
            return MyDCWithException.GetInstance();
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
        host.Open();
        Console.WriteLine("Host opened");

        ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
        ITest proxy = factory.CreateChannel();

        Console.WriteLine(proxy.GetDCWithException());

        ((IClientChannel)proxy).Close();
        factory.Close();

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}