强制 XmlDataSource 缓存失效的技巧
我发现当你通过代码更改 XmlDataSource 控件的 Data 属性时,它不会自动使缓存失效。 这是一个针对此问题的 hack。
引言
我们经常将 XmlDataSource
控件与 TreeView
控件一起使用。
如果数据源是静态的,它工作得很好。但是,当数据源需要是动态的时,似乎存在一些问题。本文将介绍其中一个问题,并为您提供一个 hack 解决方案。
症状
如果数据源需要是动态的,您可以选择
- 在 Web 表单上放置多个
XmlDataSource
控件,并通过设置不同的DataSourceID
来切换它们。 - 仅放置一个
XmlDataSource
控件,并在必要时更改其DataFile
或Data
属性的值。
显然,第一种方式更受限制,仅适用于某些特殊情况。在表单上放置大量数据源控件不是一个好主意,更重要的是,数据源控件的数量必须是一个固定值。
但是,当您更改 XmlDataSource
控件的 DataFile
或 Data
属性的值时会发生什么? 从 Microsoft 的文档中,您可能会发现以下信息
如果您更改
DataFile
/Data
属性的值,则会引发DataSourceChanged
事件。 如果启用了缓存并且您更改了DataFile
/Data
的值,则会使缓存失效。
不幸的是,在我的测试中(您可以下载示例自己查看),我发现当您更改 XmlDataSource
控件的 Data
属性的值时,缓存 不会 自动失效,尽管 DataFile
没有问题。
解决方法
首先,您可以选择更改 XmlDataSource
的 DataFile
属性的值,而不是 Data
。 这是一个简单的解决方案。
否则,如果您出于某种原因坚持更改 Data
的属性(例如,您的数据源不是真正的 XML 文件,而只是一个动态填充的字符串),您可以尝试以下 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
{
}
}
(当然,文件开头需要 "using System.Reflection;
")
这只是针对此问题的一个 hack。我花了超过一天的时间调试以找到这个奇怪问题的根源。
(附注:如果您找到更完善的解决方法,避免使用 Reflection,请 告诉我。 谢谢!)
感谢 PlamenLeykov
您当然可以完全禁用 XmlDataSource
的缓存功能。它也运行良好。这是另一种简单的解决方案。
但是,如果你的情况就像我一样:更改的可能性低于其他回发可能性(例如,TreeView
很大,并且总是比数据源更改更频繁地触发回发),您将更喜欢使用 Reflection 而不是禁用缓存。
这是否是 Microsoft 的一个错误?
我不确定这是否是 Microsoft 的一个错误,或者它是否仅适用于设计规范。但是,实现是错误的,或者文档是错误的。