.NET 4.5.2, IIS 8.5 on Windows 8.1 x64. I have a single ASP.NET web site at /localhost/.
I've got a real async-puzzle here that I've been wrestling with for two days now.
I'm reworking some long-running reports to be async, but I can demonstrate my problem with very simple code.
I have an asp:DataGrid on my page that I've initially set visible="false". It should only be visible if it is populated. My problem is, if the code that populates it is async I don't see the grid!
Here's the markup:
<body>
<form runat="server">
<asp:datagrid ID="grid" visible="false" Runat="server"></asp:datagrid>
</form>
</body>
In the code-behind, this code WORKS:
void Page_Load()
{
grid.DataSource = new Dictionary<string, string>()
{
{ "col1", "value1" }
};
grid.DataBind();
grid.Visible = true;
}
Now if I make two changes:
Add Async="True" to the @Page directive Replace Page_Load with this
void Page_Load()
{
this.RegisterAsyncTask(new PageAsyncTask(async () =>
{
grid.DataSource = new Dictionary<string, string>()
{
{ "col1", "value1" }
};
grid.DataBind();
grid.Visible = true;
}));
}
The grid is not rendered. Note that I've used the async keyword even though there is no await in the delegate. I have tried several things, all with the same result:
- Add an await Task.Delay(...)
- Remove the async keyword and Return Task.FromResult(0)
I have overridden and instrumented the page lifecycle events to see when the grid is populated and how its visiblity changes. This is the output I see:
OnPreInit: Visible=False Rows=0 Thread=63
OnInit: Visible=False Rows=0 Thread=63
OnInitComplete: Visible=False Rows=0 Thread=63
OnPreLoad: Visible=False Rows=0 Thread=63
OnLoad: Visible=False Rows=0 Thread=63
OnLoadComplete: Visible=False Rows=0 Thread=63
OnPreRender: Visible=False Rows=0 Thread=63
Async 1: Visible=False Rows=0 Thread=63
Async 2: Visible=True Rows=1 Thread=63
OnPreRenderComplete: Visible=True Rows=1 Thread=63
OnSaveStateComplete: Visible=True Rows=1 Thread=63
Render 1: Visible=True Rows=1 Thread=63
Render 2: Visible=True Rows=1 Thread=63
"Async 1" and "2" are on either side of the grid population inside the delegate. You can see the grid is getting a row and its visibility gets true, yet it isn't rendered. If I populate the grid with my first code sample, synchronously, all is well.
Another note: I can enclose the grid in another control to make it work:
<body>
<form runat="server">
<div id="container" visible="false" runat="server">
<asp:datagrid ID="grid" Runat="server"></asp:datagrid>
</div>
</form>
</body>
It seems to be the visible="false" on the asp:datagrid itself that screws this up.
What am I doing wrong?
Try placing the Grid in an UpdatePanel and call the async method (to load the data in the Grid and manage its visibility) on the OnLoad event of the UpdatePanel