Switching threads on UI in asp.net page

J

Jeremy Holt

Hi,

In a windows.forms application I would BeginInvoke a delegate on the UI
thread to collect data from a database. When the call returns to the
AsyncCallback, if the Control.InvokeRequired = True, I would then have the
Control.BeginInvoke(New AsyncCallback(AddressOf GetDataCallback), New
Object() {ar}).

How would one achieve the same thing on an asp.net page (without using a
webseervice)? In the code below, because the GetDataCallBack returns on a
thread different to the one originally invoked, the DataGrid will not
update.

Private da As New clsYields

Private Delegate Function GetDataDelegate(ByVal Crop As Integer) As dsYields
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Debug.WriteLine("Page load " &
Threading.Thread.CurrentThread.GetHashCode)
End Sub

Private Function GetData(ByVal Crop As Integer) As dsYields
Return Me.da.GetData(Crop)
End Function

Private Sub GetDataCallBack(ByVal ar As IAsyncResult)
Try
If ar.IsCompleted Then
Dim deleg As GetDataDelegate = CType(ar.AsyncState,
GetDataDelegate)
Dim ds As dsYields = deleg.EndInvoke(ar)
Me.DataGrid1.DataSource = ds.Production.DefaultView
Me.DataBind()
Debug.WriteLine("Data loaded " &
Threading.Thread.CurrentThread.GetHashCode)
End If
Catch ex As Exception
Tools.WriteException(ex)
End Try
End Sub

' Windows.Forms application
Private Sub GetDataCallBack(ByVal ar As IAsyncResult)
Try
If ar.IsCompleted Then
If Me.Form1.InvokeRequired Then
Me.Form1.BeginInvoke(New AsyncCallback(AddressOf
GetDataCallback), New Object() {ar})
Else
Dim deleg As GetDataDelegate = CType(ar.AsyncState,
GetDataDelegate)
Dim ds As dsYields = deleg.EndInvoke(ar)
Me.DataGrid1.DataSource = ds.Production.DefaultView
Debug.WriteLine("Data loaded " &
Threading.Thread.CurrentThread.GetHashCode)
End If
End If
Catch ex As Exception
Tools.WriteException(ex)
End Try
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim deleg As New GetDataDelegate(AddressOf GetData)
deleg.BeginInvoke(2005, New AsyncCallback(AddressOf GetDataCallBack),
deleg)
End Sub

Many thanks in advance
Jeremy
 
S

Scott Allen

Hi Jeremy:

Web controls do not have thread affinity like the Windows UI controls.
You can touch them from any thread.

There are a host of other threading issues that crop up in ASP.NET
however.

My guess is your async callback happens after the page has finished
processing. the primary response thread has probably already asked the
web form and all the controls to render before the callback happens.

Your best bet, if you need to make just one web service call, is not
to do async processing but make a blocking call and wait on the
results. The user will have to wait just as long a if you did the
async processing.
 
S

Steven Cheng[MSFT]

Thanks for Scott's informative inputs.

Hi Jeremy,

As Scott has mentioned, ASP.NET web page/serverside processing has
completely different model from winform application. For winform
application, there will exist a UI thread( and generally the primary thread
in process) which will process the windows message. However, in asp.net,
there is no such UI thread, and haven't the same windows message mechanism
like winform app, all the ASP.NET request are being processed under a
worker thread which is retrieved from the server process's managed thread
pool. Also, asp.net 's page request is being processed on serverside, it'll
go through a series of pipline modules and some certain events, after that
the page's request ended and response stream is written down to clientside.
So when we do asynchronous method invoking (delegate.begininvoke) which
execute on a separate threadpool thread, we can not guarantee the method
invoking will be finished before the page's request lifecycle ended( that
will cause the async delegate's callback be called too late for update the
page's properties or controls....)

So in asp.net app, we can not simply use async method invoking like in
winform, if you do need to do this, we need to make sure that before the
request processing end, the method is finished, you can ensure this through
the following code:

In postback handler

{
IAsyncResult ar = xxxxdelegate.BeginInvoke(.....)

//do other processing

//after processing other task, pending under the async method finish

ar.AsyncWaitHandle.WaitOne();


//continue ....

}



In addition, here are some articles discussing on ASP.NET's page model and
serverside lifecycle:

#The ASP.NET HTTP Runtime
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html
/dngrfTheASPNETHTTPRuntime.asp

#The ASP.NET Page Object Model
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html
/aspnet-pageobjectmodel.asp

#Control Execution Lifecycle
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
l/cpconControlExecutionLifecycle.asp


Hope helps. If anything unclear, please feel free to post here.

Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)


