1

我正在尝试调用 Web 服务并让我的代码等待该服务返回结果(或超时)。我的项目是 Silverlight 5,带有使用 .NET 4.0 的 Web 服务,我在 VS 2012 下使用 Microsoft.Bcl.Async.1.0.16\lib\sl4\Microsoft.Threading.Tasks.dll ... 任务运行这个项目。 Extensions.dll ... 和 Extensions.Silverlight.dll。

这就是我一直在做的事情并且它正在工作,但我正在尝试弄清楚如何更改我的代码,以便我可以使用 Async/Await 进程。Web 服务引用配置为在所有引用的程序集中返回 ObservableCollection 和 Generic.Dictionary 以及 Reuse 类型。

我需要转换为 Async/Await 的一些代码:

    Private _Units As Collections.ObjectModel.ObservableCollection(Of DC.SL.Services.WebServiceUnit.Units)
Public Property Units() As Collections.ObjectModel.ObservableCollection(Of DC.SL.Services.WebServiceUnit.Units)
    Get
        Return _Units
    End Get
    Set(ByVal value As Collections.ObjectModel.ObservableCollection(Of DC.SL.Services.WebServiceUnit.Units))
        _Units = value
        OnPropertyChanged(New PropertyChangedEventArgs("Units"))
    End Set
End Property


   Public Sub ReadUnits()

    Try

        ' Client is required
        If Not Me.Client Is Nothing Then

            ' User is required
            If Not Me.User Is Nothing Then

                ' Must be a real Client
                If Me.Client.ClientID > 0 Then

                    ' My have a sites
                    If Not Me.Site Is Nothing Then

                        ' Call the web service relative to where this application is running
                        Dim webServiceURI As New Uri("../WebServices/Unit.svc", UriKind.RelativeOrAbsolute)
                        Dim webServiceAddress As New EndpointAddress(webServiceURI)

                        ' Setup web Service proxy
                        Dim wsUnits As New DC.SL.Services.WebServiceUnit.UnitClient
                        wsUnits.Endpoint.Address = webServiceAddress

                        ' Add event handler so we can trap for web service completion
                        AddHandler wsUnits.LoadsCompleted, AddressOf LoadUnitsCompleted

                        ' Call web service to get Sites the user has access to
                        wsUnits.LoadsAsync(Me.Client, Me.Site.SiteID, Me.Size.SizeID, Me.RentalType.RentalTypeID, Me.UnitState)

                    End If

                End If

            End If

        End If

    Catch ex As Exception

        Dim Problem As New DC.SL.Tools.Errors(ex)

    End Try

End Sub

Private Sub LoadUnitsCompleted(ByVal sender As Object, ByVal e As DC.SL.Services.WebServiceUnit.LoadsCompletedEventArgs)

    Try

        If Not IsNothing(e.Result) Then

            Me.Units = e.Result

            If Me.Units.Count > 0 Then
                Me.Unit = Me.Units.Item(0)
            End If

        End If

    Catch ex As Exception

        Dim Problem As New DC.SL.Tools.Errors(ex)

    End Try

End Sub

仍然没有让这个工作......这是我现在所拥有的,但问题仍然存在...... UI线程执行继续并且不等待Web服务调用完成。

调用代码:

ReadUnitsAsync().Wait(3000)

这是更新的代码:

    Public Async Function ReadUnitsAsync() As Task(Of Boolean)

    Dim Results As Object = Await LoadReadUnitsAsync()

    Return True

End Function

Public Function LoadReadUnitsAsync() As Task(Of System.Collections.ObjectModel.ObservableCollection(Of DC.SL.Services.WebServiceUnit.Units))

    LoadReadUnitsAsync = Nothing

    Dim tcs = New TaskCompletionSource(Of System.Collections.ObjectModel.ObservableCollection(Of DC.SL.Services.WebServiceUnit.Units))

    ' Client is required
    If Not Me.Client Is Nothing Then

        ' User is required
        If Not Me.User Is Nothing Then

            ' Must be a real Client associated
            If Me.Client.ClientID > 0 Then

                ' Only get associated sites IF we don't have any defined
                If Not Me.Site Is Nothing Then

                    ' Call the web service relative to where this application is running
                    Dim webServiceURI As New Uri("../WebServices/Unit.svc", UriKind.RelativeOrAbsolute)
                    Dim webServiceAddress As New EndpointAddress(webServiceURI)

                    ' Setup Site web Service proxy
                    Dim wsUnits As New DC.SL.Services.WebServiceUnit.UnitClient
                    wsUnits.Endpoint.Address = webServiceAddress

                    ' Add event handler so we can trap for web service completion
                    AddHandler wsUnits.LoadUnitsCompleted, Sub(s, e)
                                                               If e.Error IsNot Nothing Then
                                                                   tcs.TrySetException(e.Error)
                                                               ElseIf e.Cancelled Then
                                                                   tcs.TrySetCanceled()
                                                               Else
                                                                   tcs.TrySetResult(e.Result)
                                                               End If
                                                           End Sub

                    '' Set Busy Status
                    'BusyStack.Manage(ProcessManager.StackAction.Add, "ReadUnits", Me.IsWorking, Me.IsWorkingMessage)

                    ' Call web service to get Sites the user has access to
                    wsUnits.LoadUnitsAsync(Me.Client, Me.Site.SiteID, Me.Size.SizeID, Me.RentalType.RentalTypeID, Me.UnitState)

                    Return tcs.Task

                End If

            End If

        End If

    End If

