Nota
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare ad accedere o a cambiare directory.
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare a cambiare directory.
L'esempio DeadLetter illustra come gestire ed elaborare i messaggi che hanno avuto esito negativo. Si basa sull'esempio dell'associazione transazionale MSMQ. 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.
Annotazioni
Questo esempio illustra ogni coda di messaggi non recapitabili dell'applicazione disponibile solo in Windows Vista. L'esempio può essere modificato per usare le code predefinite a livello di sistema per MSMQ 3.0 in Windows Server 2003 e Windows XP.
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.
Poiché la comunicazione in coda può comportare una certa quantità di inattività, si potrebbe voler associare un valore di tempo di vita al messaggio per assicurarsi che il messaggio non venga recapitato all'applicazione se è trascorso il periodo di validità. Esistono anche casi in cui un'applicazione deve essere informata se il recapito di un messaggio non è riuscito. In tutti questi casi, ad esempio quando il time-to-live sul messaggio è scaduto o il recapito del messaggio non è riuscito, il messaggio viene inserito in una coda di messaggi non recapitabili. L'applicazione di invio può quindi leggere i messaggi nella coda dei messaggi non recapitabili ed eseguire azioni correttive che vanno da nessuna azione alla correzione dei motivi per il recapito non riuscito e il reinvio del messaggio.
La coda di messaggi non recapitabili nell'associazione NetMsmqBinding è espressa nelle proprietà seguenti:
DeadLetterQueue per esprimere il tipo di coda di messaggi non recapitabili richiesti dal client. Questa enumerazione ha i valori seguenti:
None: Nessuna coda di messaggi non recapitabili è richiesta dal client.System: La system dead-letter queue viene usata per archiviare i messaggi non recapitabili. La coda di messaggi non recapitabili del sistema è condivisa da tutte le applicazioni in esecuzione nel computer.Custom: una coda di messaggi non recapitabili personalizzata, specificata tramite la proprietà CustomDeadLetterQueue, viene usata per archiviare messaggi non recapitabili. Questa funzionalità è disponibile solo in Windows Vista. Viene usato quando l'applicazione deve usare la propria coda di messaggi morti anziché condividerla con altre applicazioni in esecuzione sullo stesso computer.CustomDeadLetterQueue per esprimere la coda specifica da usare come coda di messaggi non recapitabili. Questa opzione è disponibile solo in Windows Vista.
In questo esempio, il client invia un batch di messaggi al servizio dall'interno dell'ambito di una transazione e specifica un valore arbitrariamente basso per questi messaggi (circa 2 secondi). Il client specifica anche una coda di messaggi non consegnati personalizzata per mettere in coda i messaggi scaduti.
L'applicazione client può leggere i messaggi nella coda dei messaggi non recapitabili e riprovare a inviare il messaggio o correggere l'errore che ha causato l'immissione del messaggio originale nella coda dei messaggi non recapitabili e inviare il messaggio. Nell'esempio il client visualizza un messaggio di errore.
Il contratto di servizio è IOrderProcessor, come illustrato nel codice di esempio seguente.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true)]
void SubmitPurchaseOrder(PurchaseOrder po);
}
Il codice del servizio nell'esempio è quello dell'associazione MSMQ transazionata.
La comunicazione con il servizio viene eseguita nell'ambito di una transazione. Il servizio legge i messaggi dalla coda, esegue l'operazione e quindi visualizza i risultati dell'operazione. L'applicazione crea anche una coda di lettere morte per i messaggi non recapitabili.
//The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.
//Client implementation code.
class Client
{
static void Main()
{
// Get MSMQ queue name from app settings in configuration
string deadLetterQueueName = ConfigurationManager.AppSettings["deadLetterQueueName"];
// Create the transacted MSMQ queue for storing dead message if necessary.
if (!MessageQueue.Exists(deadLetterQueueName))
MessageQueue.Create(deadLetterQueueName, true);
// Create a proxy with given client endpoint configuration
OrderProcessorClient client = new OrderProcessorClient("OrderProcessorEndpoint");
// Create the purchase order
PurchaseOrder po = new PurchaseOrder();
po.CustomerId = "somecustomer.com";
po.PONumber = Guid.NewGuid().ToString();
PurchaseOrderLineItem lineItem1 = new PurchaseOrderLineItem();
lineItem1.ProductId = "Blue Widget";
lineItem1.Quantity = 54;
lineItem1.UnitCost = 29.99F;
PurchaseOrderLineItem lineItem2 = new PurchaseOrderLineItem();
lineItem2.ProductId = "Red Widget";
lineItem2.Quantity = 890;
lineItem2.UnitCost = 45.89F;
po.orderLineItems = new PurchaseOrderLineItem[2];
po.orderLineItems[0] = lineItem1;
po.orderLineItems[1] = lineItem2;
//Create a transaction scope.
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
// Make a queued call to submit the purchase order
client.SubmitPurchaseOrder(po);
// Complete the transaction.
scope.Complete();
}
client.Close();
Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
}
}
La configurazione del client specifica un tempo breve perché il messaggio raggiunga il servizio. Se il messaggio non può essere trasmesso entro la durata specificata, il messaggio scade e viene spostato nella coda dei messaggi non recapitabili.
Annotazioni
È possibile che il client recapita il messaggio alla coda del servizio entro l'ora specificata. Per assicurarsi di vedere il servizio di gestione dei messaggi non recapitabili in azione, è necessario eseguire il client prima di avviare il servizio. Il messaggio va in timeout e viene recapitato al servizio di messaggistica per lettere morte.
L'applicazione deve definire quale coda utilizzare come coda di messaggi non recapitabili. Se non viene specificata alcuna coda, la coda predefinita a livello di sistema per i messaggi non recapitabili transazionali viene utilizzata per accodare i messaggi non recapitabili. In questo esempio, l'applicazione client specifica la propria coda di messaggi non recapitabili.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- use appSetting to configure MSMQ Dead Letter queue name -->
<add key="deadLetterQueueName" value=".\private$\ServiceModelSamplesOrdersAppDLQ"/>
</appSettings>
<system.serviceModel>
<client>
<!-- Define NetMsmqEndpoint -->
<endpoint name="OrderProcessorEndpoint"
address="net.msmq://localhost/private/ServiceModelSamplesDeadLetter"
binding="netMsmqBinding"
bindingConfiguration="PerAppDLQBinding"
contract="IOrderProcessor" />
</client>
<bindings>
<netMsmqBinding>
<binding name="PerAppDLQBinding"
deadLetterQueue="Custom"
customDeadLetterQueue="net.msmq://localhost/private/ServiceModelSamplesOrdersAppDLQ"
timeToLive="00:00:02"/>
</netMsmqBinding>
</bindings>
</system.serviceModel>
</configuration>
Il servizio messaggi non recapitabili legge i messaggi dalla coda di messaggi non recapitabili. Il servizio di messaggi non recapitabili implementa il contratto IOrderProcessor. La sua implementazione, tuttavia, non consiste nell'elaborare gli ordini. Il servizio messaggi non recapitabili è un servizio client e non dispone della funzionalità per elaborare gli ordini.
Annotazioni
La coda dei messaggi non recapitabili è una coda client ed è locale per il gestore di code del client.
L'implementazione del servizio messaggi non recapitabili verifica il motivo del mancato recapito di un messaggio e adotta provvedimenti correttivi. Il motivo di un errore del messaggio viene acquisito in due enumerazioni e DeliveryFailureDeliveryStatus. È possibile recuperare il MsmqMessageProperty dal OperationContext come illustrato nel codice di esempio seguente.
public void SubmitPurchaseOrder(PurchaseOrder po)
{
Console.WriteLine("Submitting purchase order did not succeed ", po);
MsmqMessageProperty mqProp =
OperationContext.Current.IncomingMessageProperties[
MsmqMessageProperty.Name] as MsmqMessageProperty;
Console.WriteLine("Message Delivery Status: {0} ",
mqProp.DeliveryStatus);
Console.WriteLine("Message Delivery Failure: {0}",
mqProp.DeliveryFailure);
Console.WriteLine();
…
}
I messaggi nella coda dei messaggi non consegnati sono messaggi indirizzati al servizio che elabora i messaggi. Pertanto, quando il servizio di gestione dei messaggi non recapitabili legge i messaggi dalla coda, il livello del canale Windows Communication Foundation (WCF) rileva la mancata corrispondenza negli endpoint e non inoltra il messaggio. In questo caso, il messaggio viene indirizzato al servizio di elaborazione degli ordini, ma viene ricevuto dal servizio messaggi non recapitabili. Per ricevere un messaggio indirizzato a un endpoint diverso, viene specificato un filtro di indirizzo in modo che corrisponda a qualsiasi indirizzo in ServiceBehavior. Questa operazione è necessaria per elaborare correttamente i messaggi letti dalla coda di messaggi non recapitabili.
In questo esempio, il servizio di messaggi non recapitabili invia nuovamente il messaggio se il motivo dell'errore è che il messaggio è scaduto. Per tutti gli altri motivi, si visualizza l'errore di consegna, come mostrato nel seguente esempio di codice.
// Service class that implements the service contract.
// Added code to write output to the console window.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Single, AddressFilterMode=AddressFilterMode.Any)]
public class PurchaseOrderDLQService : IOrderProcessor
{
OrderProcessorClient orderProcessorService;
public PurchaseOrderDLQService()
{
orderProcessorService = new OrderProcessorClient("OrderProcessorEndpoint");
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po)
{
Console.WriteLine("Submitting purchase order did not succeed ", po);
MsmqMessageProperty mqProp = OperationContext.Current.IncomingMessageProperties[MsmqMessageProperty.Name] as MsmqMessageProperty;
Console.WriteLine("Message Delivery Status: {0} ", mqProp.DeliveryStatus);
Console.WriteLine("Message Delivery Failure: {0}", mqProp.DeliveryFailure);
Console.WriteLine();
// resend the message if timed out
if (mqProp.DeliveryFailure == DeliveryFailure.ReachQueueTimeout ||
mqProp.DeliveryFailure == DeliveryFailure.ReceiveTimeout)
{
// re-send
Console.WriteLine("Purchase order Time To Live expired");
Console.WriteLine("Trying to resend the message");
// reuse the same transaction used to read the message from dlq to enqueue the message to app. queue
orderProcessorService.SubmitPurchaseOrder(po);
Console.WriteLine("Purchase order resent");
}
}
// Host the service within this EXE console application.
public static void Main()
{
// Create a ServiceHost for the PurchaseOrderDLQService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(PurchaseOrderDLQService)))
{
// Open the ServiceHostBase to create listeners and start listening for messages.
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The dead letter service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
}
}
}
L'esempio seguente illustra la configurazione per un messaggio non recapitato:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service
name="Microsoft.ServiceModel.Samples.PurchaseOrderDLQService">
<!-- Define NetMsmqEndpoint in this case, DLQ end point to read messages-->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesOrdersAppDLQ"
binding="netMsmqBinding"
bindingConfiguration="DefaultBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
</service>
</services>
<client>
<!-- Define NetMsmqEndpoint -->
<endpoint name="OrderProcessorEndpoint"
address="net.msmq://localhost/private/ServiceModelSamplesDeadLetter"
binding="netMsmqBinding"
bindingConfiguration="SystemDLQBinding"
contract="IOrderProcessor" />
</client>
<bindings>
<netMsmqBinding>
<binding name="DefaultBinding" />
<binding name="SystemDLQBinding"
deadLetterQueue="System"/>
</netMsmqBinding>
</bindings>
</system.serviceModel>
</configuration>
Nell'esecuzione dell'esempio sono disponibili 3 eseguibili da eseguire per vedere come funziona la coda dei messaggi non recapitabili per ogni applicazione; il client, il servizio e un servizio di messaggi non recapitabili che legge dalla coda dei messaggi non recapitabili per ogni applicazione e invia nuovamente il messaggio al servizio. Tutte sono applicazioni console con output nelle finestre della console.
Annotazioni
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. Dovresti avviare il servizio e arrestarlo in modo che la coda possa essere creata.
Quando si esegue il client, il client visualizza il messaggio:
Press <ENTER> to terminate client.
Il client ha tentato di inviare il messaggio, ma a causa di un breve timeout, il messaggio è scaduto ed è ora inserito nella coda dei messaggi non recapitabili per ogni applicazione.
Esegui quindi il servizio di dead-letter, che legge il messaggio, visualizza il codice di errore e invia nuovamente il messaggio al servizio.
The dead letter service is ready.
Press <ENTER> to terminate service.
Submitting purchase order did not succeed
Message Delivery Status: InDoubt
Message Delivery Failure: ReachQueueTimeout
Purchase order Time To Live expired
Trying to resend the message
Purchase order resent
Il servizio viene avviato e quindi rilegge il messaggio e lo elabora.
The service is ready.
Press <ENTER> to terminate service.
Processing Purchase Order: 97897eff-f926-4057-a32b-af8fb11b9bf9
Customer: somecustomer.com
OrderDetails
Order LineItem: 54 of Blue Widget @unit price: $29.99
Order LineItem: 890 of Red Widget @unit price: $45.89
Total cost of this order: $42461.56
Order status: Pending
Per configurare, compilare ed eseguire l'esempio
Assicurati di aver eseguito la procedura di installazione di One-Time per gli esempi di Windows Communication Foundation.
Se il servizio viene eseguito per primo, verifica che la coda sia presente. Se la coda non è presente, il servizio ne creerà uno. È possibile eseguire prima il servizio per creare la coda oppure crearne una tramite Gestione code MSMQ. Seguire questa procedura per creare una coda in Windows 2008.
Aprire Server Manager in Visual Studio 2012.
Espandi la scheda funzionalità.
Fare clic con il pulsante destro del mouse code di messaggi privati e selezionare Nuovo, coda privata.
Selezionare la casella transazionale.
Inserire
ServiceModelSamplesTransactedcome nome della nuova coda.
Per compilare l'edizione C# o Visual Basic .NET della soluzione, seguire le istruzioni in Compilazione degli esempi di Windows Communication Foundation.
Per eseguire l'esempio in una configurazione singola o tra computer, modifica i nomi delle code in modo appropriato, sostituendo "localhost" con il nome completo del computer, e segui le istruzioni in Esecuzione degli esempi di Windows Communication Foundation.
Per eseguire l'esempio in un computer aggiunto a un gruppo di lavoro
Se il computer non fa parte di un dominio, disattivare la sicurezza del trasporto impostando la modalità di autenticazione e il livello di protezione su
Nonecome illustrato nella configurazione di esempio seguente:<bindings> <netMsmqBinding> <binding name="TransactedBinding"> <security mode="None"/> </binding> </netMsmqBinding> </bindings>Verificare che l'endpoint sia associato all'associazione impostando l'attributo dell'endpoint
bindingConfiguration.Assicurarsi di modificare la configurazione in DeadLetterService, nel server e nel client prima di eseguire l'esempio.
Annotazioni
L'impostazione di
security modesuNoneequivale all'impostazione della sicurezza diMsmqAuthenticationMode,MsmqProtectionLeveleMessagesuNone.
Commenti
Per impostazione predefinita con il binding di trasporto netMsmqBinding, la sicurezza è abilitata. Due proprietà, MsmqAuthenticationMode e MsmqProtectionLevel, insieme determinano il tipo di sicurezza del trasporto. 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. Se si esegue questo esempio in un computer che non fa parte di un dominio, viene visualizzato l'errore seguente: "Il certificato di accodamento messaggi interno dell'utente non esiste".