我正在开发WCF服务。
其中一个OperationContracts将复杂类型作为参数之一(System.Exception是特定的)。
当客户端调用代理时,如果我创建新的异常,例如
System.Exception toNewException = new Exception();
发送它......它的效果相当不错。
但是如果我尝试发送'System.Web.HttpUnhandledException'类型的异常。服务故障类型未知。 (见下面的错误)
尝试序列化参数时出错 http://tempuri.org/:Exception。 InnerException消息是'Type 带有数据协定名称的'System.Web.HttpUnhandledException' 'HttpUnhandledException:HTTP://schemas.datacontract.org/2004/07/System.Web' 不是预期的。将任何静态未知的类型添加到列表中 已知类型 - 例如,通过使用KnownTypeAttribute属性 或者将它们添加到传递给的已知类型列表中 DataContractSerializer的。“。有关详细信息,请参阅InnerException。
我已经研究过已知的类型属性......但到目前为止我还没有找到任何有帮助的例子或文档。
任何人都知道有关我如何能够改变我的客户端/服务器以接受/处理任何异常的信息的良好来源?
让我的问题更加详细......错误说明; '将任何已知类型的静态已知类型添加到已知类型中。这就是我想知道如何专门处理复杂的.net对象,如system.exception。
更新
我尝试进行以下更改:
[OperationContract]
[ServiceKnownType(typeof(HttpUnhandledException))]
void LogError(Exception Exception, Boolean LogInternalFlag, int UserId, int ApplicationId, int SeverityId);
我最终得到了另一个错误!
尝试序列化参数时出错 http://tempuri.org/:Exception。 InnerException消息是'Type 带有数据协定名称的'System.Collections.ListDictionaryInternal' 'ArrayOfKeyValueOfanyTypeanyType:HTTP://schemas.microsoft.com/2003/10/Serialization/Arrays' 不是预期的。将任何静态未知的类型添加到列表中 已知类型 - 例如,通过使用KnownTypeAttribute属性 或者将它们添加到传递给的已知类型列表中 DataContractSerializer的。“。有关详细信息,请参阅InnerException。
除了有意义的错误之外还有错误......我不确定这意味着什么。
我还要投入,我确实尝试将异常序列化为xml并将其作为字符串传递...遗憾的是,这并不像听起来那么简单,并且需要考虑很多因素用于序列化异常和任何内部异常。
答案 0 :(得分:2)
问题不在于类型复杂。您的问题是您的合同是使用基类(Exception)声明的,并且您传入了子类(HttpUnhandledException)。您未向合同序列化程序提供子项添加到基本定义的任何类型信息。您可以通过KnownTypes提供额外信息。
我在MSDN上的KnowTypes上看到的最佳文档是here。
您在搜索中缺少的是因为您只有一个OperationContract(没有DataContract),您真正想要使用的属性是ServiceKnownType。
[ServiceContract]
public interface IContract
{
[OperationContract]
[ServiceKnownType(typeof(HttpUnhandledException))]
void PassException(Exception c);
}
您可以将属性设置为方法或整个界面。
注意,如果您在编译时不知道所有可能的子(Exception)类型,则会有一个ServiceKnownType(和KnowTypes)版本采用运行时方法。
答案 1 :(得分:1)
您可以通过将异常序列化为字节数组,然后在服务器端反序列化来解决此问题。
客户端,您可以使用:
try { /* Do something that generates an exception here. */ }
catch(System.Exception exception)
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, exception);
YourWCFMethodHere(ms.ToArray());
}
}
然后在服务器端:
public void YourWCFMethodHere(byte[] exception)
{
using (MemoryStream ms = new MemoryStream(exception, false))
{
BinaryFormatter bf = new BinaryFormatter();
Exception ex = (Exception)bf.Deserialize(ms);
// Do something with the exception here
}
}
当然,您需要进行一些错误检查,以防传入的byte []实际上不是Exception。
答案 2 :(得分:0)
ErnieL有正确的技术答案。但是,实际上,我倾向于1)打破异常的部分并仅传递那些或2)创建自己的自定义ErrorLog类型并发送它。
这消除了处理异常对象的子类化的需要,并为您提供了一致的界面。可能,您只需要异常中的一些成员(错误消息,内部异常错误消息和堆栈跟踪)。
对于内部异常,只需编写一个循环遍历消息并将它们连接在一起的方法。他们真的需要分开存放吗?