2014-10-20 53 views
1

我有一个小型VB.Net项目,使用网络服务link to sqlSOAP)。 我必须确保所有表格完全响应无论如何,它的工作得很好。我唯一的问题是加载应用程序! 主要开办形式只有一行代码:VB.Net + WebService:主窗体加载时无响应

Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    Await objWebService.GetCurrentSessionsAsync 
End Sub 

但在执行这个“awaitable”代码的形式是反应迟钝,冻结,等待光标显示。

任何想法可能会导致此问题,以及如何处理它?

+0

检查我的编辑,我修改了PanagiotisKanavos之后的答案发表评论。 – Neolisk 2014-10-21 13:53:36

回答

1

至于你的答案,该代码可以是干净多了,如果你不结合不同的编程模式,检查了这一点:

Private Async Sub frmMain_Load(sender As Object, 
           e As EventArgs) Handles MyBase.Load 
    Dim res = Await GetCurrentSessionsAsync() 
End Sub 

Private Async Function GetCurrentSessionsAsync() As Task(Of com.services.Server) 
    Try 
    Return Await Task.Factory. 
     StartNew(Function() objWebService.GetCurrentSessions) 
    Catch ex As Exception 
    Glob.ErrorLog("GetCurrentSessions", ex, True) 
    Return New com.services.Server 
    End Try 
End Function 

参考文献:

+1

太棒了!谢谢你,我有一种感觉,我可以用更简单的方式实现这一点,但由于我不是这方面的专家,我害怕我永远不会得到它:$ – Saleem 2014-10-22 13:47:40

1

关键问题是Async不会奇迹般地让你的方法异步。它只让编译器知道你的方法将有Await关键字,并且代码需要是converted into a state machine即使方法标记为Async,任何未等待的代码也会同步执行。考虑下面的例子:

Private Async Sub Form1_Load(sender As Object, 
          e As EventArgs) Handles MyBase.Load 
    Await LongRunning1() 'opens the form, then asynchronously changes 
         'Text property after 2 seconds 
End Sub 

Private Async Function LongRunning1() As Task 
    Await Task.Factory.StartNew(Sub() Threading.Thread.Sleep(2000)) 
    Me.Text = "Finished LongRunning1" 
End Function 

这里长时间运行的过程,Thread.Sleep作为一个例子,被包裹成一个任务,并且有一个Await关键字。它告诉编译器在执行下一行之前等待任务内部的语句完成。如果没有AwaitText属性将立即设置。

现在,假设你有一些长期运行的同步代码在你Async方法:在这种情况下

Private Async Sub Form1_Load(sender As Object, 
          e As EventArgs) Handles MyBase.Load 
    Await LongRunning2() 'synchronously waits 2 seconds, opens the form, 
         'then asynchronously changes Text property after 2 seconds 
End Sub 

Private Async Function LongRunning2() As Task 
    Threading.Thread.Sleep(2000) 
    Await LongRunning1() 
    Me.Text = "Finished LongRunning2" 
End Function 

注意到它同步等待Thread.Sleep完成,因此对于最终用户,您的应用程序显示为挂。底线是 - 必须知道哪些方法调用可以长时间运行,并将它们包装到基于任务的await模型中。否则,您可能会看到您遇到的问题。

如果这听起来太复杂了,可以启动后台工作器(.NET 2.0+)或使用TPL(.NET 4.0+)来启动任务。如果您希望进入较低级别,则从.NET 1.1开始可以使用线程。然后在窗体/控件的顶部显示一些等待/进度窗口/叠加层,但功能尚不可用。检查这些了:

感谢@PanagiotisKanavos指着我在正确的方向。

+1

这是不正确的。您*可*具有异步事件处理程序,因此存在'async void'或'Async Sub'语法。这实际上是一个使用此语法除事件处理程序以外的任何错误。 – 2014-10-21 07:59:46

+0

@PanagiotisKanavos:你说得对。我给了这个更多的研究,并编辑了我的答案。让我知道你的想法。 – Neolisk 2014-10-21 13:47:39

+1

我注意到,以后我会标记你的答案!谢谢你的更新。 – Saleem 2014-10-21 15:34:54

0

所以这里它是什么(我不得不说,Neolisk和Panagiotis的答案导致我的解决方案): 什么使我的加载形式无响应似乎是一个Web服务中的错误,只有第一次调用我的网络服务会产生这个问题。所以如果第一次调用是在表单加载之后进行的,那么在另一个事件中,我会面临同样的问题。 为了解决这个问题,我改变了使用TaskCompletionSource变量通过web服务调用我的第一个方法的方式,并使用Thread调用我的第一个方法。我会发布我之前/之后的代码,以确保我清楚地提供了我的修复程序。我希望

Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    Dim res = Await GetCurrentSessionsAsync() 
End Sub 

Dim _tcServer As New TaskCompletionSource(Of MyProject.com.services.Server) 

Private Async Function GetCurrentSessionsAsync() As Task(Of com.services.Server) 
    Try 
     Dim th As New System.Threading.Thread(AddressOf GetCurrentSessions) 
     th.Start() 
     Return Await _tcServer.Task 
    Catch ex As Exception 
     Return New MyProject.com.services.Server 
    End Try 
End Function 

Private Sub GetCurrentSessions() 
    Try 
     Dim res = objWebService.GetCurrentSessions 
     _tcServer.SetResult(res) 
    Catch ex As Exception 
     Glob.ErrorLog("GetCurrentSessions", ex, True) 
    End Try 
End Sub 

这可以帮助别人的未来:

前:

Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    Dim res = Await objWebService.GetCurrentSessionsAsync 
End Sub 

后。 谢谢。

+0

检查我的其他答案(我决定保持分开,以避免混淆)。 – Neolisk 2014-10-22 13:42:06