【问题标题】:Asynchronous WCF calls timeout on client side after 10 seconds10 秒后客户端异步 WCF 调用超时
【发布时间】:2011-04-13 13:10:39
【问题描述】:

编辑

看了一段时间后,我认为这可能是我的开发框的配置问题。但是,在将源代码干净下载到另一台开发机器后,我仍然遇到这个问题。

我有一个异步调用 WCF 服务的 Silverlight 客户端。间歇性地,我会得到一个通用的NotFound 异常。在我调用的几乎所有服务上,异常(众所周知缺乏细节)都会间歇性发生。

事情就是这样。通过明智地设置断点,我已经能够确定服务端正在正常执行。正在检索和返回数据。问题似乎更多地出在客户端。

这就是问题所在...如果我让服务执行超过 10 秒,我可以始终让异常发生。当我这样做时,它永远不会回到我完成的回调。相反,我在服务的客户端 Reference.cs 中得到了异常:

        public System.Collections.ObjectModel.ObservableCollection<Project.Ui.SilverLight.ServiceName.ModelName> EndGetService(System.IAsyncResult result) {
            object[] _args = new object[0];
            System.Collections.ObjectModel.ObservableCollection<roject.Ui.SilverLight.ServiceName.ModelName> _result = ((System.Collections.ObjectModel.ObservableCollection<roject.Ui.SilverLight.ServiceName.ModelName>)(base.EndInvoke("GetService", _args, result)));
            return _result;
        }

我得到的例外是(不是很有帮助):

