簡體   English   中英

Xamarin.Forms ViewModel 中的異步方法不等待 AzureServiceTokenProvider 和 SqlConnection 初始化

[英]Async method in Xamarin.Forms ViewModel not waiting for AzureServiceTokenProvider and SqlConnection to initialize

(編輯以添加有關我正在撥打的每個電話的更多詳細信息)

我有一個 Xamarin Forms 應用程序連接到 Azure 應用服務中托管的 .Net Core 2.2 Web 服務。

在我的視圖模型中,我有一個這樣的電話:

private async Task GetItems() {            
    var result = await itemsListFactory.GetItemsAsync()
}

這稱為:

public async Task<IEnumerable<IItemInfo>> GetItemsAsync() {
    return await ItemList.GetItemListAsync();
}

其中調用此(CSLA 業務對象):

  public static async Task<ItemList> GetItemListAsync() {
        return await DataPortal.FetchAsync<ItemList>();
    }

這稱為:

[Fetch]
private async void DataPortal_Fetch() {
    var rlce = RaiseListChangedEvents;
    RaiseListChangedEvents = false;
    IsReadOnly = false;

    using (var ctx = Dal.DalFactory.GetManager()) {
        var dal = ctx.GetProvider<IItemDal>();
        List<ItemDto> list = null;

        list = await dal.FetchAsync();

        foreach (var item in list) {
            Add(DataPortal.FetchChild<ItemInfo>(item));                    
        }
    }

    IsReadOnly = true;
    RaiseListChangedEvents = rlce;
}

其中調用:

public async Task<List<ItemDto>> FetchAsync() {

    var resultSet = new List<ItemDto>();

    var connectionManager = ServiceLocator.Current.GetInstance<IAzureConnectionManager>();

    using (var conn = await connectionManager.GetOpenConnectionAsync()) {
        /* Reading from DB */                    
    }

    return resultSet;         
}

AzureConnectionManager 的實現如下所示:

public async Task<SqlConnection> GetOpenConnectionAsync()
{            
    var accessToken = await new AzureServiceTokenProvider().GetAccessTokenAsync("https://database.windows.net/");
    var connection = new SqlConnection(dbconnection) {
        AccessToken = accessToken
    };

    await connection.OpenAsync();

    return connection;
}

但是,我第一次撥打此電話時(例如當天的第一次電話,或一段時間未使用該服務后),我沒有收到任何結果。 任何后續調用似乎都可以正常工作。 我的猜測是,這與由於不活動而必須采取一些“額外步驟”來返回數據的服務有關。

每當我調試 Web 服務並在我的視圖模型和服務器端代碼中設置斷點時,這種懷疑似乎都會得到證實。 每當服務的調用返回而沒有記錄時,它幾乎就像是從服務器提前返回一樣,因為它返回到沒有數據的視圖模型,然后我的調試器在收到訪問令牌后跳回服務器。 因此,就好像我的代碼決定不等待 GetAccessTokenAsync 和 OpenAsync 在返回客戶端之前完成它們必須執行的操作。

我可以通過將 .Result 添加到 GetAccessTokenAsync() 和 .Wait() 到 OpenAsync() 來解決這個問題,如下所示:

public async Task<SqlConnection> GetOpenConnectionAsync()
        {            
            var accessToken = new AzureServiceTokenProvider().GetAccessTokenAsync("https://database.windows.net/").Result;
            var connection = new SqlConnection(dbconnection) {
                AccessToken = accessToken
            };

            connection.OpenAsync().Wait();

            return connection;
        }

但這感覺就像一個黑客。

我懷疑這是我應該解決的方法,但也許確實如此。 如果這是處理這種情況的正確方法,至少我想了解這里發生了什么。

await 運算符暫停對封閉異步方法的評估,直到由其操作數表示的異步操作完成。 當異步操作完成時,await 運算符返回操作的結果(如果有)。 當 await 運算符應用於表示已完成操作的操作數時,它會立即返回操作結果,而不會暫停封閉方法。 await 運算符不會阻塞評估異步方法的線程。 當 await 運算符掛起封閉的異步方法時,控制權返回給方法的調用者。

關於這個的官方文件

因此,如果我們查看文檔中關於 Async/Await 的內容,您會注意到

當 await 運算符應用於表示已完成操作的操作數時,它會立即返回操作結果,而不會暫停封閉方法。

更有可能OpenAsync(); 被視為已經完成的操作數,因為您可能沒有等待返回,因此操作運行檢索您的數據,但因為您沒有在 OpenAsync 中掛起任何內容它可能假設操作數已經在第一個實例上完成,然后繼續數據已加載,因此在您第二次嘗試時您可以使用數據,因為它在第一次嘗試時已經填充。

所以我實際上希望看到更多的代碼。

然而,我要說的一件事是 .Wait() 是壞的如果你必須等待結果並強制等待更好的方法是.GetAwaiter().GetResult()我可以鏈接你一個研討會,在關於這一點的詳細信息。 但是在本質中.Wait()異常拋出到空白中並使它們極難跟蹤(或者至少比您希望的要困難得多)

“另請注意,我絕不會靠近 Async/Await 專家,所以請隨時糾正我”

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM