简体   繁体   中英

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).

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). 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:

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.

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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