Как программно добавить возможность обнаружения к службе и клиенту WCF

В этом разделе объясняется, как сделать службу Windows Communication Foundation (WCF) обнаруживаемой. Он основан на примере самостоятельного узла .

Настройка образца службы существующего резидентного размещения для обнаружения

  1. Откройте решение самообслуживания в Visual Studio 2012. Образец находится в каталоге TechnologySamples\Basic\Service\Hosting\SelfHost.

  2. Добавьте ссылку на проект службы System.ServiceModel.Discovery.dll. Вы можете увидеть сообщение об ошибке с фразой "Система. для ServiceModel.Discovery.dll или одной из зависимостей требуется более поздняя версия платформа .NET Framework, чем указанная в проекте ..." Если вы видите это сообщение, щелкните проект правой кнопкой мыши в Обозреватель решений и выберите "Свойства". В окне "Свойства проекта" убедитесь, что целевая платформа платформа .NET Framework 4.6.1.

  3. Откройте файл Service.cs и добавьте следующую инструкцию using.

    using System.ServiceModel.Discovery;
    
  4. В методе Main() в инструкции using добавьте экземпляр ServiceDiscoveryBehavior в узел службы.

    public static void Main()
    {
        // Create a ServiceHost for the CalculatorService type.
        using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService)))
        {
            // Add a ServiceDiscoveryBehavior
            serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
    
            // ...
        }
    }
    

    ServiceDiscoveryBehavior указывает, что служба, к которой оно применяется, доступна для обнаружения.

  5. Добавьте UdpDiscoveryEndpoint в узел службы сразу после кода, добавляющего ServiceDiscoveryBehavior.

    // Add ServiceDiscoveryBehavior
    serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
    
    // Add a UdpDiscoveryEndpoint
    serviceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());
    

    Этот код указывает, что сообщения об обнаружении должны отправляться стандартной конечной точке обнаружения UDP.

Создание клиентского приложения, использующего обнаружение при вызове службы

  1. Добавьте в решение новое консольное приложение с именем DiscoveryClientApp.

  2. Добавьте ссылку на сборки System.ServiceModel.dll и System.ServiceModel.Discovery.dll.

  3. Скопируйте файлы GeneratedClient.cs и App.config из существующего проекта клиента в новый проект DiscoveryClientApp. Для этого щелкните правой кнопкой мыши файлы в Обозреватель решений, выберите "Копировать", а затем выберите проект DiscoveryClientApp, щелкните правой кнопкой мыши и выберите "Вставить".

  4. Откройте Program.cs.

  5. Добавьте следующие операторы using.

    using System.ServiceModel;
    using System.ServiceModel.Discovery;
    using Microsoft.ServiceModel.Samples;
    
  6. Добавьте статический метод с именем FindCalculatorServiceAddress() в класс Program.

    static EndpointAddress FindCalculatorServiceAddress()
    {
    }
    

    Этот метод использует обнаружение для поиска службы CalculatorService.

  7. Внутри метода FindCalculatorServiceAddress создайте новый экземпляр DiscoveryClient, передав UdpDiscoveryEndpoint в конструктор.

    static EndpointAddress FindCalculatorServiceAddress()
    {
        // Create DiscoveryClient
        DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
    }
    

    Это сообщает WCF, что DiscoveryClient класс должен использовать стандартную конечную точку обнаружения UDP для отправки и получения сообщений об обнаружении.

  8. В следующей строке вызовите метод Find и укажите экземпляр FindCriteria, содержащий контракт службы, который необходимо найти. В данном случае укажите ICalculator.

    // Find ICalculatorService endpoints
    FindResponse findResponse = discoveryClient.Find(new FindCriteria(typeof(ICalculator)));
    
  9. После вызова Find проверьте наличие хотя бы одной соответствующей службы и верните EndpointAddress первой из найденных. В противном случае верните значение null.

    if (findResponse.Endpoints.Count > 0)
    {
        return findResponse.Endpoints[0].Address;
    }
    else
    {
        return null;
    }
    
  10. Добавьте статический метод с именем InvokeCalculatorService в класс Program.

    static void InvokeCalculatorService(EndpointAddress endpointAddress)
    {
    }
    

    Этот метод использует для вызова службы калькулятора адрес конечной точки, возвращенной из FindCalculatorServiceAddress.

  11. Внутри метода InvokeCalculatorService создайте экземпляр класса CalculatorServiceClient. Этот класс определяется примером самостоятельного узла . Он был сформирован с помощью программы Svcutil.exe.

    // Create a client
    CalculatorClient client = new CalculatorClient();
    
  12. В следующей строке укажите адрес конечной точки клиента в адресе конечной точки, возвращенном методом FindCalculatorServiceAddress().

    // Connect to the discovered service endpoint
    client.Endpoint.Address = endpointAddress;
    
  13. Сразу после кода предыдущего шага вызовите методы, доступные через службу калькулятора.

    Console.WriteLine("Invoking CalculatorService at {0}", endpointAddress);
    
    double value1 = 100.00D;
    double value2 = 15.99D;
    
    // Call the Add service operation.
    double result = client.Add(value1, value2);
    Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
    
    // Call the Subtract service operation.
    result = client.Subtract(value1, value2);
    Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);
    
    // Call the Multiply service operation.
    result = client.Multiply(value1, value2);
    Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);
    
    // Call the Divide service operation.
    result = client.Divide(value1, value2);
    Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
    Console.WriteLine();
    
    //Closing the client gracefully closes the connection and cleans up resources
    client.Close();
    
  14. Добавьте в метод Main() класса Program код для вызова FindCalculatorServiceAddress.

    public static void Main()
    {
        EndpointAddress endpointAddress = FindCalculatorServiceAddress();
    }
    
  15. В следующей строке вызовите метод InvokeCalculatorService() и передайте конечной точке адрес, возвращенный методом FindCalculatorServiceAddress().

    if (endpointAddress != null)
    {
        InvokeCalculatorService(endpointAddress);
    }
    
    Console.WriteLine("Press <ENTER> to exit.");
    Console.ReadLine();
    

