zoukankan      html  css  js  c++  java
  • WCF中因序列化问题引起的异常和错误。

    这段时间一直在忙着赶项目,由DAL+WCF+WinForm几层组成。其中数据库使用的MySQL+MySQL.Data.dll Driver。不过在使用中,经常碰到如下错误:

    接收对 http://localhost/***.svc 的 HTTP 响应时发生错误。这可能是由于服务终结点绑定未使用 HTTP 协议造成的。这还可能是由于服务器中止了 HTTP 请求上下文(可能由于服务关闭)所致。有关详细信息,请参见服务器日志。

    有时也会出现如下错误

    基础连接已经关闭: 连接被意外关闭。

    经过仔细核对发现,每当发生MySql.Data.MySqlClient.MySqlException异常时,就会报这个错误。网上找了半天也没有找到解决方案,后来使用Trace Viewer跟踪才发现是MySqlException序列化时出现了问题:

    System.ServiceModel.CommunicationException: 尝试对参数 http://tempuri.org/ 进行序列化时出错: result。InnerException 消息是“不应为数据协定名称为“MySqlException:http://schemas.datacontract.org/2004/07/MySql.Data.MySqlClient”的类型“MySql.Data.MySqlClient.MySqlException”。请考虑使用 DataContractResolver,或将任何未知类型以静态方式添加到已知类型的列表。例如,可以使用 KnownTypeAttribute 特性,或者将未知类型添加到传递给 DataContractSerializer 的已知类型列表。”。有关详细信息,请参见 InnerException。  System.Runtime.Serialization.SerializationException:.......

    其中result是一个存储操作结果的类实例,它横跨DAL、WCF、WinForm三层,用以存储一个完整操作中发现的异常及信息。里面对可能发生的异常做了包装,它的结构如下(其它属性及构造函数等没有列出):

    [DataContract]
    public class Result
    {
        private bool success;
     
        [DataMember]
        public boll Success
        {
            get {return this.success;}
            set {this.success = value;}
        }
     
        private Exception exception;
        
        [DataMember]
        publice Exception Exception
        {
            get {return this.exception;}
            set {this.exception = value;}
        }
    }

    当DAL层中涉及SQL语句的执行发生错误时,result.Exception类型实际为MySqlException。虽然在Result类定义时已经声明[DataContract],不过序列化时仍然出错,头疼!查看MySqlException的定义如下:

    [Serializable]
    public sealed class MySqlException : DbException
    {
        public int Number { get; }
    }

    明明是已经声明了[Serializable]特性,而且查看MySQL.Data.dll 文档,发现其在0.7版本的时候,就已经支持序列化了,却仍然不可在WCF中序列化,只能再找原因。

    根据错误的提示,在IService的契约声明接口中,加上了[ServiceKnownType(typeof(MySql.Data.MySqlClient.MySqlException))]声明,可到头来结果还是一样不起作用。但是如果发生的异常不是MySqlException类型时,就不会报序列化错误。

    对比Exception和MySqlException的实现,发现虽然都声明了[Serializable]特性,但MySqlException却没有实现序列化和逆序列化的函数。问题很可能出现在这个地方。

    不过由于没有MySQL.Data.dll 的源代码,无法让添加这两个函数,只得新建一个异常类CustomException存放在Result。其代码如下:

    [Serializable]    
    public class CustomException : ISerializable,Exception
    {
        private string message;
     
        public override string Message
        {
            get
            {
                return this.message;
            }
        }
     
        private string stackTrace;
     
        public override string StackTrace
        {
            get
            {
                return this.stackTrace;
            }
        }
     
        public CustomException() { }
     
        public CustomException(string exceptionMessage, string exceptionStackTrace)
        {
            this.message = exceptionMessage;
            this.stackTrace = exceptionStackTrace;
        }
        /*
         以下序列化和逆序列化中,只保存了Message和StackTrace
         */
        protected CustomException(SerializationInfo info, StreamingContext context)
        {
            this.message = info.GetString("Message");
            this.stackTrace = info.GetString("StackTraceString");
        }
     
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Message", this.message);
            info.AddValue("StackTraceString", this.stackTrace);
        }
     
        public override string ToString()
        {
            if (string.IsNullOrEmpty(this.message)) 
                return string.Empty;
     
            return this.message.ToString();
        }
    }

    之所以override定义Message和StackTrace,是为能对它们俩重写,因为Exception类中,定义的StackTrace是只读的,Message也只能在构造函数中赋值。此外,此处只定义了这两个属性,是因为项目中只用到了Exception中的这两个属性,一般情况下,这两个属性也已经足够查找异常信息了。

    当然最主要的地方,还是要实现一个构造函数,用来序列化,以及GetObjectData 方法设置序列化对象的替代值。

    再次跟踪执行,当产生MySqlException时,Result对象可以正常从DAL->WCF->WinForm。OK啦!

    总结:这个问题,的确是折磨了我好几天,由于是对WCF头一次在项目中使用,对它的了解也不多。如果不是看到使用Trace Viewer,还不会找到问题的本质所在。看来.NET下的异常提示,有时候也不一定就是问题的产生点,就像编译代码一样,少个逗号,提示的信息却是五花八门。

  • 相关阅读:
    软件工程——理论、方法与实践 第三章
    软件工程——理论、方法与实践 第二章
    软件工程——理论、方法与实践 第一章
    使用@RunWith(SpringJUnit4ClassRunner.class)进行单元测试时 报错 和 java.lang.NoSuchMethodError的解决方法
    springMVC 校验时,CustomValidationMessages.properties中的错误提示信息的中文乱码 问题
    通过scrapy,从模拟登录开始爬取知乎的问答数据
    利用AJAX JAVA 通过Echarts实现豆瓣电影TOP250的数据可视化
    Scrapy爬取伯乐在线的所有文章
    搭建第一个scrapy项目的常见问题
    利用Ajax实现数据的同步传输,从mysql中提取数据,通过echarts可视化
  • 原文地址:https://www.cnblogs.com/RitchieChen/p/2213761.html
Copyright © 2011-2022 走看看