--------------------
| From: Scott Allen <[email protected]>
| Subject: Re: Switching threads on UI in asp.net page
| Date: Sun, 25 Sep 2005 15:39:07 -0400
| Message-ID: <[email protected]>
| References: <[email protected]>
| X-Newsreader: Forte Agent 1.8/32.548
| MIME-Version: 1.0
| Content-Type: text/plain; charset=us-ascii
| Content-Transfer-Encoding: 7bit
| Newsgroups: microsoft.public.dotnet.framework.aspnet
| NNTP-Posting-Host: dyn-170-234-71.myactv.net 24.170.234.71
| Lines: 1
| Path: TK2MSFTNGXA01.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP11.phx.gbl
| Xref: TK2MSFTNGXA01.phx.gbl
microsoft.public.dotnet.framework.aspnet:126928
| X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
|
| Hi Jeremy:
|
| Web controls do not have thread affinity like the Windows UI controls.
| You can touch them from any thread.
|
| There are a host of other threading issues that crop up in ASP.NET
| however.
|
| My guess is your async callback happens after the page has finished
| processing. the primary response thread has probably already asked the
| web form and all the controls to render before the callback happens.
|
| Your best bet, if you need to make just one web service call, is not
| to do async processing but make a blocking call and wait on the
| results. The user will have to wait just as long a if you did the
| async processing.
|
| --
| Scott
| http://www.OdeToCode.com/blogs/scott/
|
| On Sun, 25 Sep 2005 10:25:59 -0300, "Jeremy Holt"
|
| >Hi,
| >
| >In a windows.forms application I would BeginInvoke a delegate on the UI
| >thread to collect data from a database. When the call returns to the
| >AsyncCallback, if the Control.InvokeRequired = True, I would then have
the
| >Control.BeginInvoke(New AsyncCallback(AddressOf GetDataCallback), New
| >Object() {ar}).
| >
| >How would one achieve the same thing on an asp.net page (without using a
| >webseervice)? In the code below, because the GetDataCallBack returns on
a
| >thread different to the one originally invoked, the DataGrid will not
| >update.
| >
| >Private da As New clsYields
| >
| >Private Delegate Function GetDataDelegate(ByVal Crop As Integer) As
dsYields
| > Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
| >System.EventArgs) Handles MyBase.Load
| > Debug.WriteLine("Page load " &
| >Threading.Thread.CurrentThread.GetHashCode)
| >End Sub
| >
| > Private Function GetData(ByVal Crop As Integer) As dsYields
| > Return Me.da.GetData(Crop)
| > End Function
| >
| >Private Sub GetDataCallBack(ByVal ar As IAsyncResult)
| > Try
| > If ar.IsCompleted Then
| > Dim deleg As GetDataDelegate = CType(ar.AsyncState,
| >GetDataDelegate)
| > Dim ds As dsYields = deleg.EndInvoke(ar)
| > Me.DataGrid1.DataSource = ds.Production.DefaultView
| > Me.DataBind()
| > Debug.WriteLine("Data loaded " &
| >Threading.Thread.CurrentThread.GetHashCode)
| > End If
| > Catch ex As Exception
| > Tools.WriteException(ex)
| > End Try
| >End Sub
| >
| >' Windows.Forms application
| >Private Sub GetDataCallBack(ByVal ar As IAsyncResult)
| > Try
| > If ar.IsCompleted Then
| > If Me.Form1.InvokeRequired Then
| > Me.Form1.BeginInvoke(New AsyncCallback(AddressOf
| >GetDataCallback), New Object() {ar})
| > Else
| > Dim deleg As GetDataDelegate = CType(ar.AsyncState,
| >GetDataDelegate)
| > Dim ds As dsYields = deleg.EndInvoke(ar)
| > Me.DataGrid1.DataSource = ds.Production.DefaultView
| > Debug.WriteLine("Data loaded " &
| >Threading.Thread.CurrentThread.GetHashCode)
| > End If
| > End If
| > Catch ex As Exception
| > Tools.WriteException(ex)
| > End Try
| >End Sub
| >
| >Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
| >System.EventArgs) Handles Button1.Click
| > Dim deleg As New GetDataDelegate(AddressOf GetData)
| > deleg.BeginInvoke(2005, New AsyncCallback(AddressOf
GetDataCallBack),
| >deleg)
| >End Sub
| >
| >Many thanks in advance
| >Jeremy
| >
|
|
 
J

Jeremy Holt

Scott/Steve,

Thank you both very much for your advice. I really hadn't understood the
point that the page could have completed loading before the async callback
had returned - it makes sense now that you have explained it so clearly!

