wcf wsdualhttpbinding超时问题

Posted

技术标签:

【中文标题】wcf wsdualhttpbinding超时问题【英文标题】:wcf wsdualhttpbinding timeout problem 【发布时间】:2011-09-07 04:18:13 【问题描述】:

请帮帮我!!!

我正在尝试构建一个使用回调合同的应用程序。我的应用程序在同一台机器上的客户端和服务器都可以正常工作,但是当我尝试从其他机器访问服务时出现异常超时(操作 din未在分配的超时时间内完成)。客户端读取一些值从服务器上的数据库中抛出服务。我不知道我的错误在哪里。我试图将客户端放在虚拟机中,并且服务(和数据库)在真机上。

这是我的服务器配置文件:

            <binding name="TrainService" closeTimeout="00:02:00" openTimeout="00:02:00"
                receiveTimeout="00:10:00" sendTimeout="00:02:00" bypassProxyOnLocal="false"
                transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <reliableSession ordered="true" inactivityTimeout="00:10:00" />
                <security mode="None">
                    <message clientCredentialType="None" negotiateServiceCredential="true"
                        algorithmSuite="Default" />
                </security>
            </binding>
        </wsDualHttpBinding>
        <wsHttpBinding>
            <binding name="WSHttpBinding_ITrainService" closeTimeout="00:02:00"
                openTimeout="00:02:00" receiveTimeout="00:10:00" sendTimeout="00:02:00"
                bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                allowCookies="false">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <reliableSession ordered="true" inactivityTimeout="00:10:00"
                    enabled="false" />
                <security mode="None">
                    <transport clientCredentialType="None" proxyCredentialType="None"
                        realm="" />
                    <message clientCredentialType="None" negotiateServiceCredential="true"
                        algorithmSuite="Default" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
  <client>
    <endpoint address="http://localhost:8732/Design_Time_Addresses/WCFandEFService/TrainService/"
      binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ITrainService"
      contract="TrainServiceRef.ITrainService" name="WSHttpBinding_ITrainService">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="net.tcp://localhost:8080/TcpService" binding="netTcpBinding"
      contract="TrainServiceRef.ITrainService" name="NetTcpBinding_ITrainService" />
    <endpoint address="http://localhost:8082/InterlockingService/Host/line"
      binding="wsDualHttpBinding" bindingConfiguration="LineService"
      contract="InterlockingServiceReference.ILineService" name="LineService">
      <identity>
        <userPrincipalName value="Romina-PC\Romina" />
      </identity>
    </endpoint>

    <endpoint address="http://localhost:8082/InterlockingService/Host/trains"
      binding="wsDualHttpBinding" bindingConfiguration="TrainService"
      contract="InterlockingServiceReference.ITrainService" name="TrainService">
      <identity>
        <userPrincipalName value="Romina-PC\Romina" />
      </identity>
    </endpoint>

  </client>

</system.serviceModel>

我的客户端配置文件:

-->

            <binding name="TrainService" closeTimeout="00:01:00" openTimeout="00:01:00"
                receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
                transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                maxBufferPoolSize="52428800" maxReceivedMessageSize="6553600"
                messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="1638400"
                    maxBytesPerRead="4096" maxNameTableCharCount="1638400" />
                <reliableSession ordered="true" inactivityTimeout="00:10:00" />
                <security mode="None">
                    <!--<message clientCredentialType="None" negotiateServiceCredential="true"
                        algorithmSuite="Default" />-->
                </security>
            </binding>
        </wsDualHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://localhost:8082/InterlockingService/Host/line"
            binding="wsDualHttpBinding" bindingConfiguration="LineService"
            contract="InterlockingServiceRef.ILineService" name="LineService">
            <identity>
                <userPrincipalName value="Romina-PC\Romina" />
            </identity>
        </endpoint>

        <endpoint address="http://localhost:8082/InterlockingService/Host/trains"
            binding="wsDualHttpBinding" bindingConfiguration="TrainService"
            contract="InterlockingServiceRef.ITrainService" name="TrainService">
            <identity>
                <userPrincipalName value="Romina-PC\Romina" />
            </identity>
        </endpoint>
    </client>
</system.serviceModel>

谢谢。

这些是合约:公共接口 ITrainServiceCallBack [OperationContract (IsOneWay=true)] void OnTrainChangeState(TrainData train);

