HOW TO:使用 HTTP 傳輸

更新:2007 年 11 月

您可以使用 HTTP 傳輸在將連接到桌面上 Windows Communication Foundation (WCF) 服務的裝置上建立應用程式。

本主題將說明如何設定 WCF 服務處理連接裝置,以及如何建立用戶端應用程式。其中將解釋 WCF 服務組態與用戶端編寫程式碼之間的差異,您必須將這些差異納入考量,才能讓行動裝置與服務連線。如需如何建立桌面上 WCF 應用程式的詳細資訊,請參閱 WCF 文件中的使用者入門教學課程

建立桌面的 WCF 服務

  1. 建立新的 Web 服務專案。

  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 Utility 工具 (NetCFSvcUtil.exe) 產生用戶端程式碼。這個工具會將許多參數的支援建置到以 .NET Compact Framework 為基礎的應用程式中。NetCFSvcUtil.exe 會在 .NET Compact Framework 的 Power Toys 中提供。如需詳細資訊,請參閱 .NET Compact Framework 的 Power Toy (英文)。

    以下範例將說明簡化的計算機應用程式的 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 服務設定至 Web 伺服器上特定的通訊埠。

    使用介於 10000 和 650000 之間的任何通訊埠號嗎。這個範例使用通訊埠 50505。

  5. 啟動 Web 伺服器。

    如果您要檢視 Web 服務描述語言 (WSDL) 輸出並在 localhost 上執行服務,請瀏覽至 https://localhost:50505/CalculatorService/Service.svc?wsdl。使用您為 WCF 服務指定的相同通訊埠號碼和 Web 專案名稱。

  6. 如果您規劃從遠端電腦或裝置連接至 Web 伺服器,請設定虛擬目錄指向包含 Web 專案的目錄。

    注意事項:

    Visual Studio 中的 ASP.NET 程式開發伺服器只會回應來自本機開發電腦的要求。建議您使用 Internet Information Services (IIS) 指定虛擬目錄。如此,只要能夠連線到伺服器,您就可以從遠端裝置連接到 Web 伺服器。

  7. 確認您可以從桌面瀏覽器和裝置瀏覽器存取目錄。

建立 .NET Compact Framework 用戶端

  1. 服務執行時,開啟命令列並巡覽至 WCF 服務所在的目錄。

  2. 從命令列執行 WCF ServiceModel Desktop Utility 工具 (SvcUtil.exe) 產生 WCF 用戶端 Proxy。以下為 SvcUtil 的命令列引動過程範例 (服務裝載於 localhost 上的該工具中):

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

    以下範例將根據簡單的計算機範例,說明 SvcUtil 產生的用戶端 Proxy。

    //------------------------------------------------------------------------------
    // <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. 移除所產生用戶端 Proxy 程式碼中不支援的屬性和項目,包括下列各項:

    • 所有 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. 將產生的用戶端 Proxy 加入專案中。

  6. 在產生的 Proxy 程式碼中,將完整的 ClientBase<TChannel> 參考變更為使用者定義的 ClientBase 類別。

  7. 在產生的 Proxy 程式碼中,叫用使用者定義的 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. 將 Proxy 的基底類別加入專案中。這個類別的名稱為 ClientBase。

    變更用戶端 Proxy 的基底類別參考,以指向您的 ClientBase 實作。

    注意事項:

    在這個範例中,ClientBase 中的 CustomBodyWriter 類別僅支援基本型別。若要支援非基本型別,則須延伸 OnWriteBodyContents 方法。例如,您可呼叫自訂的序列化程式,以序列化訊息資料。在這種情況下,您會將所產生的用戶端 Proxy 中的程式碼屬性,轉譯成 XML 序列化程式可使用的屬性。在這個案例中,您必須先在執行 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. 加入類別以執行個體化及使用用戶端 Proxy。

    以下範例將說明叫用用戶端 Proxy 的程式碼。

    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 中的訊息

其他資源

Windows Communication Foundation (WCF) 開發和 .NET Compact Framework