0

I have a category page (Classic ASP.NET) which loads products from DB (MS SQL Server). Each product (implemented as userControl) has its own databound controls. I want to load these product controls in parallel so I created a helper module which creates PageAsyncTask and register it.

Public Module AsyncHelper

Public Delegate Sub AsyncDeleg()

Private Function OnBegin(sender As Object, e As EventArgs, cb As AsyncCallback, state As Object) As IAsyncResult
    Return DirectCast(state, AsyncDeleg).BeginInvoke(cb, state)
End Function

Private Sub OnEnd(ar As IAsyncResult)
    Try
        DirectCast(ar.AsyncState, AsyncDeleg).EndInvoke(ar)
        HttpContext.Current.Trace.Write("OnEnd", ar.CompletedSynchronously)
    Catch ex As Exception
        DirectCast(ar.AsyncState, AsyncDeleg).Invoke()
        HttpContext.Current.Trace.Write("OnEnd", ex.Message)
    End Try
End Sub

Public Sub RunAsyncTask(pg As Web.UI.Page, subToRun As AsyncDeleg)
    pg.RegisterAsyncTask(New PageAsyncTask(AddressOf OnBegin, AddressOf OnEnd, Nothing, subToRun, True))
End Sub

End Module

The call from the UserControl is very simple:

AsyncHelper.RunAsyncTask(Me.Page, New AsyncHelper.AsyncDeleg(AddressOf BindData))

Sub BindData queries DB and binds result to a repeater or ListView.

It works really in parallel but sometimes it produces exception like Control not found Stack empty

For this purpose catch in OnEnd works fine.

Much worse thing is that sometimes it takes part data from correct product and part from any random product without any kind of error ;(

Technical details:
.NET 4.5
httpRuntime targetFramework="4.5"
<%@ Page Async="true"

Any suggestions?
Thank you.

Alex Kudryashev
  • 9,120
  • 3
  • 27
  • 36
  • 1
    Why are you using code like this on .NET 4.5? Just use `Await`, it's much simpler. And you can't just access the `Page` in your `BindData` method, since it doesn't run on the correct thread and synchronization context. Let it return the data instead, and do the binding back on the request thread. – Luaan Apr 15 '16 at 19:49
  • For some reason Await doesn't run in parallel. ;( And I don't need Page inside BindData. BindData works in a UserControl with its controls. – Alex Kudryashev Apr 15 '16 at 20:00
  • 1
    Those user controls are still a part of the page and need to be synchronized the same way. `Await` doesn't run in parallel, because it makes your code synchronous - you need to start all your asynchronous tasks first, and then do something like `Await Task.WhenAll`. `Await`s are just the natural (and easy to use) synchronization points. – Luaan Apr 15 '16 at 22:30
  • I found that that controls which are bound declaratively (i.e. `<%#Eval("price")%>` are messed more often then never but `control_ItemDataBinding` receives correct data. – Alex Kudryashev Apr 24 '16 at 05:46
  • ...but `control_ItemDataBinding` receives correct data... most times. not always ;( I'm still looking for better solution. I want to bind independent data in parallel. – Alex Kudryashev May 21 '16 at 00:20
  • 1
    Yes, if by chance all the parallel tasks finish before control_ItemDataBinding is invoked, it might get the correct data. Multi-threading bugs are a bit non-deterministic, and tend to be hard to reproduce and fix - you really want to do it right the first time. – Luaan May 21 '16 at 18:42

0 Answers0