Korelasi Pesan
Sampel MessageCorrelation menunjukkan cara aplikasi Message Queuing (MSMQ) dapat mengirim pesan MSMQ ke layanan Windows Communication Foundation (WCF) dan cara pesan dapat berkorelasi antara aplikasi pengirim dan penerima dalam skenario permintaan/respons. Sampel ini menggunakan pengikatan msmqIntegrationBinding. Layanan dalam hal ini adalah aplikasi konsol yang dihost sendiri untuk memungkinkan Anda mengamati layanan yang menerima pesan antrean. k
Layanan memproses pesan yang diterima dari pengirim dan mengirim pesan respons kembali ke pengirim. Pengirim menghubungkan respons yang diterimanya dengan permintaan yang dikirim pada awalnya. Properti MessageID
dan CorrelationID
pesan digunakan untuk menghubungkan pesan permintaan dan respons.
Kontrak layanan IOrderProcessor
mendefinisikan operasi layanan satu arah yang cocok untuk digunakan dengan antrean. Pesan MSMQ tidak memiliki header Tindakan, sehingga tidak mungkin untuk memetakan pesan MSMQ yang berbeda ke kontrak operasi secara otomatis. Oleh karena itu, hanya ada satu kontrak operasi dalam kasus ini. Jika Anda ingin menentukan lebih banyak kontrak operasi dalam layanan, aplikasi harus memberikan informasi tentang header mana dalam pesan MSMQ (misalnya, label, atau correlationID) yang dapat digunakan untuk memutuskan kontrak operasi mana yang akan dikirim.
Pesan MSMQ juga tidak berisi informasi tentang header mana yang dipetakan ke parameter kontrak operasi yang berbeda. Oleh karena itu, hanya ada satu parameter dalam kontrak operasi. Parameter berjenis MsmqMessage<T>, yang berisi pesan MSMQ yang mendasar. Jenis "T" di kelas MsmqMessage<T>
mewakili data yang diserialisasikan ke dalam isi pesan MSMQ. Dalam sampel ini, jenis PurchaseOrder
diserialisasikan ke dalam isi pesan MSMQ.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
[ServiceKnownType(typeof(PurchaseOrder))]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true, Action = "*")]
void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> msg);
}
Operasi layanan memproses pesanan pembelian dan menampilkan konten pesanan pembelian dan statusnya di jendela konsol layanan. OperationBehaviorAttribute mengonfigurasi operasi untuk mendaftarkan transaksi dengan antrean dan menandai transaksi selesai saat operasi kembali. PurchaseOrder
berisi detail pesanan yang harus diproses oleh layanan.
// Service class that implements the service contract.
public class OrderProcessorService : IOrderProcessor
{
[OperationBehavior(TransactionScopeRequired = true,
TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> ordermsg)
{
PurchaseOrder po = (PurchaseOrder)ordermsg.Body;
Random statusIndexer = new Random();
po.Status = PurchaseOrder.OrderStates[statusIndexer.Next(3)];
Console.WriteLine("Processing {0} ", po);
//Send a response to the client that the order has been received
// and is pending fulfillment.
SendResponse(ordermsg);
}
private void SendResponse(MsmqMessage<PurchaseOrder> ordermsg)
{
OrderResponseClient client = new OrderResponseClient("OrderResponseEndpoint");
//Set the correlation ID such that the client can correlate the response to the order.
MsmqMessage<PurchaseOrder> orderResponseMsg = new MsmqMessage<PurchaseOrder>(ordermsg.Body);
orderResponseMsg.CorrelationId = ordermsg.Id;
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
client.SendOrderResponse(orderResponseMsg);
scope.Complete();
}
client.Close();
}
}
Layanan ini menggunakan OrderResponseClient
klien kustom untuk mengirim pesan MSMQ ke antrean. Karena aplikasi yang menerima dan memproses pesan adalah aplikasi MSMQ dan bukan aplikasi WCF, tidak ada kontrak layanan implisit antara kedua aplikasi. Jadi, kami tidak dapat membuat proksi menggunakan alat Svcutil.exe dalam skenario ini.
Proksi kustom pada dasarnya sama untuk semua aplikasi WCF yang menggunakan pengikatan msmqIntegrationBinding
untuk mengirim pesan. Tidak seperti proksi lain, proksi ini tidak mencakup berbagai operasi layanan. Ini hanya operasi kirim pesan.
[System.ServiceModel.ServiceContractAttribute(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface IOrderResponse
{
[System.ServiceModel.OperationContractAttribute(IsOneWay = true, Action = "*")]
void SendOrderResponse(MsmqMessage<PurchaseOrder> msg);
}
public partial class OrderResponseClient : System.ServiceModel.ClientBase<IOrderResponse>, IOrderResponse
{
public OrderResponseClient()
{ }
public OrderResponseClient(string configurationName)
: base(configurationName)
{ }
public OrderResponseClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress address)
: base(binding, address)
{ }
public void SendOrderResponse(MsmqMessage<PurchaseOrder> msg)
{
base.Channel.SendOrderResponse(msg);
}
}
Layanan ini dihost sendiri. Saat menggunakan transportasi integrasi MSMQ, antrean yang digunakan harus dibuat terlebih dahulu. Ini dapat dilakukan secara manual atau melalui kode. Dalam sampel ini, layanan berisi kode System.Messaging untuk memeriksa keberadaan antrean dan membuatnya jika perlu. Nama antrean dibaca dari file konfigurasi.
public static void Main()
{
// Get the MSMQ queue name from application settings in configuration.
string queueName =
ConfigurationManager.AppSettings["orderQueueName"];
// Create the transacted MSMQ queue if necessary.
if (!MessageQueue.Exists(queueName))
MessageQueue.Create(queueName, true);
// Create a ServiceHost for the OrderProcessorService type.
using (ServiceHost serviceHost = new
ServiceHost(typeof(OrderProcessorService)))
{
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.ReadLine();
// Close the ServiceHost to shutdown the service.
serviceHost.Close();
}
}
Antrean MSMQ tempat permintaan pesanan dikirim ditentukan di bagian appSettings dari file konfigurasi. Titik akhir klien dan layanan didefinisikan di bagian system.serviceModel dari file konfigurasi. Keduanya menentukan pengikatan msmqIntegrationBinding
.
<appSettings>
<add key="orderQueueName" value=".\private$\Orders" />
</appSettings>
<system.serviceModel>
<client>
<endpoint name="OrderResponseEndpoint"
address="msmq.formatname:DIRECT=OS:.\private$\OrderResponse"
binding="msmqIntegrationBinding"
bindingConfiguration="OrderProcessorBinding"
contract="Microsoft.ServiceModel.Samples.IOrderResponse">
</endpoint>
</client>
<services>
<service
name="Microsoft.ServiceModel.Samples.OrderProcessorService">
<endpoint address="msmq.formatname:DIRECT=OS:.\private$\Orders"
binding="msmqIntegrationBinding"
bindingConfiguration="OrderProcessorBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor">
</endpoint>
</service>
</services>
<bindings>
<msmqIntegrationBinding>
<binding name="OrderProcessorBinding" >
<security mode="None" />
</binding>
</msmqIntegrationBinding>
</bindings>
</system.serviceModel>
Aplikasi klien menggunakan System.Messaging untuk mengirim pesan tahan lama dan transaksi ke antrean. Isi pesan berisi pesanan pembelian.
static void PlaceOrder()
{
//Connect to the queue
MessageQueue orderQueue =
new MessageQueue(
ConfigurationManager.AppSettings["orderQueueName"])
// 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;
Message msg = new Message();
msg.UseDeadLetterQueue = true;
msg.Body = po;
//Create a transaction scope.
using (TransactionScope scope = new
TransactionScope(TransactionScopeOption.Required))
{
// Submit the purchase order.
orderQueue.Send(msg, MessageQueueTransactionType.Automatic);
// Complete the transaction.
scope.Complete();
}
//Save the messageID for order response correlation.
orderMessageID = msg.Id;
Console.WriteLine("Placed the order, waiting for response...");
}
Antrean MSMQ tempat respons pesanan diterima ditentukan di bagian appSettings dari file konfigurasi, seperti yang ditunjukkan dalam konfigurasi sampel berikut.
Catatan
Nama antrean menggunakan titik (.) untuk komputer lokal dan pemisah garis miring terbalik di jalurnya. Alamat titik akhir WCF menentukan skema msmq.formatname, dan menggunakan "localhost" untuk komputer lokal. Nama format yang dibentuk dengan benar mengikuti msmq.formatname dalam URI sesuai dengan pedoman MSMQ.
<appSettings>
<add key=" orderResponseQueueName" value=".\private$\Orders" />
</appSettings>
Aplikasi klien menyimpan messageID
pesan permintaan pesanan yang dikirim ke layanan dan menunggu respons dari layanan. Setelah respons tiba dalam antrean, klien menghubungkannya dengan pesan pesanan yang dikirimnya menggunakan properti correlationID
pesan, yang berisi messageID
pesan pesanan yang dikirim klien ke layanan awalnya.
static void DisplayOrderStatus()
{
MessageQueue orderResponseQueue = new
MessageQueue(ConfigurationManager.AppSettings
["orderResponseQueueName"]);
//Create a transaction scope.
bool responseReceived = false;
orderResponseQueue.MessageReadPropertyFilter.CorrelationId = true;
while (!responseReceived)
{
Message responseMsg;
using (TransactionScope scope2 = new
TransactionScope(TransactionScopeOption.Required))
{
//Receive the Order Response message.
responseMsg =
orderResponseQueue.Receive
(MessageQueueTransactionType.Automatic);
scope2.Complete();
}
responseMsg.Formatter = new
System.Messaging.XmlMessageFormatter(new Type[] {
typeof(PurchaseOrder) });
PurchaseOrder responsepo = (PurchaseOrder)responseMsg.Body;
//Check if the response is for the order placed.
if (orderMessageID == responseMsg.CorrelationId)
{
responseReceived = true;
Console.WriteLine("Status of current Order: OrderID-{0},Order
Status-{1}", responsepo.PONumber, responsepo.Status);
}
else
{
Console.WriteLine("Status of previous Order: OrderID-{0},Order
Status-{1}", responsepo.PONumber, responsepo.Status);
}
}
}
Saat Anda menjalankan sampel, aktivitas klien dan layanan ditampilkan baik di jendela konsol layanan dan klien. Anda dapat melihat layanan menerima pesan dari klien dan mengirim respons kembali ke klien. Klien menampilkan respons yang diterima dari layanan. Tekan ENTER di setiap jendela konsol untuk mematikan layanan dan klien.
Catatan
Sampel ini memerlukan penginstalan Message Queuing (MSMQ). Lihat instruksi penginstalan MSMQ di bagian Lihat Juga.
Menyiapkan, membangun, dan menjalankan sampel
Pastikan Anda telah melakukan Prosedur Penyiapan Satu Kali untuk Sampel Windows Communication Foundation.
Jika layanan dijalankan terlebih dahulu, layanan akan memeriksa untuk memastikan bahwa antrean ada. Jika antrean tidak ada, layanan akan membuatnya. Anda dapat menjalankan layanan terlebih dahulu untuk membuat antrean, atau Anda dapat membuatnya melalui Pengelola Antrean MSMQ. Ikuti langkah-langkah ini untuk membuat antrean di Windows 2008.
Buka Pengelola Server di Visual Studio 2012.
Luaskan tab Fitur.
Klik kanan Antrean Pesan Privat, dan pilih Baru, Antrean Privat.
Centang kotak Transaksional.
Masukkan
ServiceModelSamplesTransacted
sebagai nama antrean baru.
Untuk membangun solusi edisi C# atau Visual Basic .NET, ikuti petunjuknya di Membangun Sampel WCF.
Untuk menjalankan sampel dalam konfigurasi komputer tunggal, ikuti instruksi dalam Menjalankan Sampel Windows Communication Foundation.
Menjalankan sampel di seluruh komputer
Salin file program layanan dari folder \service\bin\, di bawah folder khusus bahasa, ke komputer layanan.
Salin file program klien dari folder \client\bin\, di bawah folder khusus bahasa, ke komputer klien.
Dalam file Client.exe.config, ubah orderQueueName untuk menentukan nama komputer layanan sebagai ganti ".".
Dalam file Service.exe.config, ubah alamat titik akhir klien untuk menentukan nama komputer klien, bukan ".".
Di komputer layanan, luncurkan Service.exe dari perintah.
Di komputer klien, luncurkan Client.exe dari perintah.