System.ServiceModel.CommunicationException was unhandled by user code
  Message=The remote server returned an error: NotFound.
  StackTrace:
       at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)
       at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
       at System.ServiceModel.ClientBase`1.ChannelBase`1.EndInvoke(String methodName, Object[] args, IAsyncResult result)
       at Project.Ui.SilverLight.Service.ServicesClient.ServicesClientChannel.EndGetxxxxx(IAsyncResult result)
       at Project.Ui.SilverLight.Service.ServicesClient.Project.Ui.SilverLight.Service.IServices.EndGetxxxx(IAsyncResult result)
       at Project.Ui.SilverLight.Service.ServicesClient.OnEndGet(IAsyncResult result)
       at System.ServiceModel.ClientBase`1.OnAsyncCallCompleted(IAsyncResult result)
  InnerException: System.Net.WebException
       Message=The remote server returned an error: NotFound.
       StackTrace:
            at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
            at System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
            at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)
       InnerException: System.Net.WebException
            Message=The remote server returned an error: NotFound.
            StackTrace:
                 at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
                 at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
                 at System.Net.Browser.AsyncHelper.<>c__DisplayClass2.<BeginOnUI>b__0(Object sendState)
            InnerException: 

绑定信息(名称已更改,但确实与正在执行的服务匹配)

    <binding name="Project.WebUI.Services.xxxxxServices.customBinding0" closeTimeout="00:01:00"
      openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00">
      <binaryMessageEncoding/>
      <httpTransport />
    </binding>

...

  <service name="Project.WebUI.Services.xxxxxServices">
    <endpoint address="" binding="customBinding" bindingConfiguration="Project.WebUI.Services.xxxxxServices.customBinding0"
      contract="Project.WebUI.Services.xxxxxServices" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>

我相信我已经检查了相关的超时。频道的operationTimeout 设置为至少一分钟,ReceiveTimeout 和 OpenTimeout 也是如此。 Silverlight 异步 WCF 调用是否有一些神秘之处需要设置为让它运行超过 10 秒?

【问题讨论】:

  • 你为什么称之为超时?它看起来很像 NotFound 错误 (404)。
  • 但不是“未找到”。这确实是这里发生的超时。如果服务运行时间少于 10 秒,我就是金。这就是让我发疯的原因。我知道服务正在执行,并且我知道它将返回有效数据。只要在 10 秒内完成,就不会出错。
  • @Robaticus:我怀疑 .NET 想象在某处看到 404 错误。
  • @John - 我听到了,但我也用自己的两只眼睛看到了正在发生的事情。 :) 我确实在某处读到过,有时 Silverlight 会将故障掩盖为 NotFound。无论如何,它看起来确实像是某种机器配置问题。 Associate 尝试了相同的代码库,并且运行良好。我可能得暂时改用笔记本电脑编码。
  • @Robaticus:你有没有解决这个问题?如果是,如何?我们遇到同样的问题已经有一段时间了,完全随机的 NotFound 错误,FaultBehavior 没有帮助等等。我的直觉告诉我它也与超时有关,或者至少感觉是这样......

标签: silverlight wcf exception


【解决方案1】:

在上面的配置文件中,它们看起来像是来自服务器的配置。您是否也检查了客户端配置?客户端通道上的 SendTimeout 和 ReceiveTimeout 属性都默认为一分钟,但它们可能已被调整或覆盖。当然,您应该检查您的配置 XML 文件,以及您在代码中创建绑定的位置,因为可能在那里设置与您的配置文件冲突的属性。 (在客户端和服务器上。)

【讨论】:

  • 我已经检查了这两个,甚至专门设置客户端使用超过 10 秒的时间。我仍然看到这个问题。我真的开始认为我的开发服务器只是有一些基础设施部分(Silverlight SDK、WCF 等?)已经过时了。
  • 这当然有可能——我以前也遇到过这种情况。但接下来我将通过配置 WCF 跟踪开始(如所述,例如,此处:software.intel.com/en-us/blogs/2010/02/03/…)。您可能还应该在 WCF 服务上启用 Silverlight 故障,如下所述:msdn.microsoft.com/en-us/library/dd470096(VS.96).aspx。这可能会为 Silverlight 提供有关问题所在的更多信息。
  • 谢谢。虽然我认为我做到了,但今晚我将验证并重新实现 Silverlight 故障。如果我还没有秃顶,我想我会在这个上拔头发。
【解决方案2】:

可能是网络上的东西。

this 中,他们收到了相同的错误消息,但实际上是 504 网关超时。

例如,如果您在 silverlight 应用程序和服务器之间有一个代理服务器,它将关闭连接,以便回调无法到达客户端。

【讨论】:

  • 你能检查一下你机器上的代理设置吗,即使是本地地址,它也可能会去代理服务器然后再回来
【解决方案3】:

出于好奇,目前web.config中设置的idleTimeout是什么?可以设置为10分钟吗?

更新

所以这是你的问题!这是 idleTimeout 的一个已知问题!只需删除该设置,一切就会恢复正常。

【讨论】:

  • 我相信它设置为 00:10:00
  • 看了,不幸的是,不是这样。我已明确将所有四个超时的超时设置为超过一分钟。
【解决方案4】:

找不到您gettign的原因不是因为超时。我花了一周的时间试图弄清楚这一点。

我提到了 silverlight,但这不是 silverlight 特定的问题。

由于错误代码的产生方式,存在未找到的故障。您需要拦截任何故障并更改错误代码 - 这将导致错误被正确报告并且由于安全原因而不会被过滤掉。

如果你仔细想想,没有找到服务器是因为调用是异步的,并且由于你的代码中的异常而死掉了。

我在我的 wcf 服务中使用这个类来插入 - 我通过 web.config 执行此操作,但是不难更改它,以便它在服务本身上具有类级别属性。

您可能想要删除所有合同内容。它正在我正在从事的项目中使用,但与此问题无关。

 [AttributeUsage(AttributeTargets.Class)]
    public class FaultBehavior : Attribute, IServiceBehavior,  IEndpointBehavior
    {  

    public class SilverlightFaultMessageInspector : IDispatchMessageInspector
    {

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            Contract.Assume(reply !=null );
            if (reply.IsFault)
            {
                HttpResponseMessageProperty property = new HttpResponseMessageProperty();

                // Here the response code is changed to 200.
                property.StatusCode = System.Net.HttpStatusCode.OK;

                Contract.Assume(reply.Properties != null);
                reply.Properties[HttpResponseMessageProperty.Name] = property;
            }
        }

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            // Do nothing to the incoming message.
            return null;
        }


    }


    #region IServiceBehavior Members

    void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {

    }

    void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        Contract.Assume( serviceHostBase != null);
        Contract.Assume(serviceHostBase.ChannelDispatchers != null);

        foreach (ChannelDispatcher cDispatcher in serviceHostBase.ChannelDispatchers)
        {
            Contract.Assume(cDispatcher != null);
            Contract.Assume(cDispatcher.Endpoints != null );
            foreach (EndpointDispatcher endpointDisbatcher in cDispatcher.Endpoints)
            {
                Contract.Assume(endpointDisbatcher != null);
                Contract.Assume(endpointDisbatcher.DispatchRuntime  != null);
                Contract.Assume(endpointDisbatcher.DispatchRuntime.MessageInspectors  != null);
                endpointDisbatcher.DispatchRuntime.MessageInspectors.Add(new SilverlightFaultMessageInspector());
            }
        }
    }

    void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {

    }

    #endregion

    #region IEndpointBehavior Members

    void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {

    }

    void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {

    }

    void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        Contract.Assume(endpointDispatcher != null);
        Contract.Assume(endpointDispatcher.DispatchRuntime != null);
        Contract.Assume(endpointDispatcher.DispatchRuntime.MessageInspectors != null);
        SilverlightFaultMessageInspector inspector = new SilverlightFaultMessageInspector();
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
    }

    void IEndpointBehavior.Validate(ServiceEndpoint endpoint)
    {

    }

    #endregion
}

然后您需要定义将出现在 web.config 中的元素

public class FaultHandlerElement   : BehaviorExtensionElement 
{
    protected override object CreateBehavior()
    {
        return new FaultBehavior();
    }

    public override Type BehaviorType
    {
        get { return typeof(FaultBehavior); }
    }


}

然后在网络配置中,您需要将其添加到服务模型部分 - 故障异常下面会有一条波浪线;)

<system.serviceModel>
    <extensions>
        <behaviorExtensions>
            <add name="faultBehaviourExtension"
  type="CopSilverlight.Web.FaultHandlerElement, CopSilverlight.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
        </behaviorExtensions>
    </extensions

然后你把你的行为联系起来,像这样使用它

   <serviceBehaviors>
                <behavior name="basicHttpBehaviour">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <faultBehaviourExtension />
                </behavior>

另一种“修复”方法是在您的 wcf 服务中打开跟踪 需要注意的是,如果你不创建目录,它根本不会产生日志

    <system.diagnostics>
        <sources>
            <source name="System.ServiceModel"
                switchValue="Information, ActivityTracing"
                propagateActivity="true">
                <listeners>
                    <add name="traceListener"
  type="System.Diagnostics.XmlWriterTraceListener"
  initializeData="c:\logs\appName\wcf.svclog"  />
                </listeners>
            </source>
        </sources>
    </system.diagnostics>

虽然日志记录并不理想 - 第一个解决方案实际上解决了问题。

我已经实现了这两个,现在我的 Silverlight 应用程序出现异常,正如您所期望的那样。

【讨论】:

  • 我仍然认为这里有一个时间因素,但我相信你的回答将帮助我找出它发生的地方。谢谢。
  • 很可能。然而,Not Found 错误只是一个阻碍你看到真正原因的门面。
  • 经过额外测试,我发现这绝对是客户端发生的事情。
  • 按照我的建议,您是否得到了未找到的异常?因为你的问题是这个例外。未找到是由 wcf 服务将故障错误代码设置为 500 引起的。如果您已将其更改为 200,那么您将看到不同的异常,这将允许您修复代码。如果问题出在客户端,那么为什么 wcf 服务会给您一个错误?是的,您可能会将错误的数据传递给它,但事实仍然是要找到真正的原因,您需要使用我上面建议的内容才能获得真正的异常和堆栈跟踪。我回答了你的问题。
  • 是的,尽管在 wcf 中起源,异常将始终出现在 reference.cs 中。
猜你喜欢
  • 2012-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-20
  • 2012-11-21
  • 1970-01-01
  • 2013-03-10
  • 1970-01-01
相关资源
最近更新 更多