VB.Net + WebService:主要表单在加载时没有响应

时间:2014-10-20 15:05:18

标签: vb.net web-services async-await

我有一个VB.Net小项目link to sql使用网络服务(SOAP)。 我必须确保所有表格都能完全响应,无论如何,它都能很好地运作。我唯一的问题是加载应用程序! 主要的启动表单只有一行代码:

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

但是这个"等待"正在执行代码,表单没有响应,冻结并显示等待光标。

关于可能导致此问题的原因以及如何处理它的任何想法?

3 个答案:

答案 0 :(得分: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关键字。它告诉编译器在执行下一行之前等待任务内的语句完成。如果没有Await,则会立即设置Text属性。

现在假设您的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 :(得分: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

参考文献:

答案 2 :(得分:0)

所以这就是它(我不得不说Neolisk和Panagiotis的答案让我得到了解决方案): 是什么让我的加载形式没有响应是什么似乎是Web服务中的错误,只有我的Web服务的第一次调用会产生这个问题。因此,如果第一次调用是在表单加载后进行的,那么在另一个事件上,我将面临同样的问题。 为了解决这个问题,我改变了使用TaskCompletionSource变量通过Web服务调用第一个方法的方式,并使用Thread调用了我的第一个方法。我会发布我的前/后代码,以确保我清楚地完成了我的修复。

<强>之前:

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

<强>后:

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

我希望将来可以帮助别人。 谢谢。