Gewusst wie: Verwenden der HTTP-Übertragung
Aktualisiert: November 2007
Mithilfe der HTTP-Übertragung können Sie Anwendungen auf einem Gerät erstellen, das eine Verbindung zu einem Windows Communication Foundation (WCF)-Dienst auf dem Desktop herstellt.
In diesem Thema wird beschrieben, wie Sie den WCF-Dienst für die Behandlung von verbindenden Geräten konfigurieren und wie Sie die Clientanwendung erstellen. Es werden die Unterschiede zwischen der WCF-Dienstkonfiguration und der clientseitigen Codierung erläutert, die berücksichtigt werden müssen, wenn Sie die Verbindung mobiler Geräte mit dem Dienst ermöglichen möchten. Zusätzliche Informationen zum Erstellen von WCF-Anwendungen für den Desktop finden Sie in der WCF-Dokumentation unter Lernprogramm "Erste Schritte".
So erstellen Sie den WCF-Dienst für den Desktop
Erstellen Sie ein neues Webdienstprojekt.
Ändern Sie die Datei Web.config, wie im folgenden Beispiel veranschaulicht. Ändern Sie folgende Elemente und Attribute in der Datei:
Ändern Sie den <endpoint>binding-Attributwert in "basicHttpBinding". .NET Compact Framework unterstützt die Textcodierung, aber keine binäre Codierung.
Ändern Sie das behaviorConfiguration-Attribut, sodass es auf den Namen des neuen Verhaltens verweist.
Ersetzen Sie das <behavior>-Element, wie im Beispiel veranschaulicht.
Wenn Sie den HTTP-Diensthandler in der Datei Web.config registrieren müssen, fügen Sie ein neues <system.WebServer>-Element mit den im Beispiel enthaltenen Informationen hinzu.
<?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>
Entfernen Sie im Quellcode des WCF-Dienstes alle im ServiceContract-Attribut und im OperationContract-Attribut angegebenen Parameter aus dem Code.
Hinweis: In diesem Beispiel wurde keine Unterstützung für Parameter implementiert , die in Verträgen wie ServiceContract und OperationContract angegeben wurden. Wenn Sie Parameterunterstützung für diese Verträge benötigen, können Sie mit dem WCF .NET Compact Framework ServiceModel-Dienstprogramm (NetCFSvcUtil.exe) Clientcode generieren. Durch dieses Tool wird Unterstützung für viele dieser Parameter in Anwendungen integriert, die auf .NET Compact Framework basieren. NetCFSvcUtil.exe ist in den Power Toys für .NET Compact Framework verfügbar. Weitere Informationen finden Sie unter Power Toys for .NET Compact Framework.
Im folgenden Beispiel wird der Quellcode des WCF-Dienstes für eine vereinfachte Rechneranwendung veranschaulicht.
<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; } }
Legen Sie den WCF-Dienst auf einen bestimmten Anschluss auf dem Webserver fest.
Verwenden Sie eine beliebige Anschlussnummer zwischen 10000 und 650000. In diesem Beispiel wird Anschluss 50505 verwendet.
Starten Sie den Webserver.
Wenn Sie die Web Services Description Language (WSDL)-Ausgabe anzeigen und den Dienst unter localhost ausführen möchten, suchen Sie https://localhost:50505/CalculatorService/Service.svc?wsdl. Verwenden Sie die Anschlussnummer und den Webprojektnamen, die Sie für den WCF-Dienst angegeben haben.
Wenn Sie von einem Remotecomputer oder -gerät eine Verbindung mit dem Webserver herstellen möchten, richten Sie ein virtuelles Verzeichnis ein, das auf das Verzeichnis mit dem Webprojekt verweist.
Hinweis: Der ASP.NET Development Server in Visual Studio reagiert nur auf Anforderungen vom lokalen Entwicklungscomputer. Es wird empfohlen, über die Internetinformationsdienste (IIS) ein virtuelles Verzeichnis anzugeben. Auf diese Weise können Sie von einem Remotegerät aus eine Verbindung mit dem Webserver herstellen, solange der Server erreichbar ist.
Überprüfen Sie, ob Sie über einen Desktopbrowser und einen Gerätebrowser auf das Verzeichnis zugreifen können.
So erstellen Sie den .NET Compact Framework-Client
Öffnen Sie, während der Dienst ausgeführt wird, eine Befehlszeile, und navigieren Sie zu dem Verzeichnis, in dem sich der WCF-Dienst befindet.
Führen Sie von der Befehlszeile das WCF ServiceModel Desktop-Dienstprogramm (SvcUtil.exe) aus, um einen WCF-Clientproxy zu generieren. Im Folgenden sehen Sie ein Beispiel für den Befehlszeilenaufruf für SvcUtil, in dem der Dienst auf localhost gehostet ist:
svcutil.exe /language:c# https://localhost:50505/CalculatorService/Service.svc
Im folgenden Beispiel wird ein von SvcUtil generierter Clientproxy veranschaulicht, der auf dem einfachen Rechnerbeispiel basiert.
//------------------------------------------------------------------------------ // <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); } }
Entfernen Sie nicht unterstützte Attribute und Elemente aus dem generierten Clientproxycode, darunter folgende:
Alle System.ServiceModel-Attribute
Verweise auf die IClientChannel-Klasse
Verweise auf <endpoint>-Konfigurationsnamen
Methodenimplementierungen, durch die Methoden der ServiceContract-Schnittstelle im internen Kanal aufgerufen werden
Im folgenden Beispiel wird veranschaulicht, wie der Code nach diesen Änderungen aussieht.
'------------------------------------------------------------------------------ ' <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); } }
Erstellen Sie ein Clientprojekt.
Fügen Sie dem Projekt den generierten Clientproxy hinzu.
Ändern Sie im generierten Proxycode den vollqualifizierten Verweis auf ClientBase<TChannel> in die benutzerdefinierte ClientBase-Klasse.
Fügen Sie im generierten Proxycode Methodenimplementierungen hinzu, indem Sie die Call-Methode in der benutzerdefinierten ClientBase-Klasse aufrufen.
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)); }
Fügen Sie dem Projekt die Basisklasse für den Proxy hinzu. Diese Klasse wird ClientBase genannt.
Ändern Sie den Basisklassenverweis des Clientproxys, sodass er auf Ihre Implementierung von ClientBase verweist.
Hinweis: In diesem Beispiel unterstützt die CustomBodyWriter-Klasse in ClientBase nur primitive Typen. Für die Unterstützung nicht primitiver Typen müssen Sie die OnWriteBodyContents-Methode erweitern. Beispielsweise können Sie einen benutzerdefinierten Serialisierer aufrufen, um Meldungsdaten zu serialisieren. In diesem Fall würden Sie Codeattribute im generierten Clientproxy in Attribute übersetzen, die vom XML-Serialisierer verwendet werden können. In diesem Szenario müssen Sie zuerst den folgenden Schalter hinzufügen, wenn Sie SvcUtil ausführen: /serializer:xmlserializer http://endpoint.
Im folgenden Code wird ein Beispiel der ClientBase-Klasse veranschaulicht.
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(); } }
Fügen Sie eine Klasse zum Instanziieren und Verwenden des Clientproxys hinzu.
Im folgenden Beispiel wird der Code veranschaulicht, durch den der Clientproxy aufgerufen wird.
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()); }
Erstellen Sie die Clientanwendung, und stellen Sie sie auf dem Gerät bereit.
Wenn der WCF-Dienst ausgeführt wird und Ihr Gerät mit dem Netzwerk verbunden ist, starten Sie die Clientanwendung auf dem Gerät.
Kompilieren des Codes
Der Quellcode für den WCF-Dienst erfordert Verweise auf die folgenden Namespaces:
Der Quellcode für die ClientBase-Klasse erfordert Verweise auf die folgenden Namespaces:
Der Quellcode für die Klasse, in der die Main-Methode in der Clientanwendung enthalten ist, erfordert Verweise auf die folgenden Namespaces:
Sicherheit
In diesem Beispiel werden keine WCF-Sicherheitsfeatures implementiert. Weitere Informationen über unterstützte Sicherheitsfeatures finden Sie unter Messaging in .NET Compact Framework.
Siehe auch
Konzepte
Messaging in .NET Compact Framework
Weitere Ressourcen
Windows Communication Foundation (WCF)-Entwicklung und .NET Compact Framework