Z
Z
zergon3212017-11-20 22:35:03
.NET
zergon321, 2017-11-20 22:35:03

Why doesn't duplex WCF work?

Wrote a WCF service and client . The bottom line is this: the client calls the Register() method on the server , which adds the client's channel to the clientChannels list so that you can then use it to call client methods. As soon as the client sends a message using the SendMessage() method , the server on each channel in the list calls the ShowMessage() method , which causes the client to print the parameter specified by the server to the console. The WCF service is hosted by a console application. All clients share the same service. In short, ServiceBehavior.InstanceContextMode = InstanceContextMode.Single , ServiceContract.SessionMode = SessionMode.Allowed, the binding is WSDualHttpBinding . The service starts and seems to work fine, but the client, when calling the Register() method, blocks and, after some timeout, throws an EndPointNotFoundException: No endpoint was listening on localhost:8733/Design_Time_Addresses/WCFDuplexServ... that could accept the message. Where is the mistake?

Contracts
using System.ServiceModel;

namespace WCFDuplexServiceTest
{
    // Server methods.
    [ServiceContract(SessionMode = SessionMode.Allowed, CallbackContract = typeof(IClientCallback))]
    public interface IMessageService
    {
        [OperationContract(IsOneWay = true)]
        void Register();

        [OperationContract(IsOneWay = true)]
        void SendMessage(string message);
    }

    // Client methods.
    public interface IClientCallback
    {
        [OperationContract(IsOneWay = true)]
        void ShowMessage(string message);
    }
}

Service Contract Implementation
using System.Collections.Generic;
using System.ServiceModel;

namespace WCFDuplexServiceTest
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class MessageService : IMessageService
    {
        private List<IClientCallback> clientChannels = new List<IClientCallback>();
        private int numberOfUsers = 0;

        public MessageService() { }

        public void Register()
        {
            clientChannels.Add(OperationContext.Current.GetCallbackChannel<IClientCallback>());
            numberOfUsers++;
        }

        public void SendMessage(string message)
        {
            foreach (var channel in clientChannels)
                channel.ShowMessage(message + string.Format("/nPeople in server: {0}", numberOfUsers));
        }
    }
}

Host
using System;
using WCFDuplexServiceTest;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace WCFDuplexServiceTestHost
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost serviceHost = new ServiceHost(typeof(MessageService), new Uri("http://localhost:8000/WCFDuplexServiceTest/"));

            try
            {
                serviceHost.AddServiceEndpoint(typeof(IMessageService), new WSDualHttpBinding(), "MessageService");
                serviceHost.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true });

                serviceHost.Open();
                Console.WriteLine("Service started; press ENTER to terminate.");
                Console.ReadLine();
                serviceHost.Close();
            }
            catch (CommunicationException ce)
            {
                Console.WriteLine("Something wrong: {0}", ce.Message);
                serviceHost.Abort();
            }
        }
    }
}

Customer
using System;
using WCFTestServiceClient.MessageService;
using System.ServiceModel;

namespace WCFTestServiceClient
{
    class Program
    {
        static void Main(string[] args)
        {
            MessageServiceClient client = new MessageServiceClient(new InstanceContext(new MessageServiceHandler()), "WSDualHttpBinding_IMessageService");

            client.Register();
            client.SendMessage("How many are people online?");
        }
    }

    internal class MessageServiceHandler : IMessageServiceCallback
    {
        public void ShowMessage(string message)
        {
            Console.WriteLine("Server response: " + message);
        }
    }
}

Service config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <!-- Во время развертывания проекта библиотеки служб содержимое файла конфигурации необходимо добавить к файлу 
  app.config на узле. Файлы конфигурации для библиотек не поддерживаются System.Configuration. -->
  <system.serviceModel>
    <services>
      <service name="WCFDuplexServiceTest.MessageService">
        <endpoint address="" binding="wsDualHttpBinding" contract="WCFDuplexServiceTest.IMessageService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8733/Design_Time_Addresses/WCFDuplexServiceTest/Service1/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!--Чтобы избежать раскрытия метаданных, 
          до развертывания задайте следующим параметрам значение "false".-->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <!-- Чтобы получить сведения об исключениях в ошибках для отладки, 
          установите ниже значение TRUE. Перед развертыванием установите значение FALSE, 
           чтобы избежать разглашения сведений об исключении -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

</configuration>

Client config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <system.serviceModel>
        <bindings>
            <wsDualHttpBinding>
                <binding name="WSDualHttpBinding_IMessageService" 
                         clientBaseAddress="http://localhost:8000/WCFTestServiceClient/" />
            </wsDualHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8733/Design_Time_Addresses/WCFDuplexServiceTest/Service1/"
                binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_IMessageService"
                contract="MessageService.IMessageService" name="WSDualHttpBinding_IMessageService">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Alexander Yudakov, 2017-11-20
@AlexanderYudakov

The firewall may have blocked listening to:
localhost:8733/Design_Time_Addresses/WCFDuplexServ...

P
Peter, 2017-11-20
@petermzg

Write more clearly on the server.

var serviceHost = new ServiceHost(typeof(MessageService));
var uri = new Uri("http://localhost:8000/WCFDuplexServiceTest/MessageService")
serviceHost.AddServiceEndpoint(typeof(IMessageService), new WSDualHttpBinding(), uri);

And then why "Service Config" if you have already launched everything you need in the code?

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question