Condividi tramite


Sessioni e code

L'esempio di sessione illustra come inviare e ricevere un set di messaggi correlati nella comunicazione in coda tramite il trasporto msmq (Message Queuing). In questo esempio viene utilizzata l'associazione netMsmqBinding . Il servizio è un'applicazione console autogestita che permette di osservare la ricezione di messaggi in coda da parte del servizio.

Annotazioni

La procedura di installazione e le istruzioni di compilazione per questo esempio si trovano alla fine di questo argomento.

Nella comunicazione in coda, il client comunica con il servizio usando una coda. Più precisamente, il client invia messaggi a una coda. Il servizio riceve messaggi dalla coda. Non è quindi necessario che il servizio e il client siano in esecuzione contemporaneamente per comunicare tramite una coda.

In alcuni casi, un client invia un set di messaggi correlati l'uno all'altro in un gruppo. Quando i messaggi devono essere elaborati insieme o in un ordine specificato, una coda può essere usata per raggrupparli, per l'elaborazione da parte di una singola applicazione ricevente. Ciò è particolarmente importante quando sono presenti diverse applicazioni riceventi in un gruppo di server ed è necessario assicurarsi che un gruppo di messaggi venga elaborato dalla stessa applicazione ricevente. Le sessioni in coda sono un meccanismo usato per inviare e ricevere un set correlato di messaggi che devono essere elaborati tutti contemporaneamente. Le sessioni in coda richiedono una transazione per seguire questo schema.

Nell'esempio, il client invia un numero di messaggi al servizio come parte di una sessione nell'ambito di una singola transazione.

Il contratto di servizio è IOrderTaker, che definisce un servizio unidirezionale adatto per l'uso con le code. L'oggetto SessionMode utilizzato nel contratto illustrato nel codice di esempio seguente indica che i messaggi fanno parte della sessione.

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required)]
public interface IOrderTaker
{
    [OperationContract(IsOneWay = true)]
    void OpenPurchaseOrder(string customerId);

    [OperationContract(IsOneWay = true)]
    void AddProductLineItem(string productId, int quantity);

    [OperationContract(IsOneWay = true)]
    void EndPurchaseOrder();
}

Il servizio definisce le operazioni del servizio in modo che la prima operazione venga inserita in una transazione, ma non completa automaticamente la transazione. Anche le operazioni successive si integrano nella stessa transazione, ma non vengono completate automaticamente. L'ultima operazione nella sessione completa automaticamente la transazione. Pertanto, la stessa transazione viene usata per diverse chiamate di operazione nel contratto di servizio. Se una delle operazioni genera un'eccezione, la transazione esegue il rollback e la sessione viene reinserita nella coda. Al termine dell'ultima operazione con successo, viene eseguito il commit della transazione. Il servizio usa PerSession come InstanceContextMode per ricevere tutti i messaggi in una sessione nella stessa istanza del servizio.

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class OrderTakerService : IOrderTaker
{
    PurchaseOrder po;

    [OperationBehavior(TransactionScopeRequired = true,
                                 TransactionAutoComplete = false)]
    public void OpenPurchaseOrder(string customerId)
    {
        Console.WriteLine("Creating purchase order");
        po = new PurchaseOrder(customerId);
    }

    [OperationBehavior(TransactionScopeRequired = true,
                                  TransactionAutoComplete = false)]
    public void AddProductLineItem(string productId, int quantity)
    {
        po.AddProductLineItem(productId, quantity);
        Console.WriteLine("Product " + productId + " quantity " +
                            quantity + " added to purchase order");
    }

    [OperationBehavior(TransactionScopeRequired = true,
                                  TransactionAutoComplete = true)]
    public void EndPurchaseOrder()
    {
       Console.WriteLine("Purchase Order Completed");
       Console.WriteLine();
       Console.WriteLine(po.ToString());
    }
}

