增加 C# 中 WCF Web 服务的超时

问题描述 投票:0回答:6

我目前有一个应用程序正在调用服务器上的 Web 服务进行搜索。我们预计会返回大量数据,因此搜索时间超过一分钟是很常见的。

对于如此大量的搜索,我们收到了以下错误消息:

请求通道在 00:00:59.7350618 之后等待回复时超时。增加传递给 Request 调用的超时值或增加 Binding 上的 SendTimeout 值。分配给此操作的时间可能是较长超时的一部分。

这是我们在 StackOverflow 上发布的多个问题中看到的问题,不幸的是,没有一个可用的解决方案可以帮助我解决问题,甚至无法配置超时窗口。

我们都更改了客户端的 app.config,增加了其中涉及的所有超时(CloseTimeout、OpenTimeout、ReceiveTimeout 和 SendTimeout)以及服务器上服务的所有 web.config 值(closeTimeout、openTimeout 和 SendTimeout) 。

这些更改都没有产生任何影响,我仍然收到分钟超时。知道为什么更改这些值没有效果吗?

在下面的示例中,我们缩短了时间,以免在测试过程中等待整整一分钟。

Web.config:

<configuration>
  <system.web>
    <compilation targetFramework="4.0" />
  </system.web>
  <system.diagnostics>
    <trace autoflush="true" />
    <sources>
      <source name="System.Net">
        <listeners>
          <add name="TraceFile" />
        </listeners>
      </source>
      <source name="System.Net.Sockets">
        <listeners>
          <add name="TraceFile" />
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add name="TraceFile" type="System.Diagnostics.TextWriterTraceListener"
           initializeData="trace.log" />
    </sharedListeners>
    <switches>
      <add name="System.Net" value="Verbose" />
      <add name="System.Net.Sockets" value="Verbose" />
    </switches>
  </system.diagnostics>
  <system.serviceModel>
    <diagnostics>
      <messageLogging logMalformedMessages="false" logMessagesAtServiceLevel="false"
                      logMessagesAtTransportLevel="false" />
    </diagnostics>
    <services>
      <service behaviorConfiguration="SearchIndexServiceBehavior" name="SearchIndex.Service">
        <endpoint address="" binding="basicHttpBinding" contract="ISearchIndexServices" />
        <host>
          <timeouts closeTimeout="00:00:10" />
        </host>
      </service>
    </services>
    <bindings>
      <basicHttpBinding>
        <binding closeTimeout="00:00:10" openTimeout="00:00:15" sendTimeout="00:00:20"
                 receiveTimeout="00:00:25" maxBufferSize="2147483647" maxBufferPoolSize="2147483647"
                 maxReceivedMessageSize="2147483647">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
                        maxArrayLength="2147483647" maxBytesPerRead="2147483647"
                        maxNameTableCharCount="2147483647" />
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="SearchIndexServiceBehavior">
          <serviceMetadata httpGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <system.transactions>
    <defaultSettings timeout="00:05:00" />
  </system.transactions>
</configuration>

应用程序配置

<configuration>
  <configSections>
  </configSections>
  <startup>
  </startup>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_ISearchIndexServices" closeTimeout="00:00:10" openTimeout="00:00:15" receiveTimeout="00:10:00" sendTimeout="00:00:20" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="5242880" maxBufferPoolSize="524288" maxReceivedMessageSize="5242880" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true"> 
          <readerQuotas maxDepth="32" maxStringContentLength="5242880"maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None" realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://MyServer/SearchIndexService/SearchIndexServices.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISearchIndexServices" contract="WFC.ISearchIndexServices" name="BasicHttpBinding_ISearchIndexServices" />
    </client>
  </system.serviceModel>
</configuration>
c# wcf
6个回答
24
投票

我认为您可能遇到了客户端请求通道的OperationTimeout,由于某种原因,它很难通过标准配置属性进行调整。

在调用长时间运行的操作之前在客户端代码中尝试此操作:

((IContextChannel)clientProxy.InnerChannel).OperationTimeout = new TimeSpan(0,30,0); // For 30 minute timeout - adjust as necessary

其中

clientProxy
是服务引用生成的 Client 类的实例(派生自
ClientBase<ISearchIndexService>
)。


6
投票

你可以试试这个

 SeriveClient client=new ServiceClient();
    var time = new TimeSpan(0, 3, 0);
    client.Endpoint.Binding.CloseTimeout = time;
                client.Endpoint.Binding.OpenTimeout = time;
                client.Endpoint.Binding.ReceiveTimeout = time;
                client.Endpoint.Binding.SendTimeout = time;

5
投票

此服务模型示例显示了需要在客户端 web.config 中设置的绑定元素超时属性。

请注意,所有超时属性均设置为 10 分钟。此示例使用绑定配置元素来设置“maxItemsInObjectGraph”属性。通常,如果您需要调高超时,则意味着您可能正在传输大量数据。另请注意,要传输的数据大小均设置为最多可处理 2 GB。

