2016-06-14 168 views
5

我有一個應用程序(UWP - Win10)和一個Windows服務。等待服務任務獲取TaskCanceledException:任務被取消

服務在後臺運行,它們都是用C#開發的。 「callAsync」是服務的方法。我正在等待在客戶端上調用它。

var obj = await callAsync(10); 

的問題是: 如果該調用需要不到1min40s(100秒)時,那麼一切工作正常。但是,如果它需要超過1分40秒,則會發生異常「TaskCanceledException:任務被取消」。

我有搜索和網頁,但仍無法找到任何跡象表明如何解決這個「超時」問題。我在應用程序和服務app.config中添加了所有「打開/關閉/接收/發送」超時標誌,雖然在這種情況下引發的異常是不同的。

如果我嘗試在客戶端簡單的延遲:

await Task.delay(200000); 

它工作正常。

該服務是通過VS2015「添加服務參考」添加的。我也「附加」到服務器,並且服務器繼續運行並在日誌前後在控制檯中打印(以確認一切正常)。

我缺少什麼?什麼配置和哪裏需要改變,這樣任務可以運行超過1分40秒?

CODE:

服務器僞代碼示例:

接口文件:

[ServiceContract(Namespace="http://.....")] 
interface ICom { 

    [OperationContract] 
    int call(int val); 

} 

Service.cs

public ServiceHost serviceHost = null; 
    public BlaBlaWindowsService() 
    { 
     ServiceName = "BlaBlaWindowsService"; 
    } 

    public static void Main() 
    { 
     ServiceBase.Run(new BlaBlaWindowsService()); 
    } 


    protected override void OnStart(string[] args) 
    { 
     if (serviceHost != null) 
     { 
      serviceHost.Close(); 
     } 

     serviceHost = new ServiceHost(typeof(BlaBlaService)); 

     serviceHost.Open(); 
    } 

    protected override void OnStop() 
    { 
     if (serviceHost != null) 
     { 
      serviceHost.Close(); 
      serviceHost = null; 
     } 
    } 
} 

[RunInstaller(true)] 
public class ProjectInstaller : Installer 
{ 
    private ServiceProcessInstaller process; 
    private ServiceInstaller service; 

    public ProjectInstaller() 
    { 
     process = new ServiceProcessInstaller(); 
     process.Account = ServiceAccount.LocalSystem; 
     service = new ServiceInstaller(); 
     service.ServiceName = "BlaBlaWindowsService"; 
     Installers.Add(process); 
     Installers.Add(service); 
    } 
} 

BlaBlaService.cs

class TPAService : ITPAComunication { 

    public int call(int val) { 

     System.Threading.Thread.Sleep(200000) 
     return 0; 
    } 

} 

App.config文件:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
<system.serviceModel> 
<bindings> 
<binding name="ServiceTimeout" closeTimeout="00:10:00" receiveTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00"/> 
</bindings> 
     <services> 
      <service name="BlaBla.Service.Service" 
        behaviorConfiguration="ServiceBehavior"> 
      <host> 
       <baseAddresses> 
       <add baseAddress="http://localhost:8000/BlaBla/service"/> 
       </baseAddresses> 
      </host> 
      <endpoint address="" 
         binding="basicHttpBinding" 
         bindingConfiguration="ServiceTimeout" 
         contract="BlaBla.Service.ICom" /> 
      <endpoint address="mex" 
         binding="mexHttpBinding" 
         contract="IMetadataExchange" /> 
      </service> 
     </services> 
     <behaviors> 
      <serviceBehaviors> 
      <behavior name="ServiceBehavior"> 
       <serviceMetadata httpGetEnabled="true"/> 
       <serviceDebug includeExceptionDetailInFaults="False"/> 
      </behavior> 
      </serviceBehaviors> 
     </behaviors> 
     </system.serviceModel> 
    </configuration> 

的應用程序的僞代碼示例:

System.ServiceModel.EndpointAddress epa = new System.ServiceModel.EndpointAddress("http://localhost:8000/blabla/service"); 

System.ServiceModel.BasicHttpBinding bhb = new System.ServiceModel.BasicHttpBinding(); 

Timespan t = new TimeSpan(0, 10, 0); 

bhb.SendTimeout = t; bhb.ReceiveTimeout =t; bhb.OpenTimeout = t; bhb.CloseTimeout = t; 

Blabla.ComunicationClient com = new Blabla.ComunicationClient(bhb, epa); 

var obj = await com.callAsync(int val); 

return obj; 

UPDATE#1

這種情況只發生在UWP中。我創建了一個類似的WinForms項目,一切都按預期工作。這意味着它可能與UWP有關。

+0

這可能是因爲Web請求超時而發生的: https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.timeout%28v=vs.110%29.aspx? f = 255&MSPPError = -2147217396 – Bas

+0

@Bas感謝您的評論,但一個超時(根據您剛纔鏈接的文檔,拋出一個WebException。我提到的情況拋出一個TaskCanceledException。(在鏈接的文檔中:「如果在超時期限內沒有返回資源,請求會拋出WebException」) – nunofmendes

回答

2

經過多次嘗試,操縱不同的配置文件,我還沒有找到解決方案,如何刪除超時限制100秒。爲了解決這個具體問題,我實施了一個對策。

我在我的嘗試發現是:

  • 如果該項目是在的WinForms,一切正常。這意味着,這100秒限制,是一個UWP「特徵」;
  • 如果您將SendTimeout減少到少於100秒,它將引發TimeoutException和相應的定時器;
  • 這不是Windows服務專有的。當與SOAP Web服務實現溝通時也會發生這種情況;
  • 只有當您正在執行需要使用服務引用的「外部通信」的任務時,纔會出現這種情況。如果您有一個需要超過100秒的「內部」任務,它將按預期工作(例如,等待Task.delay(250000))。

我怎麼解決這個問題?

在C#SO頻道聊天后,@Squiggle提出了輪詢方法,這就是我成功實施和測試的方法。

這是我所採取的步驟:

  1. 我更新了現有的服務請求(調用(INT VAL))接受另一種說法,一個GUID,所以我能夠確定哪些要求我想做的「輪詢」;
  2. 我在服務創建了一個附加請求,接受InquireAboutCurrentRequest並接受一個GUID參數,並返回一個int;
  3. 我使用新請求更新了UWP應用程序中的服務引用;
  4. 我用try catch叫了「await call(val,guid)」。我這樣做是因爲這些調用中的90%在不到30秒內返回*;
  5. 在catch中,我添加了一個「If」,用於檢查異常是否是CancelTask​​,如果我調用了「await InquireAboutCurrentRequest(guid)」;
  6. 此方法在windows服務中不斷檢查其他操作是否已結束並每隔X秒進行一次睡眠。由於第一次通話的總時間最多隻能是2分鐘,所以我只需要等待20秒;
  7. 之後我會相應地處理結果,但至少這次我知道我已經「等了2分鐘」的迴應。

還有其他可能的解決方案,如我沒有嘗試過的套接字,可以工作。

*如果所有請求都需要超過100秒,我建議在請求開始時使用輪詢方法,而不是等待try/catch。

+0

輪詢不合並。 「輪詢」是指反覆詢問,「池」是使用一組資源,其中個別請求從組中移除,然後在完成時將資源返回給組。這兩個詞在編程中經常使用,因此使用正確的詞很重要。 –

+0

好的。感謝您的澄清和編輯:) – nunofmendes

0

我不確定 - 但可能更好地使用Task.WhenAll而不是等待?

+0

它仍然會爲與該服務通信的任務引發任務取消異常。 – nunofmendes