Share via


Procedura: utilizzare il trasporto HTTP

Aggiornamento: novembre 2007

È possibile utilizzare il trasporto HTTP per creare applicazioni su un dispositivo che verrà connesso a un servizio Windows Communication Foundation (WCF) sul desktop.

In questo argomento viene descritto come configurare il servizio WCF per la gestione dei dispositivi di connessione e come creare l'applicazione client. Vengono illustrate le differenze tra la configurazione del servizio WCF e la codifica sul lato client di cui tener conto quando si abilitano i dispositivi mobili per la connessione al servizio. Per ulteriori informazioni sulla creazione di applicazioni WCF per il desktop, vedere la sezione Esercitazione introduttiva nella documentazione WCF.

Per creare il servizio WCF per il desktop

  1. Creare un nuovo progetto di servizio Web.

  2. Modificare il file Web.config come illustrato nell'esempio seguente. Modificare gli elementi e gli attributi seguenti nel file:

    • Modificare il valore dell'attributo <endpoint>binding con "basicHttpBinding". .NET Compact Framework supporta la codifica del testo, ma non quella binaria.

    • Modificare l'attributo behaviorConfiguration in modo che faccia riferimento al nuovo nome di comportamento.

    • Sostituire l'elemento <behavior> come illustrato nell'esempio.

    • Se è necessario registrare il gestore dei servizi HTTP nel file Web.config, aggiungere un nuovo elemento <system.WebServer> con le informazioni riportate nell'esempio.

    <?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. Nel codice sorgente per il servizio WCF rimuovere i parametri specificati per gli attributi ServiceContract e OperationContract.

    Nota:

    Nell'esempio non viene implementato il supporto per i parametri specificati nei contratti quali ServiceContract e OperationContract. Se per tali contratti è necessario il supporto per i parametri, è possibile utilizzare lo strumento WCF ServiceModel Utility (NetCFSvcUtil.exe) di .NET Compact Framework per generare il codice client. Tale strumento consente di compilare il supporto per molti di questi parametri nelle applicazioni basate su .NET Compact Framework. NetCFSvcUtil.exe è disponibile in Power Toys per .NET Compact Framework. Per ulteriori informazioni, vedere Power Toys for .NET Compact Framework (informazioni in lingua inglese).

    Nell'esempio riportato di seguito viene illustrato il codice sorgente del servizio WCF per un'applicazione calcolatrice semplificata.

    <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. Impostare il servizio WCF su una porta specifica sul server Web.

    Utilizzare qualsiasi numero di porta compreso tra 10000 e 650000. Nell'esempio viene utilizzata la porta 50505.

  5. Avviare il server Web.

    Se si desidera visualizzare l'output WSDL (Web Services Description Language) ed eseguire il servizio su localhost, immettere https://localhost:50505/CalculatorService/Service.svc?wsdl. Utilizzare lo stesso numero di porta e nome di progetto Web specificati per il servizio WCF.

  6. Se si intende connettersi al server Web da un dispositivo o un computer remoto, impostare una directory virtuale in modo che punti alla directory contenente il progetto Web.

    Nota:

    Il server di sviluppo ASP.NET di Visual Studio risponde solo alle richieste generate dal computer di sviluppo locale. Per specificare una directory virtuale, è consigliabile utilizzare Internet Information Services (IIS). In questo modo sarà possibile connettersi al server Web da un dispositivo remoto purché il server sia raggiungibile.

  7. Assicurarsi di poter accedere alla directory da un browser desktop e da un browser per dispositivi.

Per creare il client .NET Compact Framework

  1. Durante l'esecuzione del servizio, aprire una riga di comando e passare alla directory in cui si trova il servizio WCF.

  2. Dalla riga di comando eseguire lo strumento WCF Service Model Desktop Utility (SvcUtil.exe) per generare un proxy client WCF. Di seguito è riportato un esempio di chiamata a SvcUtil dalla riga di comando in cui il servizio è ospitato su localhost:

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

    Nell'esempio riportato di seguito è mostrato un proxy client generato da SvcUtil che si basa sull'esempio di calcolatrice semplificata.

    //------------------------------------------------------------------------------
    // <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. Rimuovere gli attributi e gli elementi non supportati dal codice proxy client generato, inclusi gli elementi seguenti:

    • Tutti gli attributi System.ServiceModel.

    • I riferimenti alla classe IClientChannel.

    • I riferimenti ai nomi di configurazione <endpoint>.

    • Le implementazioni di metodo che chiamano i metodi dell'interfaccia ServiceContract sul canale interno.

    Nell'esempio riportato di seguito viene illustrato il codice generato in seguito a queste modifiche.

    '------------------------------------------------------------------------------
    ' <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. Creare un progetto client.

  5. Aggiungere il proxy client generato al progetto.

  6. Nel codice proxy generato modificare il riferimento completo a ClientBase<TChannel> con la classe ClientBase definita dall'utente.

  7. Nel codice proxy generato aggiungere le implementazioni di metodo richiamando il metodo Call nella classe ClientBase definita dall'utente.

    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. Aggiungere la classe base per il proxy nel progetto. Tale classe si chiama ClientBase.

    Modificare il riferimento alla classe base del proxy client in modo che punti all'implementazione di ClientBase.

    Nota:

    In questo esempio la classe CustomBodyWriter di ClientBase supporta solo tipi primitivi. Per supportare tipi non primitivi è necessario estendere il metodo OnWriteBodyContents. È ad esempio possibile chiamare un serializzatore personalizzato per serializzare i dati dei messaggi. In questo caso è necessario convertire gli attributi del codice presenti nel proxy client generato in attributi utilizzabili dal serializzatore XML. In questo scenario è innanzitutto necessario aggiungere l'opzione /serializer:xmlserializer http://endpoint quando si esegue SvcUtil.

    Nel codice riportato di seguito viene illustrato un esempio di 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();
        }
    }
    
  9. Aggiungere una classe per creare un'istanza del proxy client e utilizzarlo.

    Nell'esempio di codice riportato di seguito viene illustrato il codice che consente di richiamare il 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());
    
    }
    
  10. Compilare l'applicazione client e distribuirla nel dispositivo.

  11. Mentre è in corso l'esecuzione del servizio WCF e il dispositivo è connesso in rete, avviare l'applicazione client sul dispositivo.

Compilazione del codice

Il codice sorgente per il servizio WCF richiede riferimenti agli spazi dei nomi seguenti:

Il codice sorgente per la classe ClientBase richiede riferimenti agli spazi dei nomi seguenti:

Il codice sorgente per la classe contenente il metodo Main nell'applicazione client richiede riferimenti agli spazi dei nomi seguenti:

Sicurezza

In questo esempio non sono implementate le funzionalità di sicurezza WCF. Per ulteriori informazioni sulle funzionalità di sicurezza supportate, vedere Messaggistica in .NET Compact Framework.

Vedere anche

Concetti

Messaggistica in .NET Compact Framework

Altre risorse

Sviluppo di Windows Communication Foundation (WCF) e .NET Compact Framework