Il servizio è autogestito. Quando si usa il trasporto MSMQ, la coda usata deve essere creata in anticipo. Questa operazione può essere eseguita manualmente o tramite il codice. In questo esempio, il servizio contiene il codice System.Messaging per verificare l'esistenza della coda e crearla, se necessario. Il nome della coda viene letto dal file di configurazione utilizzando la classe AppSettings.

// Host the service within this EXE console application.
public static void Main()
{
    // Get MSMQ queue name from app settings in configuration.
    string queueName = ConfigurationManager.AppSettings["queueName"];

    // Create the transacted MSMQ queue if necessary.
    if (!MessageQueue.Exists(queueName))
        MessageQueue.Create(queueName, true);

    // Create a ServiceHost for the OrderTakerService type.
    using (ServiceHost serviceHost = new ServiceHost(typeof(OrderTakerService)))
    {
        // Open the ServiceHost to create listeners and start listening for messages.
        serviceHost.Open();

        // The service can now be accessed.
        Console.WriteLine("The service is ready.");
        Console.WriteLine("Press <ENTER> to terminate service.");
        Console.WriteLine();
        Console.ReadLine();

        // Close the ServiceHost to shutdown the service.
        serviceHost.Close();
    }
}

Il nome della coda MSMQ viene specificato in una sezione appSettings del file di configurazione. L'endpoint per il servizio viene definito nella sezione system.serviceModel del file di configurazione e specifica l'associazione netMsmqBinding .

<appSettings>
  <!-- Use appSetting to configure MSMQ queue name. -->
  <add key="queueName" value=".\private$\ServiceModelSamplesSession" />
</appSettings>

<system.serviceModel>
  <services>
    <service name="Microsoft.ServiceModel.Samples.OrderTakerService"
        behaviorConfiguration="CalculatorServiceBehavior">
      ...
      <!-- Define NetMsmqEndpoint -->
      <endpoint address="net.msmq://localhost/private/ServiceModelSamplesSession"
                binding="netMsmqBinding"
                contract="Microsoft.ServiceModel.Samples.IOrderTaker" />
      ...
    </service>
  </services>
  ...
</system.serviceModel>

Il client crea un ambito di transazione. Tutti i messaggi nella sessione vengono inviati alla coda all'interno dell'ambito della transazione, causandone la gestione come un'unità atomica in cui tutti i messaggi hanno esito positivo o negativo. Il commit della transazione viene eseguito chiamando Complete.

//Create a transaction scope.
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
    // Create a client with given client endpoint configuration.
    OrderTakerClient client = new OrderTakerClient("OrderTakerEndpoint");
    // Open a purchase order.
    client.OpenPurchaseOrder("somecustomer.com");
    Console.WriteLine("Purchase Order created");

    // Add product line items.
    Console.WriteLine("Adding 10 quantities of blue widget");
    client.AddProductLineItem("Blue Widget", 10);

    Console.WriteLine("Adding 23 quantities of red widget");
    client.AddProductLineItem("Red Widget", 23);

    // Close the purchase order.
    Console.WriteLine("Closing the purchase order");
    client.EndPurchaseOrder();

    //Closing the client gracefully closes the connection and cleans up resources.
    client.Close();

    // Complete the transaction.
    scope.Complete();
}

Annotazioni

È possibile usare solo una singola transazione per tutti i messaggi nella sessione e tutti i messaggi nella sessione devono essere inviati prima di eseguire il commit della transazione. La chiusura del client chiude la sessione. Pertanto, il client deve essere chiuso prima che la transazione sia completata per poter inviare tutti i messaggi della sessione alla coda.

Quando si esegue l'esempio, le attività client e di servizio vengono visualizzate sia nelle finestre del servizio che della console client. È possibile visualizzare il servizio che riceve messaggi dal client. Premere INVIO in ogni finestra della console per spegnere il servizio e il client. Poiché l'accodamento è in uso, il client e il servizio non devono essere operativi contemporaneamente. È possibile eseguire il client, arrestarlo, e poi avviare il servizio, il quale riceverà comunque i suoi messaggi.

