gpt4 book ai didi

c# - 等待服务任务获取 TaskCanceledException : A task was canceled

转载 作者:太空狗 更新时间:2023-10-29 23:37:14 25 4
gpt4 key购买 nike

我有一个应用程序 (UWP - Win10) 和一个 Windows 服务。

该服务在后台运行,它们都是用 C# 开发的。 “callAsync”是服务上的方法。我正在使用 await 在客户端调用它。

var obj = await callAsync(10);

问题是:如果此调用花费的时间少于 1 分钟 40 秒(100 秒),则一切正常。但是如果超过1min40s,就会出现异常“TaskCanceledException: A task was canceled”。

我搜索了 SO 和网络,但仍然找不到任何关于如何解决此“超时”问题的指示。我已经在应用程序和服务 app.config 上添加了所有“打开/关闭/接收/发送”超时标志,尽管在这种情况下抛出的异常是不同的。

如果我在客户端尝试简单的延迟:

await Task.delay(200000); 

它正常工作。

该服务是通过VS2015“添加服务引用”添加的。我还“附加”到服务器,服务器保持运行并在日志前后在控制台中打印(以确认一切正常)。

我错过了什么?我需要更改什么配置和在哪里才能使任务运行超过 1 分 40 秒?

代码:

服务器伪代码示例:

接口(interface)文件:

[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>

App伪代码示例:

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;

更新 #1

这种情况只发生在UWP中。我创建了一个类似的 WinForms 项目,一切都按预期进行。这意味着它可能与 UWP 有关。

最佳答案

经过多次尝试,操作不同的配置文件,我还没有找到关于如何删除 100 秒超时限制的解决方案。为了解决这个具体问题,我实现了一个对策。

我在尝试过程中发现的是:

  • 如果项目在 WinForms 中,一切都会按预期进行。这意味着,这个 100 秒的限制是 UWP 的“功能”;
  • 如果您将 SendTimeout 减少到小于 100 秒,它将使用相应的计时器抛出 TimeoutException;
  • 这不是 Windows 服务独有的。与 SOAP Web 服务实现通信时也会发生这种情况;
  • 这似乎只有在您执行需要与服务引用进行“外部通信”的任务时才会发生。如果您有一个需要超过 100 秒的“内部”任务,它会按预期工作(例如 await Task.delay(250000))。

我是如何解决这个问题的?

在 C# SO channel 聊天后,@Squiggle 提出了一种轮询方法,这就是我成功实现和测试的方法。

这些是我采取的步骤:

  1. 我更新了现有的服务请求 (call(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。

关于c# - 等待服务任务获取 TaskCanceledException : A task was canceled,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37817934/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com