如何:以编程方式向 WCF 服务和客户端添加可检测性How to: Programmatically Add Discoverability to a WCF Service and Client

本主题说明如何使 Windows Communication Foundation (WCF)服务可发现。This topic explains how to make a Windows Communication Foundation (WCF) service discoverable. 它基于自主机示例。It is based on the Self-Host sample.

针对 Discovery 配置现有自承载服务示例To configure the existing Self-Host service sample for Discovery

  1. 在 Visual Studio 2012 中打开自承载解决方案。Open the Self-Host solution in Visual Studio 2012. 示例位于 TechnologySamples\Basic\Service\Hosting\SelfHost 目录中。The sample is located in the TechnologySamples\Basic\Service\Hosting\SelfHost directory.

  2. 将对 System.ServiceModel.Discovery.dll 的引用添加到服务项目中。Add a reference to System.ServiceModel.Discovery.dll to the service project. 你可能会看到一条错误消息,指出 "系统。You may see an error message saying "System. "System.servicemodel. .dll" 或其依赖项之一需要更高版本的 .NET Framework,而不是在项目中指定的版本 ... "如果看到此消息,请在解决方案资源管理器中右键单击该项目,然后选择 "属性"。ServiceModel.Discovery.dll or one of its dependencies requires a later version of the .NET Framework than the one specified in the project …" If you see this message, right-click the project in the Solution Explorer and choose Properties. 在项目的 "属性" 窗口中,确保 .NET Framework 4.6.1.NET Framework 4.6.1目标框架In the Project Properties window, make sure that the Target Framework is .NET Framework 4.6.1.NET Framework 4.6.1.

  3. 打开 Service.cs 文件并添加下面的 using 语句。Open the Service.cs file and add the following using statement.

    using System.ServiceModel.Discovery;  
    
  4. Main() 方法的 using 语句内部,将一个 ServiceDiscoveryBehavior 实例添加到服务主机中。In the Main() method, inside the using statement, add a ServiceDiscoveryBehavior instance to the service host.

    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 指定自身应用到的服务可供检测。The ServiceDiscoveryBehavior specifies that the service it is applied to is discoverable.

  5. UdpDiscoveryEndpoint 添加到服务主机中,位置紧随添加 ServiceDiscoveryBehavior 的代码之后。Add a UdpDiscoveryEndpoint to the service host right after the code that adds the ServiceDiscoveryBehavior.

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

    此代码指定应将发现消息发送到标准 UDP 发现终结点。This code specifies that discovery messages should be sent to the standard UDP discovery endpoint.

