Hantering av giftmeddelanden i MSMQ 4.0
MSMQ4-exemplet visar hur du utför hantering av giftmeddelanden i en tjänst. Det här exemplet baseras på transacted MSMQ-bindningsexemplet . I det här exemplet används netMsmqBinding
. Tjänsten är ett konsolprogram med egen värd som gör att du kan observera att tjänsten tar emot köade meddelanden.
I kökommunikation kommunicerar klienten till tjänsten med hjälp av en kö. Mer exakt skickar klienten meddelanden till en kö. Tjänsten tar emot meddelanden från kön. Tjänsten och klienten behöver därför inte köras samtidigt för att kommunicera med en kö.
Ett giftmeddelande är ett meddelande som läss upprepade gånger från en kö när tjänsten som läser meddelandet inte kan bearbeta meddelandet och därför avslutar transaktionen under vilken meddelandet läss. I sådana fall görs ett nytt försök med meddelandet. Detta kan teoretiskt sett fortsätta för alltid om det finns ett problem med meddelandet. Detta kan bara inträffa när du använder transaktioner för att läsa från kön och anropa tjänståtgärden.
Baserat på versionen av MSMQ stöder NetMsmqBinding begränsad identifiering till fullständig identifiering av giftmeddelanden. När meddelandet har identifierats som förgiftat kan det hanteras på flera sätt. Återigen, baserat på versionen av MSMQ, stöder NetMsmqBinding begränsad hantering till fullständig hantering av giftmeddelanden.
Det här exemplet illustrerar de begränsade giftanläggningar som tillhandahålls på Windows Server 2003 och Windows XP-plattformen och de fullständiga giftanläggningarna som tillhandahålls i Windows Vista. I båda exemplen är målet att flytta giftmeddelandet från kön till en annan kö. Kön kan sedan betjänas av en tjänst för giftmeddelanden.
MSMQ v4.0 Gifthanteringsexempel
I Windows Vista tillhandahåller MSMQ en giftunderfråga som kan användas för att lagra giftmeddelanden. Det här exemplet visar bästa praxis för att hantera giftmeddelanden med hjälp av Windows Vista.
Identifieringen av giftmeddelanden i Windows Vista är sofistikerad. Det finns tre egenskaper som hjälper till med identifiering. Antalet ReceiveRetryCount gånger ett visst meddelande läss om från kön och skickas till programmet för bearbetning. Ett meddelande läss på nytt från kön när det sätts tillbaka i kön eftersom meddelandet inte kan skickas till programmet eller programmet återställer transaktionen i tjänståtgärden. MaxRetryCycles är antalet gånger meddelandet flyttas till kön för återförsök. När ReceiveRetryCount har nåtts flyttas meddelandet till kön för återförsök. Egenskapen RetryCycleDelay är den tidsfördröjning efter vilken meddelandet flyttas från återförsökskön tillbaka till huvudkön. ReceiveRetryCount Återställs till 0. Meddelandet provas igen. Om alla försök att läsa meddelandet har misslyckats markeras meddelandet som förgiftat.
När meddelandet har markerats som förgiftat hanteras meddelandet enligt inställningarna i ReceiveErrorHandling uppräkningen. Så här upprepar du de möjliga värdena:
Fel (standard): Fel på lyssnaren och även tjänstvärden.
Släpp: Så här släpper du meddelandet.
Flytta: Flytta meddelandet till underfrågan giftmeddelande. Det här värdet är endast tillgängligt i Windows Vista.
Avvisa: Om du vill avvisa meddelandet skickar du tillbaka meddelandet till avsändarens kö med obeställbara meddelanden. Det här värdet är endast tillgängligt i Windows Vista.
Exemplet visar hur du använder borttagningen Move
för giftmeddelandet. Move
leder till att meddelandet flyttas till giftunderfrågan.
Tjänstkontraktet är IOrderProcessor
, som definierar en enkelriktad tjänst som är lämplig för användning med köer.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true)]
void SubmitPurchaseOrder(PurchaseOrder po);
}
Tjänståtgärden visar ett meddelande om att den bearbetar ordern. För att demonstrera funktionen för giftmeddelanden utlöser tjänståtgärden SubmitPurchaseOrder
ett undantag för att återställa transaktionen vid ett slumpmässigt anrop av tjänsten. Detta gör att meddelandet sätts tillbaka i kön. Så småningom markeras meddelandet som gift. Konfigurationen är inställd på att flytta giftmeddelandet till giftunderfrågan.
// Service class that implements the service contract.
// Added code to write output to the console window.
public class OrderProcessorService : IOrderProcessor
{
static Random r = new Random(137);
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po)
{
int randomNumber = r.Next(10);
if (randomNumber % 2 == 0)
{
Orders.Add(po);
Console.WriteLine("Processing {0} ", po);
}
else
{
Console.WriteLine("Aborting transaction, cannot process purchase order: " + po.PONumber);
Console.WriteLine();
throw new Exception("Cannot process purchase order: " + po.PONumber);
}
}
public static void OnServiceFaulted(object sender, EventArgs e)
{
Console.WriteLine("Service Faulted");
}
// 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 (!System.Messaging.MessageQueue.Exists(queueName))
System.Messaging.MessageQueue.Create(queueName, true);
// Get the base address that is used to listen for WS-MetaDataExchange requests.
// This is useful to generate a proxy for the client.
string baseAddress = ConfigurationManager.AppSettings["baseAddress"];
// Create a ServiceHost for the OrderProcessorService type.
ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService), new Uri(baseAddress));
// Hook on to the service host faulted events.
serviceHost.Faulted += new EventHandler(OnServiceFaulted);
// Open the ServiceHostBase 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();
if(serviceHost.State != CommunicationState.Faulted) {
serviceHost.Close();
}
}
}
Tjänstkonfigurationen innehåller följande egenskaper för giftmeddelanden: receiveRetryCount
, maxRetryCycles
, retryCycleDelay
och receiveErrorHandling
som visas i följande konfigurationsfil.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- Use appSetting to configure MSMQ queue name. -->
<add key="queueName" value=".\private$\ServiceModelSamplesPoison" />
<add key="baseAddress" value="http://localhost:8000/orderProcessor/poisonSample"/>
</appSettings>
<system.serviceModel>
<services>
<service
name="Microsoft.ServiceModel.Samples.OrderProcessorService">
<!-- Define NetMsmqEndpoint -->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesPoison"
binding="netMsmqBinding"
bindingConfiguration="PoisonBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
</service>
</services>
<bindings>
<netMsmqBinding>
<binding name="PoisonBinding"
receiveRetryCount="0"
maxRetryCycles="1"
retryCycleDelay="00:00:05"
receiveErrorHandling="Move">
</binding>
</netMsmqBinding>
</bindings>
</system.serviceModel>
</configuration>
Bearbeta meddelanden från giftmeddelandekön
Tjänsten för giftmeddelanden läser meddelanden från den slutliga giftmeddelandekön och bearbetar dem.
Meddelanden i kön för giftmeddelanden är meddelanden som är adresserade till tjänsten som bearbetar meddelandet, vilket kan skilja sig från tjänstslutpunkten för giftmeddelandet. När tjänsten för giftmeddelanden läser meddelanden från kön hittar WCF-kanallagret därför matchningen i slutpunkter och skickar inte meddelandet. I det här fallet är meddelandet adresserat till orderbearbetningstjänsten men tas emot av tjänsten för giftmeddelande. Om du vill fortsätta att ta emot meddelandet även om meddelandet är adresserat till en annan slutpunkt måste vi lägga till en ServiceBehavior
för att filtrera adresser där matchningskriteriet är att matcha alla tjänstslutpunkter som meddelandet är adresserat till. Detta krävs för att bearbeta meddelanden som du läser från giftmeddelandekön.
Själva implementeringen av tjänsten poison message liknar tjänstimplementeringen. Det implementerar kontraktet och bearbetar beställningarna. Kodexemplet är följande.
// Service class that implements the service contract.
// Added code to write output to the console window.
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
public class OrderProcessorService : IOrderProcessor
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po)
{
Orders.Add(po);
Console.WriteLine("Processing {0} ", po);
}
public static void OnServiceFaulted(object sender, EventArgs e)
{
Console.WriteLine("Service Faulted...exiting app");
Environment.Exit(1);
}
// Host the service within this EXE console application.
public static void Main()
{
// Create a ServiceHost for the OrderProcessorService type.
ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService));
// Hook on to the service host faulted events.
serviceHost.Faulted += new EventHandler(OnServiceFaulted);
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The poison message service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
// Close the ServiceHostBase to shutdown the service.
if(serviceHost.State != CommunicationState.Faulted)
{
serviceHost.Close();
}
}
Till skillnad från orderbearbetningstjänsten som läser meddelanden från orderkön läser tjänsten giftmeddelande meddelanden från underfrågan gift. Giftkön är en underfråga i huvudkön, heter "gift" och genereras automatiskt av MSMQ. För att komma åt den anger du huvudkönamnet följt av ett ";" och underfrågans namn, i det här fallet -"poison", som visas i följande exempelkonfiguration.
Kommentar
I exemplet för MSMQ v3.0 är namnet på giftkön inte en underkö, snarare kön som vi flyttade meddelandet till.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="Microsoft.ServiceModel.Samples.OrderProcessorService">
<!-- Define NetMsmqEndpoint -->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesPoison;poison"
binding="netMsmqBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor" >
</endpoint>
</service>
</services>
</system.serviceModel>
</configuration>
När du kör exemplet visas aktiviteterna för klient-, tjänst- och giftmeddelandetjänsten i konsolfönster. Du kan se att tjänsten tar emot meddelanden från klienten. Tryck på RETUR i varje konsolfönster för att stänga av tjänsterna.
Tjänsten börjar köra, bearbeta beställningar och börjar slumpmässigt avsluta bearbetningen. Om meddelandet anger att det har bearbetat beställningen kan du köra klienten igen för att skicka ett annat meddelande tills du ser att tjänsten faktiskt har avslutat ett meddelande. Baserat på de konfigurerade giftinställningarna provas meddelandet en gång för bearbetning innan det flyttas till den slutliga giftkön.
The service is ready.
Press <ENTER> to terminate service.
Processing Purchase Order: 0f063b71-93e0-42a1-aa3b-bca6c7a89546
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
Processing Purchase Order: 5ef9a4fa-5a30-4175-b455-2fb1396095fa
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
Aborting transaction, cannot process purchase order: 23e0b991-fbf9-4438-a0e2-20adf93a4f89
Starta tjänsten för giftmeddelande för att läsa det förgiftade meddelandet från giftkön. I det här exemplet läser tjänsten giftmeddelande meddelandet och bearbetar det. Du kan se att inköpsordern som avslutades och förgiftades läses av tjänsten för giftmeddelande.
The service is ready.
Press <ENTER> to terminate service.
Processing Purchase Order: 23e0b991-fbf9-4438-a0e2-20adf93a4f89
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
Så här konfigurerar du, skapar och kör exemplet
Kontrollera att du har utfört engångsinstallationsproceduren för Windows Communication Foundation-exempel.
Om tjänsten körs först kontrollerar den att kön finns. Om kön inte finns skapar tjänsten en. Du kan köra tjänsten först för att skapa kön, eller så kan du skapa en via MSMQ Queue Manager. Följ de här stegen för att skapa en kö i Windows 2008.
Öppna Serverhanteraren i Visual Studio 2012.
Expandera fliken Funktioner .
Högerklicka på Privata meddelandeköer och välj Ny privat kö.
Markera rutan Transaktionell .
Ange
ServiceModelSamplesTransacted
som namnet på den nya kön.
Om du vill skapa C# eller Visual Basic .NET-versionen av lösningen följer du anvisningarna i Skapa Windows Communication Foundation-exempel.
Om du vill köra exemplet i en konfiguration med en eller flera datorer ändrar du könamnen så att de återspeglar det faktiska värdnamnet i stället för localhost och följer anvisningarna i Köra Windows Communication Foundation-exempel.
Som standard med bindningstransporten netMsmqBinding
är säkerheten aktiverad. Två egenskaper, MsmqAuthenticationMode
och MsmqProtectionLevel
, bestämmer tillsammans typen av transportsäkerhet. Som standard är autentiseringsläget inställt på Windows
och skyddsnivån är inställd på Sign
. För att MSMQ ska kunna tillhandahålla autentiserings- och signeringsfunktionen måste den vara en del av en domän. Om du kör det här exemplet på en dator som inte ingår i en domän får du följande fel: "Användarens interna meddelandeköcertifikat finns inte".
Så här kör du exemplet på en dator som är ansluten till en arbetsgrupp
Om datorn inte ingår i en domän inaktiverar du transportsäkerheten genom att ställa in autentiseringsläget och skyddsnivån på
None
enligt följande exempelkonfiguration:<bindings> <netMsmqBinding> <binding name="TransactedBinding"> <security mode="None"/> </binding> </netMsmqBinding> </bindings>
Kontrollera att slutpunkten är associerad med bindningen genom att ange slutpunktens bindingConfiguration-attribut.
Se till att du ändrar konfigurationen på PoisonMessageServer, servern och klienten innan du kör exemplet.
Kommentar
Inställningen
security mode
tillNone
motsvarar inställningenMsmqAuthenticationMode
,MsmqProtectionLevel
ochMessage
säkerhet tillNone
.För att Meta Data Exchange ska fungera registrerar vi en URL med http-bindning. Detta kräver att tjänsten körs i ett förhöjt kommandofönster. Annars får du ett undantag som:
Unhandled Exception: System.ServiceModel.AddressAccessDeniedException: HTTP could not register URL http://+:8000/ServiceModelSamples/service/. Your process does not have access rights to this namespace (see https://go.microsoft.com/fwlink/?LinkId=70353 for details). ---> System.Net.HttpListenerException: Access is denied
.