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

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

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

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

  2. Добавьте ссылку на проект службы System.ServiceModel.Discovery.dll. Может появиться следующее сообщение об ошибке: «System. ServiceModel.Discovery.dll или одна из его зависимостей требует наличия более поздней версии .NET Framework, чем версия, указанная в проекте …». Получив такое сообщение, щелкните проект в обозревателе решений правой кнопкой мыши и выберите Свойства. В окне Свойства проекта проверьте, что Требуемая версия .NET Framework равна .NET Framework, версия 4.

  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
  1. Результатом выполнения Discoveryclientapp.exe должен быть следующий вывод.
    Invoking CalculatorService at https://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

    Чтобы выйти, нажмите клавишу &lt;ВВОД&gt;.

Пример

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

    // 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();
    
            }
        }
    }

См. также

Основные понятия

Общие сведения об обнаружении WCF
Модель объектов обнаружения WCF