<?xml version="1.0" encoding="UTF-8"?>
<system.serviceModel>
   <bindings>
      <basicHttpBinding>
         <binding name="BasicHttpBinding_ISearchIndexServices" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
            <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
            <security mode="None">
               <transport clientCredentialType="None" proxyCredentialType="None" realm="" />
               <message clientCredentialType="UserName" algorithmSuite="Default" />
            </security>
         </binding>
      </basicHttpBinding>
   </bindings>
   <client>
      <endpoint address="http://MyServer/SearchIndexService/SearchIndexServices.svc" behaviorConfiguration="SearchIndexServicesBehavior" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISearchIndexServices" contract="WFC.ISearchIndexServices" name="BasicHttpBinding_ISearchIndexServices" />
   </client>
   <behaviors>
      <endpointBehaviors>
         <behavior name="SearchIndexServicesBehavior">
            <dataContractSerializer maxItemsInObjectGraph="2147483647" />
         </behavior>
      </endpointBehaviors>
   </behaviors>
</system.serviceModel>

0
投票

超时时间是客户端发送超时时间。这是客户端准备等待响应的时间,因此必须在客户端而不是服务上设置


0
投票

超时是调试过程中的一个难题。谁能在一分钟内调试!我使用上面的 Junior M/BuzzWilder 并将以下内容添加到 app.config 中的服务调用中:

            <binding name="WSHttpBinding_bindingname"
                     openTimeout="01:00:00"
                     closeTimeout="01:00:00"
                     receiveTimeout="01:00:00"
                     sendTimeout="01:00:00"
                     >

再见服务超时。 :)


0
投票

截至目前,越来越多的 WCF 用户正在转向 ASP.Net Core,因此我在这里还添加了如何使用 CoreWCF 增加超时的指南,尽管该方法也应该适用于 WCF。

以下是如何更轻松地在 WCF 中测试和配置超时。超时在客户端项目中配置。

首先,图像证明或它没有发生。在这里,您可以看到我在 15 秒后超时,那么我是怎么做到的?

注意,我为客户端使用以下 Nuget 包,这是一个 .NET 6 控制台应用程序:

<ItemGroup>
    <PackageReference Include="System.ServiceModel.Duplex" Version="4.10.*" />
    <PackageReference Include="System.ServiceModel.Federation" Version="4.10.*" />
    <PackageReference Include="System.ServiceModel.Http" Version="4.10.*" />
    <PackageReference Include="System.ServiceModel.NetTcp" Version="4.10.*" />
    <PackageReference Include="System.ServiceModel.Security" Version="4.10.*" />
  </ItemGroup>

服务器项目使用这些 Nuget 包,我已经从 CoreWCF 模板制作了客户端和服务 WCF :

  <ItemGroup>
    <PackageReference Include="CoreWCF.Primitives" Version="1.*" />
    <PackageReference Include="CoreWCF.Http" Version="1.*" />
  </ItemGroup>

在客户端自动生成的Reference.cs文件中,我们得到了这个方法:

   [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")]
    public partial class ServiceClient : System.ServiceModel.ClientBase<MyService.IService>, MyService.IService
    {
        
        /// <summary>
        /// Implement this partial method to configure the service endpoint.
        /// </summary>
        /// <param name="serviceEndpoint">The endpoint to configure</param>
        /// <param name="clientCredentials">The client credentials</param>
        static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);

//more code 

我们记下客户端的命名空间,并添加以下带有一组配置的超时的部分类。根据需要调整这些超时。

我在这里添加了一个名为ServiceClient的文件,类名也与Reference.cs中的ServiceClient类名相匹配。

namespace MyService
{
    public partial class ServiceClient
    {

        /// <summary>
        /// Implement this partial method to configure the service endpoint.
        /// </summary>
        /// <param name="serviceEndpoint">The endpoint to configure</param>
        /// <param name="clientCredentials">The client credentials</param>
        static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials)
        {
            serviceEndpoint.Binding.OpenTimeout 
                = serviceEndpoint.Binding.CloseTimeout
                = serviceEndpoint.Binding.ReceiveTimeout
                = serviceEndpoint.Binding.SendTimeout = TimeSpan.FromSeconds(15);
        }

    }
}

此处设置的超时设置为 15 秒。显然,您希望这些超时时间更长一些,我只输入了一个小值来快速测试它。默认值通常是 30 或 60 秒,在生产中,您可能会考虑很多分钟,以防您的服务方法应该执行长时间运行的作业 - 或者考虑使用一个框架,例如 Hangfire。

这种方法的好处是,如果您更新 Reference.cs(这在 VS 2022 中仍然有点麻烦,不像以前在 .NET Frmaework 中使用 WCF 那么容易),您配置的设置仍然保留。通过设置端点绑定,您还可以进行许多其他配置。

© www.soinside.com 2019 - 2024. All rights reserved.