最近,我收到了Ninject.Web的错误报告,它与ASP.NET动态数据一起工作不正常.问题是在回发时(例如,当插入,删除,编辑记录时),表格不再显示.
一些debuging表明问题是由IHttpModule引起的,它在初始化后递归遍历页面的所有控件.只要此模块访问Controls属性获取FormView或GridView的访问器,就会出现问题.如果这种类型的控件滑雪,一切都很好.以下代码显示了该模块:
public class NinjectHttpModule : DisposableObject, IHttpModule
{
private HttpApplication httpApplication;
public void Init(HttpApplication context)
{
this.httpApplication = context;
this.httpApplication.PreRequestHandlerExecute += this.OnPreRequestHandlerExecute;
}
private static void InjectUserControls(Control parent)
{
if (parent == null)
{
return;
}
foreach (Control control in parent.Controls)
{
if (control is UserControl)
{
// KernelContainer.Inject(control); This is irrelevant for the question.
}
InjectUserControls(control);
}
}
private void OnPreRequestHandlerExecute(object sender, EventArgs e)
{
var page = this.httpApplication.Context.CurrentHandler as Page;
if (page == null)
{
return;
}
KernelContainer.Inject(page);
page.InitComplete += (src, args) => InjectUserControls(page);
}
}
如果更改此代码,以便通过DataBoundControls的子控件的迭代延迟到DataBound事件,一切都很好.由下一个代码段显示:
private static void InjectUserControls(Control parent, bool skipDataBoundControls)
{
if (parent == null)
{
return;
}
if (skipDataBoundControls)
{
var dataBoundControl = parent as DataBoundControl;
if (dataBoundControl != null)
{
dataBoundControl.DataBound += InjectDataBoundControl;
return;
}
}
foreach (Control control in parent.Controls)
{
if (control is UserControl)
{
KernelContainer.Inject(control);
}
InjectUserControls(control, skipDataBoundControls);
}
}
private static void InjectDataBoundControl(object sender, EventArgs e)
{
var dataBoundControl = sender as DataBoundControl;
if (dataBoundControl != null)
{
dataBoundControl.DataBound -= InjectDataBoundControl;
InjectUserControls(dataBoundControl, false);
}
}
因为我对System.Web.DynamicData完全不熟悉,所以我想知道一些事情,以便更好地了解如何修复这个bug:
>为什么会出现这个问题?我的意思是它只是对Controls属性的简单读取访问.
>上述变化有哪些副作用?
>在数据绑定事件之后注入控件是否仍然足够早?
>您认为这是针对此问题的有效错误修复方法吗?
最佳答案 当然,令人费解的行为,有时会发生在具有许多执行阶段的WebForms中.
即使它只是对Controls属性的简单读取访问,该属性实际上可以做很多工作来返回子控件.特别是,它不能返回子控件,除非它们已经创建,并且创建通常直到页面生命周期的后期才会发生.因此,通过在InitComplete中访问它,孩子最终会在一些重要的动态数据连接发生之前过早地被创建,导致一些控件丢失.是的,我意识到最终结果行为似乎毫无意义,这就是为什么有些人喜欢MVC的直截了当:)
作为替代可能的解决方法,您可以尝试将注射从InitComplete移动到PreLoad吗?例如
page.PreLoad += (src, args) => InjectUserControls(page);
我很确定这会解决问题,但我不太确定这是否会导致你的KernelContainer.Inject逻辑出现问题.试一试,因为它比你的解决方法更简单.
如果这不起作用,我认为您的解决方法是可以的,因为它会延迟枚举直到创建子项.至于“在数据绑定事件之后是否足够早地注入控件”,我认为这完全取决于KernelContainer.Inject的功能,以及它对控件状态的期望.