//[ServiceContract(Name = "LineService", CallbackContract = typeof(ILineServiceCallBack))]
[ServiceContract(CallbackContract = typeof(ITrainServiceCallBack))]
public interface ITrainService

    [OperationContract]
    TrainData GetTrainData(string trainName);

    [OperationContract]
    bool ChangeTrainState_bool(ref TrainData train);

    [OperationContract]
    void ChangeTrainState(ref Trains_Detail train);
    [OperationContract]
    bool SubscribeToTrainChangeEvent();

    [OperationContract]
    bool UnSubscribeFromTrainChangeEvent();
    [OperationContract]
    TrainData TranslateTrainEntityToTrainData(Trains_Detail trainEntity);

    [OperationContract]
    IEnumerable<Trains_Detail> GetTrains();

    [OperationContract]
    IEnumerable<Trains_Detail> GetTrains_ByStation(int Statie_plecare, int Statie_sosire);

方法实现:

使用系统; 使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Runtime.Serialization; 使用 System.ServiceModel; 使用 System.Text; 使用 System.Data;

命名空间 WCFandEFService // 注意:您可以使用“重构”菜单上的“重命名”命令同时更改代码和配置文件中的类名“ProductService”。 //[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]

public partial class InterlockingService : ITrainService


    static List<ITrainServiceCallBack> subscribers_train = new List<ITrainServiceCallBack>();


    public bool TrainExists(string nrTren, InterlockingEntities database)
    
        // Check to see whether the specified product exists in the database
        int numTrain = (from t in database.Trains_Details
                       where string.Equals(t.Nr_tren, nrTren)
                       select t).Count();

        return numTrain > 0;

    


    public TrainData TranslateTrainEntityToTrainData(Trains_Detail trainEntity)
    
        TrainData train = new TrainData();

        train.nrTren=trainEntity.Nr_tren;
        train.ora_Plecare= trainEntity.Ora_plecare;
        train.ora_Sosire=trainEntity.Ora_sosire;
        train.statie_Plecare=trainEntity.Statie_plecare;
        train.statie_Sosire=trainEntity.Statie_sosire;
        train.rang=trainEntity.Rang;
        train.observatii=trainEntity.Observatii;            
        train.RowVersion=trainEntity.RowVersion;

        return train;

    

    #region ILineService Members



    public IEnumerable<Trains_Detail> GetTrains()
    
        InterlockingEntities context = new InterlockingEntities();


        IEnumerable<Trains_Detail> result =
                (from t in context.Trains_Details
                 //where l.Station == station
                 select t);
        return result;

    

     public IEnumerable<Trains_Detail> GetTrains_ByStation(int Statie_plecare,int Statie_sosire)
    
        InterlockingEntities context = new InterlockingEntities();

        IEnumerable<Trains_Detail> result =
                (from t in context.Trains_Details
                 where t.Statie_plecare==Statie_plecare && t.Statie_sosire==Statie_sosire
                 select t);
        return result;

    



    public TrainData GetTrainData(string trainNr)
    
        InterlockingEntities context = new InterlockingEntities();
        Trains_Detail trainInDB =
             (from t
              in context.Trains_Details
              where String.Compare(t.Nr_tren, trainNr) == 0
              select t).FirstOrDefault();
        if (trainInDB == null)
        

            throw new Exception("No line cu numele " + trainInDB.Nr_tren);

        

        context.Detach(trainInDB);
        return TranslateTrainEntityToTrainData(trainInDB);
    

    public bool ChangeTrainState_bool(ref TrainData train)
    
        InterlockingEntities context = new InterlockingEntities();
        String trainName = train.nrTren;
        //int lineStation = line.station;
        Trains_Detail trainInDB =
             (from t
              in context.Trains_Details
              where String.Compare(t.Nr_tren, trainName) == 0
              select t).FirstOrDefault();

        if (trainInDB == null)
        
            throw new Exception("No train cu numele " + trainInDB.Nr_tren);
        

        context.Detach(trainInDB);


        trainInDB.Nr_tren = train.nrTren;
        trainInDB.Ora_plecare=train.ora_Plecare;
        trainInDB.Ora_sosire=train.ora_Sosire;
        trainInDB.Statie_plecare=train.statie_Plecare;
        trainInDB.Statie_sosire=train.statie_Sosire;
        trainInDB.Rang=train.rang;

        trainInDB.RowVersion = train.RowVersion;

        context.Attach(trainInDB);

        context.ObjectStateManager.ChangeObjectState(trainInDB, System.Data.EntityState.Modified);
        context.SaveChanges();
        train.RowVersion = trainInDB.RowVersion;
        context.Dispose();
        raiseTrainChangeState(TranslateTrainEntityToTrainData(trainInDB));
        return true;
    


    public void ChangeTrainState(ref Trains_Detail train)
    
        using (var context = new InterlockingEntities())
        
            context.Attach(train);
            context.ObjectStateManager.ChangeObjectState(train, EntityState.Modified);
            context.SaveChanges();
        
    
   


    public bool SubscribeToTrainChangeEvent()
    
        try
        
            ITrainServiceCallBack callback = OperationContext.Current.GetCallbackChannel<ITrainServiceCallBack>();

            if (!subscribers_train.Contains(callback))
            
                subscribers_train.Add(callback);
            
            return true;
        
        catch (Exception)
        

            return false;
        


    

    public bool UnSubscribeFromTrainChangeEvent()
    
        try
        
            ITrainServiceCallBack callback = OperationContext.Current.GetCallbackChannel<ITrainServiceCallBack>();
            subscribers_train.Remove(callback);

            return true;
        
        catch (Exception)
        
            return false;
        
    

    #endregion




    private void raiseTrainChangeState(TrainData train)
    
        subscribers_train.AsParallel().ForAll(callback =>
        
            if (((ICommunicationObject)callback).State == CommunicationState.Opened)
            
                callback.OnTrainChangeState(train);

            
            else
            
                subscribers_train.Remove(callback);
            
        );
    







