又一个疑似Bug: XmlDataSource 控件的 Data 属性动态改变时,缓存不会自动失效

最近似乎不太顺利,总是一钻进 Reflector 就 N 久时间找不到问题所在,一点一点琢磨那些可疑的、没有头绪的、没有注释的 BCL (.net 的基础类库)源代码,以确认到底是我错了,还是微软错了。

这不,又发现一个疑似bug,如标题所写。

XmlDataSource 控件一般是和 TreeView 组合使用的,如果是静态的 XML 数据是不会碰到什么问题的,但一变成动态数据,就总碰到一些怪异的现象。(虽然大部分最终还是被克服了。)

想让 TreeView 显示动态数据,第一条,可以不用绑定,直接一个 TreeNode 一个 TreeNode 的添加,保证 100% 符合要求。

第二条,在画面上放上多个 XmlDataSource 控件,根据情况将 TreeView 的 DataSourceID 属性指到相应的 XmlDataSource 控件。但局限也很明显,总不能一下子放上 100个,1000个 XmlDataSource 控件吧?

第三条,XmlDataSource 只用一个,但改变它的 DataFile 或者 Data 属性,以改变数据。

改变 DataFile 属性的方案,经试验是可行的。不过相对于 Data 属性,局限就是必须有硬盘上存在的 XML 文件做源。虽然你可以选择动态生成 XML 文件,然后绑上去,但还是有些麻烦,还得考虑考虑这些临时文件的废弃处理措施。

Data 属性相对就比较合我的口味,不过,我就在这个方案上栽了跟斗:我发现无论怎么改变 Data 值,TreeView 的显示总是不变。(只有页面初始化那一次有效。)

先是怀疑是不是 TreeView 没有自动去 XmlDataSource 去取最新数据?对 BCL 的 debug 是有点麻烦的,好像是有办法下载微软公开的源代码,然后进行 debug 的,不过我这会儿没功夫去调。就用 Reflection 将我看到的那些 private 变量的值弄出来看,结果没发现 TreeView 有“偷工”的迹象。

然后把矛头掉转到 XmlDataSource,看看是不是它有问题。一钻去,首先就发现这个家伙跟其他的 DataSource 控件相比,有一点很与众不同,它默认的 Cache.Enabled = true。这个默认设置,也算可以理解,毕竟 XML 文件相对于数据库那些数据源来说,还是很稳定的,而且加载很多节点的 XML 文档也是很费劲的。

进一步的追踪发现,问题的原因应该就是出在缓存上。Data 属性变化后,缓存没有自动失效,导致了问题。

下面是我使用 Reflection 的 Hack:

    public static void XmlDataSourceCacheHack(XmlDataSource dataSource)
    {
        try
        {
            Type t = typeof(XmlDataSource);
            MethodInfo m = t.GetMethod("CreateCacheKey", 
                BindingFlags.Instance | BindingFlags.NonPublic);
            string key = (string)m.Invoke(dataSource, null);
            PropertyInfo p = t.GetProperty("Cache",
                BindingFlags.Instance | BindingFlags.NonPublic);
            object cache = p.GetValue(dataSource, null);

            Type t2 = t.Assembly.GetType("System.Web.UI.DataSourceCache");
            MethodInfo m2 = t2.GetMethod("Invalidate", 
                BindingFlags.Instance | BindingFlags.Public);
            m2.Invoke(cache, new object[] { key });
        }
        catch
        {
        }
    }

如果你有不使用 Reflection 就能解决的方法,敬请不吝赐教,那就多谢了!

如果你希望看点示例代码,请到 codeproject 下面的页面去下载:

http://www.codeproject.com/KB/webforms/XmlDataSource_Cache_Hack.aspx

补充:

当然,还有个简单的做法,就是直接禁用 XmlDataSource 的 cache 功能。不过,像我的实际情况中,切换数据源的可能性要远远低于其他 PostBack 的几率,缓存要比 reflection 更重要一些。你可以根据你的实际情况决定。

posted on 2008-06-16 20:16  破宝  阅读(294)  评论(0编辑  收藏  举报

导航