How to: Use the HTTP Transport
[This documentation is for preview only, and is subject to change in later releases. Blank topics are included as placeholders.]
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
Create a new Web service project.
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>
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; } }
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.
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.
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.
Verify that you can access the directory from a desktop browser and a device browser.
To create the .NET Compact Framework client
While the service is running, open a command line and navigate to the directory where the WCF service is located.
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); } }
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); } }
Create a client project.
Add the generated client proxy to the project.
In the generated proxy code, change the fully-qualified reference to ClientBase<TChannel> to the user-defined ClientBase class.
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)); }
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 https://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(); } }
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()); }
Build the client application and deploy it to your device.
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