简体   繁体   English

实现双工时WCF中的超时异常

[英]TimeOut exception in WCF while implementing duplex

My service contract and callback contracts look like this: 我的服务合同和回调合同如下所示:

[ServiceContract(CallbackContract = typeof(IWebshopCallback))]
interface IWebshop
{
    [OperationContract]
    string GetWebshopName ();
    [OperationContract]
    string GetProductInfo (Item i);
    [OperationContract]
    List<Item> GetProductList ();
    [OperationContract]
    bool BuyProduct (string i);
    [OperationContract]
    void ConnectNewClient ();
}

[ServiceContract]
interface IWebshopCallback
{
    [OperationContract]
    void NewClientConnected (int totalNrOfConnectedClients);
}

My service: 我的服务:

[ServiceBehavior (InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
class WebshopService : IWebshop
{
  ...
}

Inside of the service I have a method which calls the other method on a client's side: 在服务内部,我有一个方法可以在客户端调用另一个方法:

public void ConnectNewClient ()
    {
        totalNumber++;
        OperationContext.Current.GetCallbackChannel<IWebshopCallback> ().NewClientConnected (totalNumber);
    }

And on the client's side I have a form which derives from IWebshopCallback and has a method NewClientConnected(int a). 在客户端,我有一个从IWebshopCallback派生并具有方法NewClientConnected(int a)的表单。

The problem is that when I try to run my code I run into this exception: 问题是,当我尝试运行代码时,遇到了以下异常:

This request operation sent to http://localhost:4000/IWebshopContract did not receive a reply within the configured timeout (00:00:59.9989895). 发送到http:// localhost:4000 / IWebshopContract的此请求操作在配置的超时时间(00:00:59.9989895)内未收到答复。 The time allotted to this operation may have been a portion of a longer timeout. 分配给该操作的时间可能是较长超时的一部分。

What's more strange, though, is that if I continue the work of my app I see that this function worked. 但是,更奇怪的是,如果我继续应用程序的工作,我会看到此功能有效。

What could be causing all of it? 是什么原因造成的呢?

On the server side when you call on a function you need to use Task.Run(), so you should have it like this: 在服务器端,当您调用一个函数时,您需要使用Task.Run(),因此您应该像这样:

var callback = OperationContext.Current.GetCallbackChannel<IWebshopCallback> ();
Task.Run (() => callback.NewClientConnected(totalNumber));

and not like this: 而不是这样:

OperationContext.Current.GetCallbackChannel<IWebshopCallback> ().NewClientConnected ();

In general, the behavior we except with the duplex is that the client returns immediately after invoking the service, and the information sent back by the server is transmitted through the callback contract. 通常,除双工模式外,我们的行为是客户端在调用服务后立即返回,并且服务器发送回的信息通过回调合同进行传输。 in this working mode, we turn both the service contract and the callback contract into one-way communication. 在这种工作模式下,我们将服务合同和回调合同都转换为单向通信。

[OperationContract(Action = "post_num", IsOneWay = true)]
void PostNumber(int n);

I have made a demo, wish it is useful to you. 我做了一个演示,希望对您有用。

Server-side. 服务器端。

class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost sh=new ServiceHost(typeof(MyService)))
            {
                ServiceMetadataBehavior smb;
                smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
                if (smb==null)
                {
                    smb = new ServiceMetadataBehavior()
                    {
                        HttpGetEnabled = true
                    };
                    sh.Description.Behaviors.Add(smb);
                }
                sh.Open();
                Console.WriteLine("Service is ready");

                Console.ReadKey();
                sh.Close();
            }
        }
    }
    [ServiceContract(Namespace ="mydomain",Name = "demo", ConfigurationName = "isv", CallbackContract = typeof(ICallback))]
    public interface IDemo
    {
        [OperationContract(Action = "post_num", IsOneWay = true)]
        void PostNumber(int n);
    }
    [ServiceContract]
    public interface ICallback
    {
        [OperationContract(Action = "report", IsOneWay = true)]
        void Report(double progress);
    }

    [ServiceBehavior(ConfigurationName ="sv")]
    public class MyService : IDemo
    {
        public void PostNumber(int n)
        {
            ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
            for (int i = 0; i <=n; i++)
            {
                Task.Delay(500).Wait();
                double p = Convert.ToDouble(i) / Convert.ToDouble(n);
                callback.Report(p);
            }
        }
    }

Server-config 服务器配置

  <system.serviceModel>
    <services>
      <service name="sv">
        <endpoint address="http://localhost:3333" binding="wsDualHttpBinding" contract="isv"/>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:3333"/>
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>

Client-side. 客户端。

class Program
{
    static void Main(string[] args)
    {
        DuplexChannelFactory<IDemo> factory = new DuplexChannelFactory<IDemo>(new CallbackHandler(), "test_ep");
        IDemo channel = factory.CreateChannel();
        Console.WriteLine("Start to Call");
        channel.PostNumber(15);
        Console.WriteLine("Calling is done");
        Console.ReadLine();
    }
}
[ServiceContract(Namespace ="mydomain",Name = "demo", ConfigurationName = "isv", CallbackContract = typeof(ICallback))]
public interface IDemo
{
    [OperationContract(Action = "post_num",IsOneWay =true)]
    void PostNumber(int n);
}
[ServiceContract]
public interface ICallback
{
    [OperationContract(Action = "report",IsOneWay =true)]
    void Report(double progress);
}
public class CallbackHandler : ICallback
{
    public void Report(double progress)
    {
        Console.WriteLine("{0:p0}", progress);
    }
}

Client-config 客户端配置

  <system.serviceModel>
    <client>
      <endpoint name="test_ep" address="http://localhost:3333" binding="wsDualHttpBinding" contract="isv"/>
    </client>
  </system.serviceModel>

Result. 结果。

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM