2016-06-14 128 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