Sul cliente.

Purchase Order created
Adding 10 quantities of blue widget
Adding 23 quantities of red widget
Closing the purchase order

Press <ENTER> to terminate client.

Nel servizio.

The service is ready.
Press <ENTER> to terminate service.

Creating purchase order
Product Blue Widget quantity 10 added to purchase order
Product Red Widget quantity 23 added to purchase order
Purchase Order Completed

Purchase Order: 7c86fef0-2306-4c51-80e6-bcabcc1a6e5e
        Customer: somecustomer.com
        OrderDetails
                Order LineItem: 10 of Blue Widget @unit price: $2985
                Order LineItem: 23 of Red Widget @unit price: $156
        Total cost of this order: $33438
        Order status: Pending

Configurare, compilare ed eseguire l'esempio

  1. Assicurati di aver eseguito la procedura di installazione di One-Time per gli esempi di Windows Communication Foundation.

  2. Per compilare l'edizione C#, C++o Visual Basic .NET della soluzione, seguire le istruzioni in Compilazione degli esempi di Windows Communication Foundation.

  3. Per eseguire l'esempio in una configurazione con computer singolo o incrociato, seguire le istruzioni riportate in Esecuzione degli esempi di Windows Communication Foundation.

Per impostazione predefinita con il NetMsmqBinding, la sicurezza del trasporto è abilitata. Esistono due proprietà rilevanti per la sicurezza del trasporto MSMQ e MsmqAuthenticationModeMsmqProtectionLevel. Per impostazione predefinita, la modalità di autenticazione è impostata su Windows e il livello di protezione è impostato su .Sign Affinché MSMQ fornisca la funzionalità di autenticazione e firma, deve far parte di un dominio e deve essere installata l'opzione di integrazione di Active Directory per MSMQ. Se si esegue questo esempio in un computer che non soddisfa questi criteri, viene visualizzato un errore.

Eseguire l'esempio in un computer aggiunto a un gruppo di lavoro

  1. Se il computer non fa parte di un dominio o non dispone dell'integrazione di Active Directory installata, disattivare la sicurezza del trasporto impostando la modalità di autenticazione e il livello di protezione su None come illustrato nella configurazione di esempio seguente.

    <system.serviceModel>
      <services>
        <service name="Microsoft.ServiceModel.Samples.OrderTakerService"
                 behaviorConfiguration="OrderTakerServiceBehavior">
          <host>
            <baseAddresses>
              <add baseAddress=
             "http://localhost:8000/ServiceModelSamples/service"/>
            </baseAddresses>
          </host>
          <!-- Define NetMsmqEndpoint -->
          <endpoint
              address=
            "net.msmq://localhost/private/ServiceModelSamplesSession"
              binding="netMsmqBinding"
              bindingConfiguration="Binding1"
           contract="Microsoft.ServiceModel.Samples.IOrderTaker" />
          <!-- The mex endpoint is exposed at-->
          <!--http://localhost:8000/ServiceModelSamples/service/mex. -->
          <endpoint address="mex"
                    binding="mexHttpBinding"
                    contract="IMetadataExchange" />
        </service>
      </services>
    
      <bindings>
        <netMsmqBinding>
          <binding name="Binding1">
            <security mode="None" />
          </binding>
        </netMsmqBinding>
      </bindings>
    
        <behaviors>
          <serviceBehaviors>
            <behavior name="OrderTakerServiceBehavior">
              <serviceMetadata httpGetEnabled="True"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    
      </system.serviceModel>
    
  2. Assicurarsi di modificare la configurazione sia nel server che nel client prima di eseguire l'esempio.

    Annotazioni

    L'impostazione della modalità di sicurezza su None equivale all'impostazione MsmqAuthenticationModedi , MsmqProtectionLevele Message della sicurezza su None.