Тестирование приложения

  1. Откройте командную строку с правами администратора и запустите программу Service.exe.

  2. Откройте окно командной строки и запустите программу Discoveryclientapp.exe.

  3. Результатом выполнения service.exe должен быть следующий вывод.

    Received Add(100,15.99)
    Return: 115.99
    Received Subtract(100,15.99)
    Return: 84.01
    Received Multiply(100,15.99)
    Return: 1599
    Received Divide(100,15.99)
    Return: 6.25390869293308
    
  4. Результатом выполнения Discoveryclientapp.exe должен быть следующий вывод.

    Invoking CalculatorService at http://localhost:8000/ServiceModelSamples/service
    Add(100,15.99) = 115.99
    Subtract(100,15.99) = 84.01
    Multiply(100,15.99) = 1599
    Divide(100,15.99) = 6.25390869293308
    
    Press <ENTER> to exit.
    

Пример

Ниже приведен полный листинг кода для данного образца. Так как этот код основан на примере самообслуживания, перечислены только те файлы, которые изменяются.

// Service.cs
using System;
using System.Configuration;
using System.ServiceModel;
using System.ServiceModel.Discovery;

namespace Microsoft.ServiceModel.Samples
{
    // See SelfHost sample for service contract and implementation
    // ...

        // Host the service within this EXE console application.
        public static void Main()
        {
            // Create a ServiceHost for the CalculatorService type.
            using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService)))
            {
                // Add the ServiceDiscoveryBehavior to make the service discoverable
                serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
                serviceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());

                // Open the ServiceHost to create listeners and start listening for messages.
                serviceHost.Open();

                // The service can now be accessed.
                Console.WriteLine("The service is ready.");
                Console.WriteLine("Press <ENTER> to terminate service.");
                Console.WriteLine();
                Console.ReadLine();
            }
        }
    }
}
// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Discovery;
using Microsoft.ServiceModel.Samples;
using System.Text;

namespace DiscoveryClientApp
{
    class Program
    {
        static EndpointAddress FindCalculatorServiceAddress()
        {
            // Create DiscoveryClient
            DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());

            // Find ICalculatorService endpoints
            FindResponse findResponse = discoveryClient.Find(new FindCriteria(typeof(ICalculator)));

            if (findResponse.Endpoints.Count > 0)
            {
                return findResponse.Endpoints[0].Address;
            }
            else
            {
                return null;
            }
        }

        static void InvokeCalculatorService(EndpointAddress endpointAddress)
        {
            // Create a client
            CalculatorClient client = new CalculatorClient();

            // Connect to the discovered service endpoint
            client.Endpoint.Address = endpointAddress;

            Console.WriteLine("Invoking CalculatorService at {0}", endpointAddress);

            double value1 = 100.00D;
            double value2 = 15.99D;

            // Call the Add service operation.
            double result = client.Add(value1, value2);
            Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

            // Call the Subtract service operation.
            result = client.Subtract(value1, value2);
            Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

            // Call the Multiply service operation.
            result = client.Multiply(value1, value2);
            Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

            // Call the Divide service operation.
            result = client.Divide(value1, value2);
            Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
            Console.WriteLine();

            //Closing the client gracefully closes the connection and cleans up resources
            client.Close();
        }
        static void Main(string[] args)
        {
            EndpointAddress endpointAddress = FindCalculatorServiceAddress();

            if (endpointAddress != null)
            {
                InvokeCalculatorService(endpointAddress);
            }

            Console.WriteLine("Press <ENTER> to exit.");
            Console.ReadLine();

        }
    }
}

См. также