zergon321
@zergon321

Почему не работает дуплексный WCF?

Написал службу и клиент WCF. Суть такова: клиент вызывает на сервере метод Register(), который добавляет канал клиента в список clientChannels, чтобы потом с его помощью можно было вызывать методы клиента. Как только клиент посылает сообщение методом SendMessage(), сервер на каждом канале из списка вызывает метод ShowMessage(), заставляющий клиента вывести в консоль параметр, заданный сервером. Хостингом службы WCF является консольное приложение. Все клиенты разделяют между собой один и тот же сервис. Если вкратце, то ServiceBehavior.InstanceContextMode = InstanceContextMode.Single, ServiceContract.SessionMode = SessionMode.Allowed, привязка - WSDualHttpBinding. Служба запускается и вроде работает нормально, а вот клиент при вызове методf Register() блокируется и после некоторого времени ожидания выбрасывает EndPointNotFoundException: Прослушивание на localhost:8733/Design_Time_Addresses/WCFDuplexServ... не выполняла ни одна конечная точка, которая могла бы принять сообщение. В чем ошибка?

Контракты
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);
    }
}

Реализация контракта сервиса
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));
        }
    }
}

Хост
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();
            }
        }
    }
}

Клиент
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);
        }
    }
}

Конфиг сервиса
<?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>

Конфиг клиента
<?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>

  • Вопрос задан
  • 524 просмотра
Пригласить эксперта
Ответы на вопрос 2
AlexanderYudakov
@AlexanderYudakov
C#, 1С, Android, TypeScript
Брандмауэр мог заблокировать прослушивание:
localhost:8733/Design_Time_Addresses/WCFDuplexServ...
Ответ написан
Комментировать
petermzg
@petermzg
Самый лучший программист
Напишите более понятнее на сервере.
var serviceHost = new ServiceHost(typeof(MessageService));
var uri = new Uri("http://localhost:8000/WCFDuplexServiceTest/MessageService")
serviceHost.AddServiceEndpoint(typeof(IMessageService), new WSDualHttpBinding(), uri);

И тогда зачем "Конфиг сервиса", если в коде вы все нужное уже запустили?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы