다음을 통해 공유


방법: HTTP 전송 사용

업데이트: 2007년 11월

HTTP 전송을 사용하여 데스크톱에서 WCF(Windows Communication Foundation) 서비스에 연결할 장치에 응용 프로그램을 만들 수 있습니다.

이 항목에서는 장치 연결을 처리하도록 WCF 서비스를 구성하는 방법과 클라이언트 응용 프로그램을 만드는 방법에 대해 설명합니다. 또한 모바일 장치가 서비스에 연결할 수 있도록 하기 위해 고려해야 하는 WCF 서비스 구성 및 클라이언트측 코딩의 차이점에 대해서도 설명합니다. 데스크톱용 WCF 응용 프로그램을 만드는 방법에 대한 자세한 내용은 WCF 설명서에서 초보자를 위한 자습서을 참조하십시오.

데스크톱용 WCF 서비스를 만들려면

  1. 새 웹 서비스 프로젝트를 만듭니다.

  2. 다음 예제에서처럼 Web.config 파일을 수정한 후 파일 내에서 다음 요소 및 특성을 수정합니다.

    • <endpoint>binding 특성 값을 "basicHttpBinding"으로 변경합니다. .NET Compact Framework는 텍스트 인코딩은 지원하지만 이진 인코딩은 지원하지 않습니다.

    • behaviorConfiguration 특성이 새 동작 이름을 참조하도록 변경합니다.

    • 예제에서처럼 <behavior> 요소를 바꿉니다.

    • Web.config 파일에 HTTP 서비스 처리기를 등록해야 하는 경우에는 예제에 나와 있는 정보가 포함된 새 <system.WebServer> 요소를 추가합니다.

    <?xml version="1.0"?>
    
    <configuration xmlns="https://schemas.microsoft.com/.NetConfiguration/v2.0">
      <system.serviceModel>
        <services>
          <service name="CalculatorService" behaviorConfiguration="MyServiceTypeBehaviors">
            <endpoint contract="ICalculatorService" binding="basicHttpBinding"/>
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="MyServiceTypeBehaviors">
              <serviceMetadata httpGetEnabled="true" />
              <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    
      <system.web>
        <compilation debug="true"/>
      </system.web>
    
      <system.webServer>
        <handlers>
          <add name="HttpSvcHandler" path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" resourceType="Unspecified" />
        </handlers>
      </system.webServer>
    
    </configuration>
    
  3. WCF 서비스의 소스 코드에서 ServiceContract 및 OperationContract 특성에 지정되어 있는 매개 변수를 모두 제거합니다.

    참고:

    이 샘플에서는 ServiceContract 및 OperationContract 등의 계약에 지정된 매개 변수에 대한 지원은 구현하지 않습니다. 이러한 계약에 대해 매개 변수를 지원해야 하는 경우에는 WCF .NET Compact Framework ServiceModel 유틸리티 도구(NetCFSvcUtil.exe)를 사용하여 클라이언트 코드를 생성하면 됩니다. 이 도구를 사용하면 .NET Compact Framework를 기반으로 하는 응용 프로그램에 대해 이러한 매개 변수의 대부분에 대한 기본적인 지원을 추가할 수 있습니다. NetCFSvcUtil.exe는 Power Toys for .NET Compact Framework에서 사용할 수 있습니다. 자세한 내용은 Power Toys for .NET Compact Framework를 참조하십시오.

    다음 예제에서는 간단한 계산기 응용 프로그램의 WCF 서비스 소스 코드를 보여 줍니다.

    <ServiceContract()>  _
    Public Interface ICalculatorService
        <OperationContract()>  _
        Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double 
        '<OperationContract()>  _
        Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double
    End Interface
    
    
    Public Class CalculatorService
        Implements ICalculatorService
    
        Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculatorService.Add
            Return n1 + n2
    
        End Function
    
        Public Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculatorService.Subtract
            Return n1 - n2
    
        End Function
    End Class
    
    [ServiceContract()]
    public interface ICalculatorService
    {
        [OperationContract]
        double Add(double n1, double n2);
        [OperationContract]
        double Subtract(double n1, double n2);
    }
    
    public class CalculatorService : ICalculatorService
    {
        public double Add(double n1, double n2) { return n1 + n2; }
        public double Subtract(double n1, double n2) { return n1 - n2; }
    }
    
  4. WCF 서비스를 웹 서버의 특정 포트로 설정합니다.

    10000에서 650000 사이의 숫자로 포트 번호를 지정합니다. 이 예제에서는 50505 포트를 사용합니다.

  5. 웹 서버를 시작합니다.

    WSDL(웹 서비스 기술 언어) 출력을 보고 localhost에서 서비스를 실행하려면 https://localhost:50505/CalculatorService/Service.svc?wsdl로 이동합니다. WCF 서비스에 대해 지정한 것과 같은 포트 번호 및 웹 프로젝트 이름을 사용하십시오.

  6. 원격 컴퓨터 또는 장치에서 웹 서버에 연결하려는 경우에는 웹 프로젝트가 들어 있는 디렉터리를 가리키도록 가상 디렉터리를 설정합니다.

    참고:

    Visual Studio의 ASP.NET Development Server는 로컬 개발 컴퓨터의 요청에만 응답합니다. 따라서 IIS(인터넷 정보 서비스)를 사용하여 가상 디렉터리를 지정하는 것이 좋습니다. 이렇게 하면 서버에 연결할 수 있는 경우 원격 장치에서 웹 서버에 연결할 수 있습니다.

  7. 데스크톱 브라우저 및 장치 브라우저에서 해당 디렉터리에 액세스할 수 있는지 확인합니다.

.NET Compact Framework 클라이언트를 만들려면

  1. 서비스가 실행 중인 동안 명령줄을 열고 WCF 서비스가 있는 디렉터리로 이동합니다.

  2. 명령줄에서 WCF ServiceModel 데스크톱 유틸리티 도구(SvcUtil.exe)를 실행하여 WCF 클라이언트 프록시를 생성합니다. 다음은 localhost에서 서비스가 호스팅되는 Svcutil에 대한 명령줄 호출의 예제입니다.

    svcutil.exe /language:c# https://localhost:50505/CalculatorService/Service.svc
    

    다음 예제에서는 간단한 계산기 예제를 기반으로 하는 SvcUtil에 의해 생성되는 클라이언트 프록시를 보여 줍니다.

    //------------------------------------------------------------------------------
    // <auto-generated>
    //     This code was generated by a tool.
    //     Runtime Version:2.0.50727.42
    //
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------
    
    
    
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="ICalculatorService")]
    public interface ICalculatorService
    {
    
        [System.ServiceModel.OperationContractAttribute(Action="https://fabrikam.com/ICalculatorService/Add", ReplyAction="https://fabrikam.com/ICalculatorService/AddResponse")]
        double Add(double n1, double n2);
    
        [System.ServiceModel.OperationContractAttribute(Action="https://fabrikam.com/ICalculatorService/Subtract", ReplyAction="https://fabrikam.com/ICalculatorService/SubtractResponse")]
        double Subtract(double n1, double n2);
    }
    
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    public interface ICalculatorServiceChannel : ICalculatorService, System.ServiceModel.IClientChannel
    {
    }
    
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    public partial class CalculatorServiceClient : System.ServiceModel.ClientBase<ICalculatorService>, ICalculatorService
    {
    
        public CalculatorServiceClient()
        {
        }
    
        public CalculatorServiceClient(string endpointConfigurationName) : 
                base(endpointConfigurationName)
        {
        }
    
        public CalculatorServiceClient(string endpointConfigurationName, string remoteAddress) : 
                base(endpointConfigurationName, remoteAddress)
        {
        }
    
        public CalculatorServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(endpointConfigurationName, remoteAddress)
        {
        }
    
        public CalculatorServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(binding, remoteAddress)
        {
        }
    
        public double Add(double n1, double n2)
        {
            return base.Channel.Add(n1, n2);
        }
    
        public double Subtract(double n1, double n2)
        {
            return base.Channel.Subtract(n1, n2);
        }
    }
    
  3. 생성된 클라이언트 프록시 코드에서 다음을 포함하여 지원되지 않는 특성 및 요소를 제거합니다.

    • 모든 System.ServiceModel 특성

    • IClientChannel 클래스에 대한 참조

    • <endpoint> 구성 이름에 대한 참조

    • 내부 채널의 ServiceContract 인터페이스 메서드를 호출하는 메서드 구현

    다음 예제에서는 이러한 수정 작업을 수행한 후의 코드를 보여 줍니다.

    '------------------------------------------------------------------------------
    ' <auto-generated>
    '     This code was generated by a tool.
    '     Runtime Version:2.0.50727.312
    '
    '     Changes to this file may cause incorrect behavior and will be lost if
    '     the code is regenerated.
    ' </auto-generated>
    '------------------------------------------------------------------------------
    
    Option Strict Off
    Option Explicit On
    
    
    
    Public Interface ICalculatorService
    
        Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double
    
        Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double
    End Interface
    
    Partial Public Class CalculatorServiceClient
        Inherits System.ServiceModel.ClientBase(Of ICalculatorService)
        Implements ICalculatorService
    
        ' Add a variable containing the endpoint address.
        Public Shared ServiceEndPoint As New System.ServiceModel.EndpointAddress("https://fabrikam.com/CalcService/CalculatorService/Service.svc")
    
        Public Sub New(ByVal binding As System.ServiceModel.Channels.Binding, ByVal remoteAddress As System.ServiceModel.EndpointAddress)
            MyBase.New(binding, remoteAddress)
        End Sub
    
        Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculatorService.Add
            Return MyBase.Channel.Add(n1, n2)
        End Function
    
        Public Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculatorService.Subtract
            Return MyBase.Channel.Subtract(n1, n2)
        End Function
    End Class
    
    //------------------------------------------------------------------------------
    // <auto-generated>
    //     This code was generated by a tool.
    //     Runtime Version:2.0.50727.42
    //
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------
    
    
    public interface ICalculatorService
    {
    
        double Add(double n1, double n2);
    
        double Subtract(double n1, double n2);
    }
    
    public partial class CalculatorServiceClient : System.ServiceModel.ClientBase<ICalculatorService>, ICalculatorService
    {
    
        // Add a variable to specify the server address.
        public static System.ServiceModel.EndpointAddress ServiceEndPoint = new System.ServiceModel.EndpointAddress("https://fabrikam.com/CalcService/CalculatorService/Service.svc");
    
        public CalculatorServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(binding, remoteAddress)
        {
        }
    
        public double Add(double n1, double n2)
        {
            return base.Channel.Add(n1, n2);
        }
    
        public double Subtract(double n1, double n2)
        {
            return base.Channel.Subtract(n1, n2);
        }
    }
    
  4. 클라이언트 프로젝트를 만듭니다.

  5. 생성된 클라이언트 프록시를 프로젝트에 추가합니다.

  6. 생성된 프록시 코드에서 ClientBase<TChannel>에 대한 정규화된 참조를 사용자 정의 ClientBase 클래스로 변경합니다.

  7. 생성된 프록시 코드에서 사용자 정의 ClientBase 클래스의 Call 메서드를 호출하여 메서드 구현을 추가합니다.

    Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculatorService.Add
        Return System.Convert.ToDouble(MyBase.Call("Add", "https://fabrikam.com/CalcService/ICalculatorService/Add", New String() {"n1", "n2"}, New Object() {n1, n2}, GetType(Double)))
    End Function
    
    public double Add(double n1, double n2)
    {
        return (double)base.Call("Add", "https://fabrikam.com/CalcService/ICalculatorService/Add", new string[] { "n1", "n2" }, new object[] { n1, n2 }, typeof(double));
    }
    
  8. 프록시의 기본 클래스를 프로젝트에 추가합니다. 이 클래스의 이름은 ClientBase입니다.

    ClientBase 구현을 가리키도록 클라이언트 프록시의 기본 클래스 참조를 변경합니다.

    참고:

    이 예제에서 ClientBase의 CustomBodyWriter 클래스는 기본 형식만을 지원합니다. 기본 형식이 아닌 형식을 지원하려면 OnWriteBodyContents 메서드를 확장해야 합니다. 예를 들어 사용자 지정 serializer를 호출하여 메시지 데이터를 serialize할 수 있습니다. 이 경우 생성된 클라이언트 프록시의 코드 특성을 XML serializer가 사용할 수 있는 특성으로 변환합니다. 이렇게 하려면 먼저 SvcUtil을 실행할 때 /serializer:xmlserializer http://endpoint 스위치를 추가해야 합니다.

    다음 코드에서는 ClientBase 클래스의 예제를 보여 줍니다.

    Public Class ClientBase(Of TChannel As Class)
    
        Private requestChannel As IRequestChannel
        Private messageVersion As MessageVersion
    
    
        Public Sub New(ByVal binding As System.ServiceModel.Channels.Binding, ByVal remoteAddress As System.ServiceModel.EndpointAddress)
            'this.remoteAddress = remoteAddress;
            Me.messageVersion = binding.MessageVersion
    
            Dim channelFactory As IChannelFactory(Of IRequestChannel)
            channelFactory = binding.BuildChannelFactory(Of IRequestChannel)(New BindingParameterCollection())
            channelFactory.Open()
            Me.requestChannel = channelFactory.CreateChannel(remoteAddress)
    
        End Sub
    
    
        Public Function [Call](ByVal op As String, ByVal action As String, ByVal varnames() As String, ByVal varvals() As Object, ByVal returntype As Type) As Object
            requestChannel.Open(TimeSpan.MaxValue)
    
            Dim msg As Message = Message.CreateMessage(Me.messageVersion, action, New CustomBodyWriter(op, varnames, varvals, "<ns passed in from Proxy>"))
    
            Dim reply As Message = requestChannel.Request(msg, TimeSpan.MaxValue)
            Dim reader As XmlDictionaryReader = reply.GetReaderAtBodyContents()
            reader.ReadToFollowing(op + "Result")
            Return reader.ReadElementContentAs(returntype, Nothing)
    
        End Function
    End Class
    
    
    Friend Class CustomBodyWriter
        Inherits BodyWriter
        Private op As String
        Private varnames() As String
        Private varvals() As Object
        Private ns As String
    
    
        Public Sub New(ByVal op As String, ByVal varnames() As String, ByVal varvals() As Object, ByVal ns As String)
            MyBase.New(True)
            Me.op = op
            Me.varnames = varnames
            Me.varvals = varvals
            Me.ns = ns
    
        End Sub
    
    
        Protected Overrides Sub OnWriteBodyContents(ByVal writer As XmlDictionaryWriter)
            writer.WriteStartElement(op, ns)
            Dim i As Integer
            For i = 0 To varnames.Length
                writer.WriteElementString(varnames(i), varvals(i).ToString())
            Next i
            writer.WriteEndElement()
    
        End Sub
    End Class
    
    public class ClientBase<TChannel>
        where TChannel : class
    {
        private IRequestChannel requestChannel;
        private MessageVersion messageVersion;
    
        public ClientBase(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress)
        {
            //this.remoteAddress = remoteAddress;
            this.messageVersion = binding.MessageVersion;
    
            IChannelFactory<IRequestChannel> channelFactory = binding.BuildChannelFactory<IRequestChannel>(
                new BindingParameterCollection());
            channelFactory.Open();
            this.requestChannel = channelFactory.CreateChannel(remoteAddress);
        }
    
        public object Call(string op, string action, string[] varnames, object[] varvals, Type returntype)
        {
            requestChannel.Open(TimeSpan.MaxValue);
    
            //Message msg =                     
            //Message.CreateMessage(MessageVersion.<FromBinding>,
            //      action,
            //      new CustomBodyWriter(op, varnames, varvals,                 
            //"<ns passed in from Proxy>"));
    
            Message msg =                   
            Message.CreateMessage(this.messageVersion, action,
                  new CustomBodyWriter(op, varnames, varvals,               
            "<ns passed in from Proxy>"));
    
            Message reply = requestChannel.Request(msg, TimeSpan.MaxValue);
            XmlDictionaryReader reader = reply.GetReaderAtBodyContents();
            reader.ReadToFollowing(op + "Result");
            return reader.ReadElementContentAs(returntype, null);
        }
    
    }
    
    internal class CustomBodyWriter : BodyWriter
    {
        private string op;
        private string[] varnames;
        private object[] varvals;
        private string ns;
    
        public CustomBodyWriter(string op, string[] varnames, object[] varvals, string ns)
            : base(true)
        {
            this.op = op;
            this.varnames = varnames;
            this.varvals = varvals;
            this.ns = ns;
        }
    
        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            writer.WriteStartElement(op, ns);
            for (int i = 0; i < varnames.Length; i++)
                writer.WriteElementString(varnames[i], varvals[i].ToString());
            writer.WriteEndElement();
        }
    }
    
  9. 클라이언트 프록시를 인스턴스화하고 사용하는 데 필요한 클래스를 추가합니다.

    다음 예제에서는 클라이언트 프록시를 호출하는 코드를 보여 줍니다.

    Shared Sub Main(ByVal args() As String)
        Dim serverAddress As String = CalculatorServiceClient.ServiceEndPoint.Uri.AbsoluteUri
        ' Using basic http connection. WS binding should be also available.
        Dim proxy As ICalculatorService = New CalculatorServiceClient(New BasicHttpBinding, New EndpointAddress(serverAddress))
        MessageBox.Show("Add 3 + 6...")
        MessageBox.Show(proxy.Add(3, 6).ToString)
        MessageBox.Show("Subtract 8 - 3...")
        MessageBox.Show(proxy.Subtract(8, 3).ToString)
    End Sub
    
    static void Main()
    {
        string serverAddress = CalculatorServiceClient.ServiceEndPoint.Uri.AbsoluteUri;
        // Using basic http connection. WS binding should be also available.
        ICalculatorService proxy = new CalculatorServiceClient(new BasicHttpBinding(), new EndpointAddress(serverAddress));
    
    
        MessageBox.Show("Add 3 + 6...");
        MessageBox.Show((proxy.Add(3, 6)).ToString());
        MessageBox.Show("Subtract 8 - 3...");        
        MessageBox.Show((proxy.Subtract(8, 3)).ToString());
    
    }
    
  10. 클라이언트 응용 프로그램을 빌드하여 장치로 배포합니다.

  11. WCF 서비스가 실행 중이며 장치가 네트워크에 연결되어 있을 때 장치에서 클라이언트 응용 프로그램을 시작합니다.

코드 컴파일

WCF 서비스의 소스 코드에는 다음 네임스페이스에 대한 참조가 필요합니다.

ClientBase 클래스의 소스 코드에는 다음 네임스페이스에 대한 참조가 필요합니다.

클라이언트 응용 프로그램에서 Main 메서드가 포함된 클래스의 소스 코드에는 다음 네임스페이스에 대한 참조가 필요합니다.

보안

이 예제에서는 WCF 보안 기능은 구현하지 않습니다. 지원되는 보안 기능에 대한 자세한 내용은 .NET Compact Framework의 메시징을 참조하십시오.

참고 항목

개념

.NET Compact Framework의 메시징

기타 리소스

WCF(Windows Communication Foundation) 개발 및 .NET Compact Framework