End Function

所以这里是最终的代码(缩写),似乎可以达到我的目标(也就是在继续之前等待 Web 服务完成)。

Public Class UIUnits
Implements INotifyPropertyChanged, IDataErrorInfo

Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

Public Async Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)

    Dim propertyEventHandler As PropertyChangedEventHandler = PropertyChangedEvent

    Try

        If propertyEventHandler IsNot Nothing Then

            RaiseEvent PropertyChanged(Me, e)

            Select Case e.PropertyName

                Case "Size"

                    Await ReadUnitsAsync()

        DoSomethingElseAfterWebServiceCallCompletes()

                Case Else

            End Select

        End If

    Catch ex As Exception

        Dim problem As New DC.SL.Tools.Errors(ex)

    End Try

End Sub

...

Private _Units As Collections.ObjectModel.ObservableCollection(Of DC.SL.Services.WebServiceUnit.Units)
Public Property Units() As Collections.ObjectModel.ObservableCollection(Of DC.SL.Services.WebServiceUnit.Units)
    Get
        Return _Units
    End Get
    Set(ByVal value As Collections.ObjectModel.ObservableCollection(Of DC.SL.Services.WebServiceUnit.Units))
        _Units = value
        OnPropertyChanged(New PropertyChangedEventArgs("Units"))
    End Set
End Property

...

Public Async Function ReadUnitsAsync() As Task(Of Boolean)

    Me.Units = Await LoadReadUnitsAsync()
    Return True

End Function

...

Public Function LoadReadUnitsAsync() As Task(Of System.Collections.ObjectModel.ObservableCollection(Of DC.SL.Services.WebServiceUnit.Units))

    LoadReadUnitsAsync = Nothing

    Dim tcs = New TaskCompletionSource(Of System.Collections.ObjectModel.ObservableCollection(Of DC.SL.Services.WebServiceUnit.Units))

    ' Client is required
    If Not Me.Client Is Nothing Then

        ' User is required
        If Not Me.User Is Nothing Then

            ' Must be a real Client associated
            If Me.Client.ClientID > 0 Then

                ' Only get associated sites IF we don't have any defined
                If Not Me.Site Is Nothing Then

                    ' Call the web service relative to where this application is running
                    Dim webServiceURI As New Uri("../WebServices/Unit.svc", UriKind.RelativeOrAbsolute)
                    Dim webServiceAddress As New EndpointAddress(webServiceURI)

                    ' Setup web Service proxy
                    Dim wsUnits As New DC.SL.Services.WebServiceUnit.UnitClient
                    wsUnits.Endpoint.Address = webServiceAddress

                    ' Add event handler so we can trap for web service completion
                    AddHandler wsUnits.LoadUnitsCompleted, Sub(s, e)
                                                               If e.Error IsNot Nothing Then
                                                                   tcs.TrySetException(e.Error)
                                                               ElseIf e.Cancelled Then
                                                                   tcs.TrySetCanceled()
                                                               Else
                                                                   tcs.TrySetResult(e.Result)
                                                               End If
                                                           End Sub

                    ' Call web service 
                    wsUnits.LoadUnitsAsync(Me.Client, Me.Site.SiteID, Me.Size.SizeID, Me.RentalType.RentalTypeID, Me.UnitState)

                    Return tcs.Task

                End If

            End If

        End If

    End If

End Function
4

2 回答 2

3

在这种情况下,从最低级别转换并向上工作可能是最容易的。首先,您需要在您的服务上定义您自己的TAP友好的扩展方法。如果你正在做桌面开发,VS 会为你生成这些,但不幸的是它不会为 Silverlight 生成这些。

MSDN 文档描述了如何包装 EAPEAP是使用*Async具有匹配*Completed事件的方法的模式)。如果您有 APM 方法,则将它们包装到 TAP中会更容易(APM是使用Begin*/End*方法对的模式)。

一旦你有一个包装器,例如,LoadUnitsTaskAsync改变你的方法来调用它而不是LoadUnitsAsync结果Await。这将要求您的ReadUnits方法为Async,因此将其更改为Task-returning Function(并将其名称从更改ReadUnitsReadUnitsAsync)。接下来更改所有调用者,ReadUnitsAsync使其Await结果。重复直到到达实际的事件处理程序,这可能是Async Sub(不要Async Sub用于任何中间方法;请Async Function ... As Task改用)。

于 2013-05-01T01:30:12.427 回答
2

我使用这个库在我的 Silverlight 5 项目中实现异步等待

于 2013-05-02T07:34:55.333 回答