방법: 프로그래밍 방식으로 WCF 서비스 및 클라이언트에 검색 기능 추가
이 항목에서는 WCF(Windows Communication Foundation) 서비스를 검색 가능하게 만드는 방법에 대해 설명하며, 이 방법은 Self-Host 샘플을 기반으로 합니다.
기존 자체 호스팅 서비스 샘플을 검색용으로 구성하려면
Visual Studio 2010에서 자체 호스트 솔루션을 엽니다. 샘플은 TechnologySamples\Basic\Service\Hosting\SelfHost 디렉터리에 있습니다.
서비스 프로젝트에
System.ServiceModel.Discovery.dll
에 대한 참조를 추가합니다. “System.ServiceModel.Discovery.dll 또는 해당 종속 항목 중 하나에 필요한 .NET Framework 버전이 프로젝트에 지정된 버전보다 높은 버전입니다…”라는 오류 메시지가 나타날 수 있습니다. 이 메시지가 나타나면 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성을 선택한 다음 프로젝트 속성 창에서 대상 프레임워크가 .NET Framework 버전 4인지 확인합니다.Service.cs 파일을 열고 다음
using
문을 추가합니다.using System.ServiceModel.Discovery;
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는 자신이 적용되는 서비스가 검색 가능하게 되도록 지정합니다.
ServiceDiscoveryBehavior를 추가하는 코드 바로 뒤에 있는 서비스 호스트에 UdpDiscoveryEndpoint를 추가합니다.
// Add ServiceDiscoveryBehavior serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior()); // Add a UdpDiscoveryEndpoint serviceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());
이 코드는 검색 메시지를 표준 UDP 검색 끝점에 보내도록 지정합니다.
검색을 사용하는 클라이언트 응용 프로그램을 만들어 서비스를 호출하려면
DiscoveryClientApp
라는 솔루션에 새 콘솔 응용 프로그램을 추가합니다.System.ServiceModel.dll
및System.ServiceModel.Discovery.dll
에 대한 참조를 추가합니다.GeneratedClient.cs 및 App.config 파일을 기본 클라이언트 프로젝트에서 새 DiscoveryClientApp 프로젝트로 복사합니다. 이렇게 하려면 솔루션 탐색기에서 파일을 마우스 오른쪽 단추로 클릭하고 복사를 선택한 다음 DiscoveryClientApp 프로젝트를 선택합니다. 그런 다음 마우스 오른쪽 단추를 클릭하고 붙여넣기를 선택합니다.
Program.cs를 엽니다.
다음
using
문을 추가합니다.using System.ServiceModel; using System.ServiceModel.Discovery; using Microsoft.ServiceModel.Samples;
FindCalculatorServiceAddress()
라는 정적 메서드를Program
클래스에 추가합니다.static EndpointAddress FindCalculatorServiceAddress() { }
이 메서드는 검색을 사용하여
CalculatorService
서비스를 찾습니다.FindCalculatorServiceAddress
메서드 안에서 생성자에 UdpDiscoveryEndpoint를 전달하여 새 DiscoveryClient 인스턴스를 만듭니다.static EndpointAddress FindCalculatorServiceAddress() { // Create DiscoveryClient DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint()); }
이렇게 하면 DiscoveryClient 클래스에서 표준 UDP 검색 끝점을 사용하여 검색 메시지를 보내고 받아야 한다는 내용이 WCF에 전달됩니다.
다음 줄에서 Find 메서드를 호출하고 검색하려는 서비스 계약이 포함된 FindCriteria 인스턴스를 지정합니다. 이 경우
ICalculator
를 지정합니다.// Find ICalculatorService endpoints FindResponse findResponse = discoveryClient.Find(new FindCriteria(typeof(ICalculator)));
Find를 호출한 후 일치하는 서비스가 하나 이상 있는지 확인하고 첫 번째 일치하는 서비스의 EndpointAddress를 반환합니다. 그렇지 않으면 null을 반환합니다.
if (findResponse.Endpoints.Count > 0) { return findResponse.Endpoints[0].Address; } else { return null; }
InvokeCalculatorService
라는 정적 메서드를Program
클래스에 추가합니다.static void InvokeCalculatorService(EndpointAddress endpointAddress) { }
이 메서드는
FindCalculatorServiceAddress
에서 반환되는 끝점 주소를 사용하여 계산기 서비스를 호출합니다.InvokeCalculatorService
메서드 안에서CalculatorServiceClient
클래스의 인스턴스를 만듭니다. 이 클래스는 Self-Host 샘플에서 정의됩니다. 이 클래스는 Svcutil.exe를 사용하여 생성되었습니다.// Create a client CalculatorClient client = new CalculatorClient();
다음 줄에서 클라이언트의 끝점 주소를
FindCalculatorServiceAddress()
에서 반환되는 끝점 주소로 설정합니다.// 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();
Program
클래스의Main()
메서드에FindCalculatorServiceAddress
를 호출하는 코드를 추가합니다.public static void Main() { EndpointAddress endpointAddress = FindCalculatorServiceAddress(); }
다음 줄에서
InvokeCalculatorService()
를 호출하고FindCalculatorServiceAddress()
에서 반환되는 끝점 주소를 전달합니다.if (endpointAddress != null) { InvokeCalculatorService(endpointAddress); } Console.WriteLine("Press <ENTER> to exit."); Console.ReadLine();
응용 프로그램을 테스트하려면
권한이 높은 명령 프롬프트를 열고 Service.exe를 실행합니다.
명령 프롬프트를 열고 Discoveryclientapp.exe를 실행합니다.
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
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
Press <ENTER> to exit.
예제
다음은 이 샘플의 코드 목록입니다. 이 코드가 Self-Host 샘플을 기반으로 하기 때문에 이 목록에는 변경된 파일만 나옵니다. Self-Host 샘플에 대한 자세한 내용은 설치 지침을 참조하십시오.
// 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();
}
}
}