1.提出问题
前面五篇说了如何实现,但是如果xml配置错了怎么办哪?
首先,利用Xsd,已经可以保证大部分xml的类型不会出错,但是,之前把Expression设计为弱类型的,也就意味着Expression不对其返回的类型负责,这是第一个在xml运行时存在的不稳定因素。
第二,变量本身也有不安全因素,首先变量名本身就非常容易出现书写错误,其次,变量名本身也是弱类型的,不到运行时,根本不知道里面到底放的是什么。
第三,参数(Parameter)。参数是在IGeneratorEngine的Generate方法输入的,因此,这里Xml配置中的参数是依赖于c#的输入的,而这个也是必须到运行时才能知道的。
第四,CliFunction。这个PInvoke是为Xml调用.net方法而设计的,那么自然也就会有各种不稳定因素会出现。
第五,实现本身的缺陷导致的问题。
2.改良日志
要排除以上运行时问题,最简单的方法就是记录日志。说到日志,是不是马上就想到:
- Log4Net
- Enterprise Library - Logging Application Block
没错,这是两个用的最多的日志工具,但是,它们也是通用的日志工具,并不适合记录Xml的场合(至少,没法帮助我们直接定为到Xml的哪一行出的错)。
所以,需要把日志服务包装一下:
现在只需要在实现TraceErrorCore的时候多添加一个Xml的调用堆栈即可。既然有调用堆栈,那就先要定义:
然后再定义调用堆栈:
然后再重写ToString方法:
然后准备一套关于Xml调用堆栈的扩展方法:
剩下来的就是让那些实现类额外实现一个IXmlFunction,例如:
这样就可以让每一个结构被调用时,把调用信息写入调用堆栈,并且可以在GetAdditionalInformation添加其它相关的参数信息。
现在再回到TraceService,可以进一步把Core方法实现了(为了避免牵涉到具体的日志工具,就用.net自带的Trace来记录):
如果context为空,那就意味着当前不在Xml配置相关的运行状态,否则就记录相关的Xml调用堆栈。
最后,把所有需要记录日志的地方替换成使用TraceService。现在Xml调用堆栈已经都准备好了。
3.进一步改良日志
前一节已经可以把日志定位到行为了,但是,这样依然不能知道到底是Xml的哪一行哪一列出了错。当然反序列化本身无法提供这样的信息。
这里,先引入一个接口:IXmlLineInfo
用Reflector来看一下哪些类实现了这个接口:
3.1 Linq to Xml
首先是Linq to Xml的XObject实现了这个接口,因此先大概写一个XLinq的Loader:
因为IXmlLineInfo接口是只读的,因此,需要再定义一个写入这些行信息的接口:
然后让Slide实现这个接口:
别忘了给新添加的公共属性添加XmlIgnore特性,否则会影响Xml序列化的行为。
再次回到XLinqLoader,现在需要额外添加IXmlLineInfo的信息:
如此就可以完成了一个使用Linq to Xml的Loader。
3.2 XPathDocument
再次看一下实现IXmlLineInfo的实现类:
这次关注一下选中的这个类,当然这个类型不是公开的,不过可以用Reflector分析一下:
该分析指出,这个类是由XPathDocument的CreateNavigator方法来创建实例的,进一步用Reflector查看这个方法:
也就是说,CreateNavigator返回的就是这个类型的一个实例。
那么再写一个利用XPathDocument的Loader:
(XPathDocument的Navigator是只读的,所有修改内容的方法都将抛出NotSupportedException)
3.3 其它
除了上面介绍的两个方法,也可以用XmlReader方式读取,用XmlReader.Create方法创建的一个XmlReader的实例,然后强转成IXmlLineInfo就可以了。
4.改良日志提供LineInfo
第二节的日志已经提供了Xml的相关信息,而在第三节又提供了LineInfo,那么在这一节,就把LineInfo写到日志里面,再次改造一下XmlCallStack的ToString方法:
这样Xml的日志已经基本完成了。
上一篇:从写组件说Xml——实现(五)