【问题讨论】:

你愿意分享合约结构和操作的实现吗? 请参考我回答中的编辑部分。检查它是否有帮助。 【参考方案1】:

回调合同中的操作合同应标记为 IsOneWay = true,并且应返回无效 - 不是服务中的所有操作合同。

另外,我在 NetTcpBinding 上使用双工合同时遇到了类似的问题。我通过在代理上设置 OperationTimeout 值(在我的情况下为 5 分钟)解决了这个问题。在创建通道时,我通过将通道转换为客户端上的 IContextChannel 接口以编程方式设置它。您应该可以在客户端配置文件中执行相同的操作。

我的代码:

((IContextChannel)myChannel).OperationTimeout = new Timespan(0, 5, 0);

【讨论】:

我已经修改了您的所有建议,但它不起作用。同样的错误消息(10 分钟 -> 操作在分配的超时时间内未完成)。其他建议?感谢回复 WSDualHttpBinding的回调合约上的操作不需要需要标记为单向。【参考方案2】:

您在客户端和服务器中的端点地址指定“localhost”作为机器名称。如果它们在不同的机器上,客户端将无法与服务对话。尝试将其更改为服务器所在的实际机器名称。

更新:这是一个 WSDualHttpBinding 示例,它在合约和回调合约上都使用非单向操作。 WSDualHttpBinding 要求回调合约上的操作是一种方式。 PollingDuplexHttpBinding(用于 Silverlight)可以,但那是另一回事了。

using System;
using System.IO;
using System.Reflection;
using System.ServiceModel;
using System.Threading;

