Udostępnij za pośrednictwem


How to: Use the HTTP Transport

You can use the HTTP transport to create applications on a device that will connect to a Windows Communication Foundation (WCF) service on the desktop.

This topic describes how to configure the WCF service to handle connecting devices and how to create the client application. It explains the differences in WCF service configuration and client-side coding that you must consider to enable mobile devices to connect to the service. For additional information about how to create WCF applications for the desktop, see the Getting Started Tutorial in the WCF documentation.

To create the WCF service for the desktop

  1. Create a new Web service project.

  2. Modify the Web.config file as shown in the following example. Modify the following elements and attributes in the file:

    • Change the <endpoint>binding attribute value to "basicHttpBinding". The .NET Compact Framework supports text encoding, but not binary encoding.

    • Change the behaviorConfiguration attribute to refer to the new behavior name.

    • Replace the <behavior> element as shown in the example.

    • If you need to register the HTTP service handler in the Web.config file, add a new <system.WebServer> element with the information shown in the example.

    <?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. In the source code for the WCF service, remove any parameters specified in the ServiceContract and OperationContract attributes from your code.

    Note

    This sample does not implement support for parameters specified in contracts such as ServiceContract and OperationContract. If you need parameter support for these contracts, you can use the WCF .NET Compact Framework ServiceModel Utility tool (NetCFSvcUtil.exe) to generate client code. This tool builds support for many of these parameters into applications that are based on the .NET Compact Framework. NetCFSvcUtil.exe is available in the Power Toys for .NET Compact Framework. For more information, see Power Toys for .NET Compact Framework.

    The following example shows the WCF service source code for a simplified calculator application.

    <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. Set the WCF service to a specific port on your Web server.

    Use any port number between 10000 and 650000. This example uses port 50505.

  5. Start the Web server.

    If you want to view Web Services Description Language (WSDL) output and run the service on localhost, browse to https://localhost:50505/CalculatorService/Service.svc?wsdl. Use the same port number and Web project name that you specified for the WCF service.

  6. If you are planning to connect to the Web server from a remote computer or device, set up a virtual directory to point to the directory that contains the Web project.

    Note

    The ASP.NET Development Server in Visual Studio responds only to requests from your local development machine. We recommend that you use Internet Information Services (IIS) to specify a virtual directory. This enables you to connect to the Web server from a remote device as long as the server is reachable.

  7. Verify that you can access the directory from a desktop browser and a device browser.

To create the .NET Compact Framework client

  1. While the service is running, open a command line and navigate to the directory where the WCF service is located.

  2. From the command line, run the WCF ServiceModel Desktop Utility tool (SvcUtil.exe) to generate a WCF client proxy. Here is an example of the command-line invocation for SvcUtil in which the service is hosted on localhost:

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

    The following example shows a client proxy generated by SvcUtil that is based on the simple calculator example.

    //------------------------------------------------------------------------------ 
    // <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. Remove unsupported attributes and elements from the generated client proxy code, including the following:

    • All System.ServiceModel attributes.

    • References to the IClientChannel class.

    • References to <endpoint> configuration names.

    • Method implementations that call methods of the ServiceContract interface on the internal channel.

    The following example shows the code after these modifications.

    '------------------------------------------------------------------------------ 
    ' <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. Create a client project.

  5. Add the generated client proxy to the project.

  6. In the generated proxy code, change the fully-qualified reference to ClientBase<TChannel> to the user-defined ClientBase class.

  7. In the generated proxy code, add method implementations by invoking the Call method in the user-defined ClientBase class.

    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. Add the base class for the proxy to the project. This class is named ClientBase.

    Change the base class reference of your client proxy to point to your implementation of ClientBase.

    Note

    In this example, the CustomBodyWriter class in ClientBase supports only primitive types. To support non-primitive types, you have to extend the OnWriteBodyContents method. For example, you could call a custom serializer to serialize message data. In this case, you would translate code attributes in the generated client proxy to attributes that the XML serializer could consume. In this scenario, you must first add the following switch when you run SvcUtil: /serializer:xmlserializer http://endpoint.

    The following code shows an example of the ClientBase class.

    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. Add a class to instantiate and use the client proxy.

    The following example shows code that invokes the client 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. Build the client application and deploy it to your device.

  11. When the WCF service is running and your device is connected to the network, start the client application on the device.

Compiling the Code

The source code for the WCF service requires references to the following namespaces:

The source code for the ClientBase class requires references to the following namespaces:

The source code for the class that contains the Main method in the client application requires references to the following namespaces:

Security

This example does not implement any WCF security features. For more information about supported security features, see Messaging in the .NET Compact Framework.

See Also

Concepts

Messaging in the .NET Compact Framework

Other Resources

Windows Communication Foundation (WCF) Development and the .NET Compact Framework