簡體   English   中英

從異步方法關閉WCF服務?

[英]Closing WCF Service from Async method?

我在.NET 4.5.2上創建的MVC 5 ASP.NET應用程序上有一個服務層項目,該項目調出外部第三方WCF服務以異步獲取信息。 調用外部服務的原始方法如下(總共共有3種,我從GetInfoFromExternalService方法中依次調用(請注意,它實際上並未調用該名稱-只是為了說明而命名))

    private async Task<string> GetTokenIdForCarsAsync(Car[] cars)
    {
        try
        {
            if (_externalpServiceClient == null)
            {
                _externalpServiceClient = new ExternalServiceClient("WSHttpBinding_IExternalService");
            }

            string tokenId= await _externalpServiceClient .GetInfoForCarsAsync(cars).ConfigureAwait(false);

            return tokenId;
        }
        catch (Exception ex)
        {
            //TODO plug in log 4 net 
            throw new Exception("Failed" + ex.Message);
        }
        finally
        {
            CloseExternalServiceClient(_externalpServiceClient);
            _externalpServiceClient= null;
        }
    }

因此,這意味着當每個異步調用完成后,將運行finally塊-WCF客戶端關閉並設置為null,然后在發出另一個請求時進行更新。 這一直很好,直到需要進行更改為止,如果用戶傳遞的汽車數量超過1000,我將創建一個Split函數,然后在WhenAll中分別使用1000調用我的GetInfoFromExternalService方法,如下所示:

if (cars.Count > 1000)
        {
            const int packageSize = 1000;
            var packages = SplitCarss(cars, packageSize);

            //kick off the number of split packages we got above in Parallel and await until they all complete
            await Task.WhenAll(packages.Select(GetInfoFromExternalService));
         }

但是,現在這好像掉了一樣,好像我有3000輛車,在WCF服務上調用GetTokenId新聞的方法調用,但是最后一個塊將其關閉,因此試圖運行的第二批1000拋出異常。 如果我刪除了finally塊,則代碼可以正常工作-但是,不關閉此WCF客戶端顯然不是一個好習慣。

我曾嘗試將其放在if if塊后面,評估cars.count的位置-但是,如果用戶上傳了例如2000輛汽車,並且完成並在1分鍾內運行,同時由於該用戶在網頁中擁有控制權,上載另一個2000或其他用戶可以上載,並且再次失敗,並拋出異常。

有沒有人可以看到正確關閉外部服務客戶端的好方法?

根據您的相關問題 ,您的“拆分”邏輯似乎無法提供您想要實現的目標。 WhenAll仍然並行執行請求,因此您可能最終在任何給定時間運行了1000個以上的請求。 使用SemaphoreSlim可以限制同時活動的請求的數量並將該數量限制為1000。這樣,您就無需進行任何拆分。

另一個問題可能是您如何處理ExternalServiceClient客戶端的創建/處置。 我懷疑那里可能有比賽條件。

最后,當您從catch塊重新拋出時,至少應包括對原始異常的引用。

以下是解決這些問題的方法(未經測試,但應能為您提供想法):

const int MAX_PARALLEL = 1000;
SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(MAX_PARALLEL);

volatile int _activeClients = 0;
readonly object _lock = new Object();
ExternalServiceClient _externalpServiceClient = null;

ExternalServiceClient GetClient()
{
    lock (_lock)
    {
        if (_activeClients == 0)
            _externalpServiceClient = new ExternalServiceClient("WSHttpBinding_IExternalService");
        _activeClients++;
        return _externalpServiceClient;
    }
}

void ReleaseClient()
{
    lock (_lock)
    {
        _activeClients--;
        if (_activeClients == 0)
        {
            _externalpServiceClient.Close();
            _externalpServiceClient = null;
        }
    }
}

private async Task<string> GetTokenIdForCarsAsync(Car[] cars)
{
    var client = GetClient();
    try 
    {
        await _semaphoreSlim.WaitAsync().ConfigureAwait(false);
        try
        {
            string tokenId = await client.GetInfoForCarsAsync(cars).ConfigureAwait(false);
            return tokenId;
        }
        catch (Exception ex)
        {
            //TODO plug in log 4 net 
            throw new Exception("Failed" + ex.Message, ex);
        }
        finally
        {
            _semaphoreSlim.Release();
        }
    }
    finally
    {
        ReleaseClient();
    }
}

根據評論更新

外部Web服務公司可以接受我在一次調用中傳遞多達5000個汽車對象-盡管他們建議將批量分為1000個並一次並行運行5個對象-因此,當我提到7000時,我並不是說GetTokenIdForCarAsync將被稱為7000次-當前使用我的代碼應該調用7次-即給我7個令牌ID-我想知道我是否可以使用您的信號量苗條先並行運行5個,然后並行運行2個

所做的更改很小(但未經測試)。 第一:

const int MAX_PARALLEL = 5;

然后,使用Marc Gravell的ChunkExtension.Chunkify ,我們引入GetAllTokenIdForCarsAsync ,而后者將從上面調用GetTokenIdForCarsAsync

private async Task<string[]> GetAllTokenIdForCarsAsync(Car[] cars)
{
    var results = new List<string>();
    var chunks = cars.Chunkify(1000);
    var tasks = chunks.Select(chunk => GetTokenIdForCarsAsync(chunk)).ToArray();
    await Task.WhenAll(tasks);
    return tasks.Select(task => task.Result).ToArray();
}

現在,您可以將所有7000輛汽車傳遞給GetAllTokenIdForCarsAsync 這是一個框架,如果任何批處理請求失敗(可以由您自己決定),可以使用一些重試邏輯進行改進。

暫無
暫無

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

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