2015-11-30 36 views
2

我想通過web服務從數據庫查詢數據。提供的API允許發送批量請求,以便在一個HTTP請求中發送多個請求。我想從中受益,並試圖通過使用異步代碼和任務構建一個C#接口來使用此服務。如何從其他功能完成任務?

我的目標是要實現類似如下:API的

// Service class that abstracts the server interface. 
class Service 
{ 
    // Return all StateA objects at the next server contact. 
    public Task<IEnumerable<StateA>> GetStatesA() { ... } 
    // Return all StateB objects at the next server contact. 
    public Task<IEnumerable<StateB>> GetStatesB() { ... } 
    // Send all queued requests to the server. 
    public Task SendRequests() { ... } 
} 

用法:

// Query all StateA and StateB objects from the database and 
// process them as soon as they arrive. 
service.GetStatesA().ContinueWith((t) => DoSomething(t.Result)); 
service.GetStatesB().ContinueWith((t) => DoSomething(t.Result)); 

// Some other code 

// Actually access the API such that the data is queried and the Tasks completed. 
service.SendRequests(); 

從我所知,在C#中的任務只能包裹同步功能和返回時,他們完成。有沒有辦法從外部完成任務?

我正在尋找類似於Dart中的Completer類(請參閱https://api.dartlang.org/1.13.0/dart-async/Completer-class.html)。

+0

我建議的一件事就是不要返回任務>。相反,返回一個物化列表......就我個人而言,當嘗試組合迭代器的延遲執行和異步/等待狀態機時,我遇到了意想不到的結果。 http://ctigeek.net/using-asyncawait-with-ienumerable-and-yield-return/ –

回答

2

什麼你要找的是一個TaskCompletionSource<T>

public class Foo 
{ 
    private readonly TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); 
    public Task GetStateA() 
    { 
     // Do stuff; 
     return tcs.Task; 
    } 

    public Task GetStateB() 
    { 
     //Do stuff 
     return tcs.Task; 
    } 

    public async Task QueryApiAsync() 
    { 
     // Query the API 
     tcs.SetResult(true); 
    } 
} 

雖然可以使用,但在我看來像你暴露是不是真的很方便的API。我不希望GetStateA()返回一個Task,只有在執行批處理查詢時纔會完成。我寧願有一種批處理方法,它提供了一個IEnumerable<States>,並在批次完成後返回給調用者。如果你沒有真正計劃允許單個狀態查詢API。

所以,我要麼把一個具有Enqueue方法,它調用回調的API方法:

public interface Foo 
{ 
    void Enqueue<T>(T state, Action callback) where T : State; 
} 

或實際暴露使得單一調用API,以及批量操作的功能:在C#

public interface Foo 
{ 
    Task<List<StateA>> GetStatesAAsync(); 
    Task<List<StateB>> GetStatesBAsync(); 
    Task<List<IState>> GetBatchStatesAsync(IEnumerable<IState> states); 
} 
+0

TaskCompletionSource真的很強大 - 我個人在集成測試SignalR事件排放時使用它。例如。 'var evt = await testContext.ExpectEvent ()',使測試非常可讀。 – Jeff

+0

@Jeff肯定。儘管在這種特殊情況下,我不確定這是OP應該如何使用的。 –

+1

雖然我同意這不是TCS的主要用例,但它*使事情變得非常容易實現。 – Jeff

0

任務只能包裹同步功能,當他們完成返回。有沒有辦法從外部完成任務?

我想刺探回答這個問題的部分(同意@Yuval Itzchakov)。使用.NET 4.0在TPL中引入了TaskTask<T>類。最初,使用任務類的理想方法是使用流利的API,即:鏈接ContinueWith。然而,今天,對於任務返回方法,最好使用async/await關鍵字。假設這是你的意思,使用await將從外部「完成」任務。 await關鍵字將暫停執行該方法,直到等待完成的任務。

+0

我的主要想法是,我將不同的動作(查詢數據,但也推送新的數據)分批到一個服務器訪問。我選擇使用'ContinueWith',因爲我不希望我的線程在每次排隊時都被阻塞,但是如果我調用'await SendRequests()',則只有一次。當服務器的響應到達時,我希望以前排隊的所有工作都能自動執行。 – Dominik

+0

啊,好的。現在更有意義了......我會考慮使用ConcurrentQueue ,因爲它是線程安全的,您可以將所需內容排入隊列,然後通過出隊和發送方式發送請求。 https://msdn.microsoft.com/en-us/library/dd267265(v=vs.110).aspx –

相關問題