public class ***_6216605_751090

    [ServiceContract(CallbackContract = typeof(ITestCallback))]
    public interface ITest
    
        [OperationContract]
        int Add(int x, int y);
        [OperationContract]
        void CallMe(int numberOfTimes);
    
    [ServiceContract]
    public interface ITestCallback
    
        [OperationContract]
        string Hello(string name);
    
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class Service : ITest
    
        public int Add(int x, int y)
        
            Console.WriteLine("In a Request/Reply operation on server: 0 + 1", x, y);
            return x + y;
        

        public void CallMe(int numberOfTimes)
        
            Console.WriteLine("In another request/reply operation on server, which will call the client.");
            ITestCallback callback = OperationContext.Current.GetCallbackChannel<ITestCallback>();
            ThreadPool.QueueUserWorkItem(delegate
            
                for (int i = 0; i < numberOfTimes; i++)
                
                    Console.WriteLine("Received from client: 0", callback.Hello("Server"));
                
            );
        
    
    [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class ClientCallback : ITestCallback
    
        static int count = 0;
        public string Hello(string name)
        
            Console.WriteLine("In a client operation, name = 0", name);
            return string.Format("[0] Hello, 1", ++count, name);
        
    
    static void PrintUsage()
    
        string programName = Path.GetFileName(Assembly.GetEntryAssembly().CodeBase);
        Console.WriteLine("Usage: 0 <options>", programName);
        Console.WriteLine("Examples:");
        Console.WriteLine("  Starting the server: 0 -server", programName);
        Console.WriteLine("  Starting the client: 0 -client <serverMachineName>", programName);
    
    public static void Main(string[] args)
    
        if (args.Length < 1)
        
            PrintUsage();
            return;
        

        if (args[0].Equals("-server", StringComparison.OrdinalIgnoreCase))
        
            string serviceAddress = "http://" + Environment.MachineName + ":8000/Service";
            ServiceHost host = new ServiceHost(typeof(Service), new Uri(serviceAddress));
            host.AddServiceEndpoint(typeof(ITest), new WSDualHttpBinding(WSDualHttpSecurityMode.None), "");
            host.Open();
            Console.WriteLine("Host opened, press ENTER to close");
            Console.ReadLine();
            host.Close();
        
        else if (args.Length > 1 && args[0].Equals("-client", StringComparison.OrdinalIgnoreCase))
        
            string serviceAddress = "http://" + args[1] + ":8000/Service";
            ClientCallback clientCallback = new ClientCallback();
            DuplexChannelFactory<ITest> factory = new DuplexChannelFactory<ITest>(
                clientCallback,
                new WSDualHttpBinding(WSDualHttpSecurityMode.None),
                new EndpointAddress(serviceAddress));
            ITest proxy = factory.CreateChannel();
            Console.WriteLine("Simple Request/Reply: 0", proxy.Add(3, 4));
            Console.WriteLine("Now calling an operation on the server which will cause callbacks");
            proxy.CallMe(10);
            Console.WriteLine("Press ENTER to close");
            Console.ReadLine();
        
        else
        
            PrintUsage();
        
    

【讨论】:

嗨@carlosfigueira,您介意展示一个示例,说明 WSHttpBinding 在何处以及如何支持请求/响应类型的通信? 我不确定如何将请求/响应类型的消息交换计为双工。类似对话请参考social.msdn.microsoft.com/Forums/en-US/wcf/thread/…。 通过双工,这意味着服务可以随时向客户端发送请求——即客户端不需要做诸如轮询服务器以获取消息之类的事情。 WSDualHttpBinding 实际上在客户端创建了一个服务器,在最初的握手中,客户端向服务器发送它将监听消息的地址。 我绝对同意这个定义。我的论点是您在一个频道中发送请求并在不同的频道中收听它。这就是 WSHttpBinding 创建 OneWayBindingElement 的原因。当然,您会在不同的渠道收到回复。但它不能被认为是请求/响应 MEP 的权利。它是双工的。 嗯,我已经尝试改变,但没有结果。还有其他建议吗?谢谢【参考方案3】:

检查您是否已将运营合同标记为一种方式。通常在双重 http 绑定中出现超时,人们未能将合同标记为一种方式。

[OperationContract(IsOneWay = true)]

编辑

请在服务合同的行为中加入以下行。

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] 

请考虑发布您的服务合同结构和运营合同的实施,以供我们参考。

【讨论】:

我所有的操作合同?因为我把所有的 isoneway=true 都放到了下面的错误:System.InvalidOperationException: 用 IsOneWay=true 标记的操作不能声明输出参数、引用参数或返回值。 wsDualHttpBinding 是双工通信绑定。本质上,它会调用一个通道并在另一个通道中接收。因此,当您拨打电话时,您应该期望您只是在拨打仅转接电话(回复将在不同的频道中收到),并且不会期望任何输出作为您的呼叫的响应。 WSDualHttpBinding 确实支持非单向(即请求/回复)操作,您不需要将操作设置为单向。 你可以参考saravananarumugam.wordpress.com/2011/04/08/…这个绑定和双工通道连接的想法。 无论您要在 WSDualHttpBinding 中使用哪个调用,都必须是单向操作。请求/响应是与双工不同的消息交换模式。

以上是关于wcf wsdualhttpbinding超时问题的主要内容,如果未能解决你的问题,请参考以下文章

WCF Duplex 是一个不错的选择吗?

WCF传byte[]的方法

wcf双工通讯

识别 WCF 服务中的客户端

WCF 自定义绑定 - 服务响应,客户端不响应

WCF 在服务器上的服务之间进行通信