创建使用发现功能调用服务的客户端应用程序To create a client application that uses discovery to call the service

  1. 向名为 DiscoveryClientApp 的解决方案添加一个新控制台应用程序。Add a new console application to the solution called DiscoveryClientApp.

  2. 添加对 System.ServiceModel.dllSystem.ServiceModel.Discovery.dll 的引用Add a reference to System.ServiceModel.dll and System.ServiceModel.Discovery.dll

  3. 将 GeneratedClient.cs 和 App.config 文件从现有客户端项目复制到新的 DiscoveryClientApp 项目。Copy the GeneratedClient.cs and App.config files from the existing client project to the new DiscoveryClientApp project. 为此,请在解决方案资源管理器中右键单击文件,选择 "复制",然后选择 " DiscoveryClientApp " 项目,右键单击并选择 "粘贴"。To do this, right-click the files in the Solution Explorer, select Copy, and then select the DiscoveryClientApp project, right-click and select Paste.

  4. 打开 Program.cs。Open Program.cs.

  5. 添加下面的 using 语句。Add the following using statements.

    using System.ServiceModel;  
    using System.ServiceModel.Discovery;  
    using Microsoft.ServiceModel.Samples;  
    
  6. 将一个名为 FindCalculatorServiceAddress() 的静态方法添加到 Program 类。Add a static method called FindCalculatorServiceAddress() to the Program class.

    static EndpointAddress FindCalculatorServiceAddress()  
    {  
    }  
    

    此方法使用发现功能搜索 CalculatorService 服务。This method uses discovery to search for the CalculatorService service.

  7. FindCalculatorServiceAddress 方法内部,创建新 DiscoveryClient 实例,以将 UdpDiscoveryEndpoint 传递给构造函数。Inside the FindCalculatorServiceAddress method, create a new DiscoveryClient instance, passing in a UdpDiscoveryEndpoint to the constructor.

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

    这会告知 WCF DiscoveryClient 类应使用标准 UDP 发现终结点来发送和接收发现消息。This tells WCF that the DiscoveryClient class should use the standard UDP discovery endpoint to send and receive discovery messages.

  8. 在下一行,调用 Find 方法并指定包含要搜索的服务协定的 FindCriteria 实例。On the next line, call the Find method and specify a FindCriteria instance that contains the service contract you want to search for. 在本示例中,指定的是 ICalculatorIn this case, specify ICalculator.

    // Find ICalculatorService endpoints              
    FindResponse findResponse = discoveryClient.Find(new FindCriteria(typeof(ICalculator)));  
    
  9. 调用 Find 之后,查看是否至少有一个匹配服务,然后返回第一个匹配服务的 EndpointAddressAfter the call to Find, check to see if there is at least one matching service and return the EndpointAddress of the first matching service. 如果找不到匹配服务,则返回 nullOtherwise return null.

    if (findResponse.Endpoints.Count > 0)  
    {  
        return findResponse.Endpoints[0].Address;  
    }  
    else  
    {  
        return null;  
    }  
    
  10. 将名为 InvokeCalculatorService 的静态方法添加到 Program 类。Add a static method named InvokeCalculatorService to the Program class.

    static void InvokeCalculatorService(EndpointAddress endpointAddress)  
    {  
    }  
    

    此方法使用从 FindCalculatorServiceAddress 返回的终结点地址调用计算器服务。This method uses the endpoint address returned from FindCalculatorServiceAddress to call the calculator service.

  11. InvokeCalculatorService 方法的内部,创建 CalculatorServiceClient 类的实例。Inside the InvokeCalculatorService method, create an instance of the CalculatorServiceClient class. 此类由自承载示例定义。This class is defined by the Self-Host sample. 并且是使用 Svcutil.exe 生成的。It was generated using Svcutil.exe.

    // Create a client  
    CalculatorClient client = new CalculatorClient();  
    
  12. 在下一行,将客户端的终结点地址设置为从 FindCalculatorServiceAddress() 返回的终结点地址。On the next line, set the endpoint address of the client to the endpoint address returned from FindCalculatorServiceAddress().

    // Connect to the discovered service endpoint  
    client.Endpoint.Address = endpointAddress;  
    
  13. 紧随上一步骤的代码之后,调用由计算器服务公开的方法。Immediately after the code for the previous step, call the methods exposed by the calculator service.

    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 方法以调用 FindCalculatorServiceAddressAdd code to the Main() method in the Program class to call FindCalculatorServiceAddress.

    public static void Main()  
    {  
        EndpointAddress endpointAddress = FindCalculatorServiceAddress();  
    }  
    
  15. 在下一行,调用 InvokeCalculatorService(),并传递由 FindCalculatorServiceAddress() 返回的终结点地址。On the next line, call the InvokeCalculatorService() and pass in the endpoint address returned from FindCalculatorServiceAddress().

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

测试应用程序To test the application

  1. 打开具有特权的命令提示符并运行 Service.exe。Open an elevated command prompt and run Service.exe.

  2. 打开命令提示符并运行 Discoveryclientapp.exe。Open a command prompt and run Discoveryclientapp.exe.

  3. service.exe 的输出应类似于以下输出。The output from service.exe should look like the following output.

    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 的输出应类似于以下输出。The output from Discoveryclientapp.exe should look like the following output.

    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.  
    

示例Example

下面是此示例的代码清单。The following is a listing of the code for this sample. 由于此代码基于自承载示例,因此仅列出已更改的文件。Because this code is based on the Self-Host sample, only those files that are changed are listed. 有关自承载示例的详细信息,请参阅安装说明For more information about the Self-Host sample, see Setup Instructions.

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

另请参阅See also