0

我创建了一个 wcf 服务来测试 wcf 超时。我的问题是即使超时已经过期,它仍然有效。

在此服务中,我创建了长时间运行的方法,并在其中创建了日志文件,然后我让服务超时。但即使服务超时已过期,日志文件仍然会附加数据,直到长时间运行的方法完成执行。?

这是怎么发生的?有没有办法阻止它?

服务超时为 1 分钟

长时间运行方法持续时间为:10 分钟

此服务使用 WAS 在 IIS 7.5 中托管

这是我的服务实现类

public class LongRunner : ILongRunner
{
    public void LongRunnerMethod()
    {
        int counter = int.Parse(ConfigurationManager.AppSettings["val"]);
        string text = string.Empty;

        for (int i = 0; true; i++)
        {
            Thread.Sleep(1000);
            if (i >= counter)
                break;
            text = string.Concat(i.ToString(), DateTime.Now.ToString());
            File.AppendAllText(@"C:\Looger\log.txt", text);
        }
    }
}

这是我的服务接口

[ServiceContract]
public interface ILongRunner
{
    [OperationContract]
    void LongRunnerMethod();
}

最后是网络配置

    <?xml version="1.0"?>
    <configuration>
  <appSettings>
    <add key="val" value="600"/>
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="ORServiceBehavior" name="PTS.LongRunner">
        <endpoint binding="netTcpBinding" bindingConfiguration="DefaultNetTcpBinding" name="ORServiceTCPEndPoint"
                contract="PTS.ILongRunner" address="" >
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" contract="IMetadataExchange"/>
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:8079/___/_________.svc" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <bindings>
      <netTcpBinding>
        <binding name="DefaultNetTcpBinding" maxBufferSize="2147483647" maxConnections="10" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" >
          <reliableSession enabled="false" ordered="false" inactivityTimeout="00:10:00"/>
          <readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="32" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647"/>
          <security mode="Message">
            <transport clientCredentialType="Windows"/>
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ORServiceBehavior">
          <serviceMetadata httpGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceThrottling maxConcurrentCalls="200" maxConcurrentSessions="200" maxConcurrentInstances="200" />
          <dataContractSerializer maxItemsInObjectGraph="50000" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

  <system.webServer>
   <modules runAllManagedModulesForAllRequests="true"/>
   </system.webServer>

   </configuration>
4

1 回答 1

0

WCF 有很多超时...

  • 绑定超时:SendTimeout、OpenTimeout 和 CloseTimeout(默认 1 分钟)、ReceiveTimeout(默认 10 分钟)
  • 服务主机:OpenTimeout(默认1分钟)、CloseTimeout(默认10秒)
  • 可靠会话不活动超时:默认 10 分钟
  • 任何继承 ConnectionOrientedTransportBindingElement 例如 NetTcp: ChannelInitializationTimeout 默认 30 秒

我的猜测是你得到了“未处理的异常:System.TimeoutException:打开操作没有在分配的超时时间内完成......” - 这意味着代理已超时等待服务发送响应。

“这是怎么发生的?[即使您有“操作未完成”超时,该服务也会继续记录]”

ServiceHost 已分配一个线程来处理对 LongRunnerMethod 方法的请求。该线程将完成对请求的处理,直到发生灾难性事件(例如进程主机关闭)或从方法内部引发异常。

“有没有办法阻止[中断处理方法调用的线程]?”

您需要从外部源获取信号,您需要在每次第 n 次迭代时检查以查看是否应该继续。您需要以唯一 id(票证)的形式从客户端将某些内容传递给第一个方法,然后将此 id 与 Cancel 方法一起使用,该方法将为 LongRunnerMethod 设置信号以中止处理。

这是一个使用 msmq 的示例,它允许真正的单向调用:

服务器

 class Program
    {
        static void Main(string[] args)
        {
            var baseAddress = "net.msmq://localhost/private/";
            var address = "ILongRunner";

            var host = new ServiceHost(typeof (LongRunner), new Uri(baseAddress));
            var binding = new NetMsmqBinding(NetMsmqSecurityMode.None);
            var se = host.AddServiceEndpoint(typeof (ILongRunner), binding, address );
            se.VerifyQueue(); //comes from IDesign ServiceModelEx http://www.idesign.net/Downloads/GetDownload/1887
            host.Open();

            Console.WriteLine("Press any key to stop");
            Console.ReadLine();
        }
    }

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
    public class LongRunner : ILongRunner
    {
        private static readonly ConcurrentBag<Guid> Cancelations = new ConcurrentBag<Guid>();

        public void CancelLongRunnerMethod(Guid id)
        {
            if (Cancelations.All(z => z != id))
                Cancelations.Add(id);
        }

        public void LongRunnerMethod(Guid id)
        {
            int counter = 300000;

            //concurrent write will require different technique
            var file = string.Format(@"D:\log.{0}.txt", id);

            for (int i = 0; true; i++)
            {
                //check every 5th call
                if (i % 5 == 0)
                {
                    if (Cancelations.Any(z => z == id))
                    {
                        Guid cancelationId;

                        Cancelations.TryTake(out cancelationId);

                        if (cancelationId == id)
                        {
                            Debug.WriteLine(string.Format("LongRunnerMethod {0} canceled", id));
                            return;
                        }
                    }
                }

                Thread.Sleep(10);
                Console.WriteLine("at " + i);
                if (i >= counter)
                    break;
                var text = string.Format("{0} {1} \n", i.ToString(), DateTime.Now.ToString());
                File.AppendAllText(file, text);
            }

            Console.WriteLine("Complete " + id);
        }


    }

    [ServiceContract()]
    public interface ILongRunner
    {
         [OperationContract(IsOneWay = true)]
        void CancelLongRunnerMethod(Guid id);

        [OperationContract(IsOneWay = true)]
        void LongRunnerMethod(Guid id);
    }

客户

class Program
    {
        static void Main(string[] args)
        {
            var baseAddress = "net.msmq://localhost/private/";
            var address = "ILongRunner";


            var binding = new NetMsmqBinding(NetMsmqSecurityMode.None);
            var c1 = new ChannelFactory<ILongRunner>(binding, new EndpointAddress(new Uri(baseAddress + address)));
            var proxy = c1.CreateChannel();
            var request1 = Guid.NewGuid();
            proxy.LongRunnerMethod(request1);
            var co = c1 as ICommunicationObject;
            co.Close();


            var c2 = ChannelFactory<ILongRunner>.CreateChannel(binding, new EndpointAddress(new Uri(baseAddress + address)));
            var request2 = Guid.NewGuid();
            c2.LongRunnerMethod(request2);

            Thread.Sleep(5000);
            var c3 = new ChannelFactory<ILongRunner>(binding, new EndpointAddress(new Uri(baseAddress + address)));
            var proxy2 = c3.CreateChannel();
            proxy2.CancelLongRunnerMethod(request1);
            var co2 = c3 as ICommunicationObject;
            co2.Close();
        }
    }
于 2013-06-26T08:57:20.063 回答