Comment : utiliser le transport HTTP
Mise à jour : novembre 2007
Vous pouvez utiliser le transport HTTP pour créer des applications sur un appareil qui se connectera à un service Windows Communication Foundation (WCF) sur l'ordinateur.
Cette rubrique décrit comment configurer le service WCF pour gérer la connexion d'appareils et comment créer l'application cliente. Elle explique les différences de configuration de service WCF et de codage côté client dont il faut tenir compte pour permettre aux appareils mobiles de se connecter au service. Pour plus d'informations sur la création d'applications WCG pour l'ordinateur, consultez Didacticiel de mise en route dans la documentation WCF.
Pour créer le service WCF pour l'ordinateur
Créez un projet de service Web.
Modifiez le fichier Web.config comme indiqué dans l'exemple suivant. Modifiez les éléments et attributs suivants dans le fichier :
Remplacez la valeur de l'attribut binding de <endpoint> par « basicHttpBinding ». Le .NET Compact Framework prend en charge le codage de texte, mais pas le codage binaire.
Modifiez l'attribut behaviorConfiguration pour faire référence au nouveau nom de comportement.
Remplacez l'élément <behavior> comme indiqué dans l'exemple.
Si vous devez enregistrer le gestionnaire de service HTTP dans le fichier Web.config, ajoutez un nouvel élément <system.WebServer> avec les informations fournies dans l'exemple.
<?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>
Dans le code source du service WCF, supprimez tous les paramètres spécifiés dans les attributs ServiceContract et OperationContract.
Remarque : Cet exemple n'implémente pas la prise en charge des paramètres spécifiés dans les contrats, tels que ServiceContract et OperationContract. Si vous voulez utiliser la prise en charge des paramètres pour ces contrats, vous pouvez faire appel à l'outil ServiceModel Utility (NetCFSvcUtil.exe) WCF du .NET Compact Framework pour générer le code client. Cet outil intègre la prise en charge de ces paramètres dans des applications basées sur le .NET Compact Framework. NetCFSvcUtil.exe est disponible dans les Power Toys pour le .NET Compact Framework. Pour plus d'informations, consultez Power Toys pour le .NET Compact Framework (en anglais).
L'exemple suivant affiche le code source du service WCF pour une application de calculatrice simplifiée.
<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; } }
Affectez au service WCF un port spécifique sur votre serveur Web.
Utilisez un numéro de port compris entre 10000 et 650000. Cet exemple utilise le port 50505.
Démarrez le serveur Web.
Si vous souhaitez consulter la sortie Web Services Description Language (WSDL) et exécuter le service sur le localhost, accédez à https://localhost:50505/CalculatorService/Service .svc? wsdl. Utilisez les mêmes numéro de port et nom de projet Web que ceux du service WCF.
Si vous comptez vous connecter au serveur Web à partir d'un ordinateur ou périphérique distant, installez un répertoire virtuel qui pointe vers le répertoire contenant le projet Web.
Remarque : Le serveur de développement ASP.NET dans Visual Studio répond uniquement aux demandes de votre ordinateur de développement local. Nous vous recommandons d'utiliser les services IIS (Internet Information Services) pour spécifier un répertoire virtuel. Vous pourrez alors vous connecter au serveur Web d'un périphérique distant si le serveur est accessible.
Vérifiez que vous pouvez accéder au répertoire à partir d'un navigateur d'ordinateur de bureau et d'un navigateur d'appareil.
Pour créer le client .NET Compact Framework
Lorsque le service est en cours d'exécution, ouvrez une ligne de commande et accédez au répertoire contenant le service WCF.
À partir de la ligne de commande, exécutez l'outil WCF ServiceModel Desktop Utility (Svcutil.exe) pour générer un proxy client WCF. L'exemple suivant illustre l'appel de ligne de commande de SvcUtil dans lequel le service est hébergé sur le localhost :
svcutil.exe /language:c# https://localhost:50505/CalculatorService/Service.svc
L'exemple suivant affiche un proxy client généré par SvcUtil qui est basé sur l'exemple de calculatrice simple.
//------------------------------------------------------------------------------ // <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); } }
Supprimez les attributs et éléments non pris en charge du code proxy client généré, y compris les suivants :
tous les attributs System.ServiceModel ;
les références à la classe IClientChannel ;
les références aux noms de configuration du <endpoint> ;
les implémentations de méthode qui appellent des méthodes de l'interface ServiceContract sur le canal interne.
L'exemple suivant affiche le code une fois ces modifications appliquées.
'------------------------------------------------------------------------------ ' <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); } }
Créez un projet client.
Ajoutez le proxy client généré au projet.
Dans le code proxy généré, remplacez la référence qualifiée complète à ClientBase<TChannel> par la classe ClientBase définie par l'utilisateur.
Dans le code proxy généré, ajoutez des implémentations de méthode en appelant la méthode Call dans la classe ClientBase définie par l'utilisateur.
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)); }
Ajoutez au projet la classe de base pour le proxy. Cette classe s'appelle ClientBase.
Modifiez la référence de classe de base de votre proxy client en la faisant pointer vers votre implémentation de ClientBase.
Remarque : Dans cet exemple, la classe CustomBodyWriter dans ClientBase ne prend en charge que les types primitifs. Pour prendre en charge des types non primitifs, vous devez étendre la méthode OnWriteBodyContents. Par exemple, vous pouvez appeler un sérialiseur personnalisé pour sérialiser des données de message. Dans ce cas, vous convertissez des attributs de code dans le proxy client généré en attributs que le sérialiseur XML pourrait consommer. Dans ce scénario, vous devez commencer par ajouter le commutateur suivant lorsque vous exécutez SvcUtil : /serializer:xmlserializer http://point de terminaison.
Le code suivant illustre un exemple de la classe 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(); } }
Ajoutez une classe à instancier et utilisez le proxy client.
L'exemple suivant affiche un code qui appelle le proxy client.
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()); }
Générez l'application cliente et déployez-la sur votre appareil.
Lorsque le service WCF est en cours d'exécution et que votre appareil est connecté au réseau, démarrez l'application cliente sur l'appareil.
Compilation du code
Le code source pour le service WCF requiert des références aux espaces de noms suivants :
Le code source pour la classe ClientBase requiert des références aux espaces de noms suivants :
Le code source pour la classe qui contient la méthode Main dans l'application cliente requiert des références aux espaces de noms suivants :
Sécurité
Cet exemple n'implémente aucune fonctionnalité de sécurité WCF. Pour plus d'informations sur les fonctionnalités de sécurité prises en charge, consultez Messagerie dans le .NET Compact Framework.
Voir aussi
Concepts
Messagerie dans le .NET Compact Framework
Autres ressources
Développement Windows Communication Foundation (WCF) et le .NET Compact Framework