Therefore, to summarise, I may as well do a synchronous call to get the
data, and wait for the data before letting the page complete.

Many thanks again for all your help.

Best regards
Jeremy
 
S

Steven Cheng[MSFT]

You're welcome Jeremy,

Also, If you have interests, I'd recommend you go through those MSDN
articles I mentioned earlier which will help you have a more clear
understanding on the ASP.NET's runtime processing. Also, some other
articles over internet also provides many deep description on ASP.NET 's
internal mechanism.

Good luck!

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)

--------------------
| From: "Jeremy Holt" <[email protected]>
| References: <[email protected]>
<[email protected]>
<[email protected]>
| Subject: Re: Switching threads on UI in asp.net page
| Date: Mon, 26 Sep 2005 20:02:47 -0300
| Lines: 219
| X-Priority: 3
| X-MSMail-Priority: Normal
| X-Newsreader: Microsoft Outlook Express 6.00.2900.2180
| X-RFC2646: Format=Flowed; Original
| X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2180
| Message-ID: <[email protected]>
| Newsgroups: microsoft.public.dotnet.framework.aspnet
| NNTP-Posting-Host: 201009013117.user.veloxzone.com.br 201.9.13.117
| Path: TK2MSFTNGXA01.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP10.phx.gbl
| Xref: TK2MSFTNGXA01.phx.gbl
microsoft.public.dotnet.framework.aspnet:127251
| X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
|
| Scott/Steve,
|
| Thank you both very much for your advice. I really hadn't understood the
| point that the page could have completed loading before the async
callback
| had returned - it makes sense now that you have explained it so clearly!
|
| Therefore, to summarise, I may as well do a synchronous call to get the
| data, and wait for the data before letting the page complete.
|
| Many thanks again for all your help.
|
| Best regards
| Jeremy
|
|
|
|
| | > Thanks for Scott's informative inputs.
| >
| > Hi Jeremy,
| >
| > As Scott has mentioned, ASP.NET web page/serverside processing has
| > completely different model from winform application. For winform
| > application, there will exist a UI thread( and generally the primary
| > thread
| > in process) which will process the windows message. However, in asp.net,
| > there is no such UI thread, and haven't the same windows message
mechanism
| > like winform app, all the ASP.NET request are being processed under a
| > worker thread which is retrieved from the server process's managed
thread
| > pool. Also, asp.net 's page request is being processed on serverside,
| > it'll
| > go through a series of pipline modules and some certain events, after
that
| > the page's request ended and response stream is written down to
| > clientside.
| > So when we do asynchronous method invoking (delegate.begininvoke) which
| > execute on a separate threadpool thread, we can not guarantee the method
| > invoking will be finished before the page's request lifecycle ended(
that
| > will cause the async delegate's callback be called too late for update
the
| > page's properties or controls....)
| >
| > So in asp.net app, we can not simply use async method invoking like in
| > winform, if you do need to do this, we need to make sure that before the
| > request processing end, the method is finished, you can ensure this
| > through
| > the following code:
| >
| > In postback handler
| >
| > {
| > IAsyncResult ar = xxxxdelegate.BeginInvoke(.....)
| >
| > //do other processing
| >
| > //after processing other task, pending under the async method finish
| >
| > ar.AsyncWaitHandle.WaitOne();
| >
| >
| > //continue ....
| >
| > }
| >
| >
| >
| > In addition, here are some articles discussing on ASP.NET's page model
and
| > serverside lifecycle:
| >
| > #The ASP.NET HTTP Runtime
| >
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html
| > /dngrfTheASPNETHTTPRuntime.asp
| >
| > #The ASP.NET Page Object Model
| >
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html
| > /aspnet-pageobjectmodel.asp
| >
| > #Control Execution Lifecycle
| >
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
| > l/cpconControlExecutionLifecycle.asp
| >
| >
| > Hope helps. If anything unclear, please feel free to post here.
| >
| > Regards,
| >
| > Steven Cheng
| > Microsoft Online Support
| >
| > Get Secure! www.microsoft.com/security
| > (This posting is provided "AS IS", with no warranties, and confers no
| > rights.)
| >
| >
| > --------------------
| > | From: Scott Allen <[email protected]>
| > | Subject: Re: Switching threads on UI in asp.net page
| > | Date: Sun, 25 Sep 2005 15:39:07 -0400
| > | Message-ID: <[email protected]>
| > | References: <[email protected]>
| > | X-Newsreader: Forte Agent 1.8/32.548
| > | MIME-Version: 1.0
| > | Content-Type: text/plain; charset=us-ascii
| > | Content-Transfer-Encoding: 7bit
| > | Newsgroups: microsoft.public.dotnet.framework.aspnet
| > | NNTP-Posting-Host: dyn-170-234-71.myactv.net 24.170.234.71
| > | Lines: 1
| > | Path: TK2MSFTNGXA01.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP11.phx.gbl
| > | Xref: TK2MSFTNGXA01.phx.gbl
| > microsoft.public.dotnet.framework.aspnet:126928
| > | X-Tomcat-NG: microsoft.public.dotnet.framework.aspnet
| > |
| > | Hi Jeremy:
| > |
| > | Web controls do not have thread affinity like the Windows UI controls.
| > | You can touch them from any thread.
| > |
| > | There are a host of other threading issues that crop up in ASP.NET
| > | however.
| > |
| > | My guess is your async callback happens after the page has finished
| > | processing. the primary response thread has probably already asked the
| > | web form and all the controls to render before the callback happens.
| > |
| > | Your best bet, if you need to make just one web service call, is not
| > | to do async processing but make a blocking call and wait on the
| > | results. The user will have to wait just as long a if you did the
| > | async processing.
| > |
| > | --
| > | Scott
| > | http://www.OdeToCode.com/blogs/scott/
| > |
| > | On Sun, 25 Sep 2005 10:25:59 -0300, "Jeremy Holt"
| > |
| > | >Hi,
| > | >
| > | >In a windows.forms application I would BeginInvoke a delegate on the
UI
| > | >thread to collect data from a database. When the call returns to the
| > | >AsyncCallback, if the Control.InvokeRequired = True, I would then
have
| > the
| > | >Control.BeginInvoke(New AsyncCallback(AddressOf GetDataCallback), New
| > | >Object() {ar}).
| > | >
| > | >How would one achieve the same thing on an asp.net page (without
using
| > a
| > | >webseervice)? In the code below, because the GetDataCallBack returns
on
| > a
| > | >thread different to the one originally invoked, the DataGrid will not
| > | >update.
| > | >
| > | >Private da As New clsYields
| > | >
| > | >Private Delegate Function GetDataDelegate(ByVal Crop As Integer) As
| > dsYields
| > | > Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
| > | >System.EventArgs) Handles MyBase.Load
| > | > Debug.WriteLine("Page load " &
| > | >Threading.Thread.CurrentThread.GetHashCode)
| > | >End Sub
| > | >
| > | > Private Function GetData(ByVal Crop As Integer) As dsYields
| > | > Return Me.da.GetData(Crop)
| > | > End Function
| > | >
| > | >Private Sub GetDataCallBack(ByVal ar As IAsyncResult)
| > | > Try
| > | > If ar.IsCompleted Then
| > | > Dim deleg As GetDataDelegate = CType(ar.AsyncState,
| > | >GetDataDelegate)
| > | > Dim ds As dsYields = deleg.EndInvoke(ar)
| > | > Me.DataGrid1.DataSource = ds.Production.DefaultView
| > | > Me.DataBind()
| > | > Debug.WriteLine("Data loaded " &
| > | >Threading.Thread.CurrentThread.GetHashCode)
| > | > End If
| > | > Catch ex As Exception
| > | > Tools.WriteException(ex)
| > | > End Try
| > | >End Sub
| > | >
| > | >' Windows.Forms application
| > | >Private Sub GetDataCallBack(ByVal ar As IAsyncResult)
| > | > Try
| > | > If ar.IsCompleted Then
| > | > If Me.Form1.InvokeRequired Then
| > | > Me.Form1.BeginInvoke(New AsyncCallback(AddressOf
| > | >GetDataCallback), New Object() {ar})
| > | > Else
| > | > Dim deleg As GetDataDelegate = CType(ar.AsyncState,
| > | >GetDataDelegate)
| > | > Dim ds As dsYields = deleg.EndInvoke(ar)
| > | > Me.DataGrid1.DataSource = ds.Production.DefaultView
| > | > Debug.WriteLine("Data loaded " &
| > | >Threading.Thread.CurrentThread.GetHashCode)
| > | > End If
| > | > End If
| > | > Catch ex As Exception
| > | > Tools.WriteException(ex)
| > | > End Try
| > | >End Sub
| > | >
| > | >Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
| > | >System.EventArgs) Handles Button1.Click
| > | > Dim deleg As New GetDataDelegate(AddressOf GetData)
| > | > deleg.BeginInvoke(2005, New AsyncCallback(AddressOf
| > GetDataCallBack),
| > | >deleg)
| > | >End Sub
| > | >
| > | >Many thanks in advance
| > | >Jeremy
| > | >
| > |
| > |
| >
|
|
|
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top