큐를 사용하면 통신하는 동안 서비스를 사용할 수 없는 경우에도 클라이언트와 WCF(Windows Communication Foundation) 서비스 간의 메시징을 신뢰할 수 있는지 확인할 수 있습니다. 다음 절차에서는 WCF 서비스를 구현할 때 대기 중인 표준 바인딩을 사용하여 클라이언트와 서비스 간의 통신을 지속하는 방법을 보여 줍니다.
이 단원에서는 WCF 클라이언트와 WCF 서비스 간의 대기 중인 통신에 NetMsmqBinding을 사용하는 방법에 대해 설명합니다.
WCF 서비스에서 큐를 사용하려면
ServiceContractAttribute로 표시된 인터페이스를 사용하여 서비스 계약을 정의합니다. OperationContractAttribute가 있는 서비스 계약의 일부인 인터페이스에서 작업을 표시하고, 메서드에 대한 응답이 반환되지 않으므로 해당 작업을 단방향으로 지정합니다. 다음 코드에서는 예제 서비스 계약 및 작업 정의를 제공합니다.
<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples")> _ Public Interface IOrderProcessor <OperationContract(IsOneWay := True)> _ Sub SubmitPurchaseOrder(ByVal po As PurchaseOrder) End Interface
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")] public interface IOrderProcessor { [OperationContract(IsOneWay = true)] void SubmitPurchaseOrder(PurchaseOrder po); }
서비스 계약에서 사용자 정의 형식을 전달하는 경우 해당 형식의 데이터 계약을 정의해야 합니다. 다음 코드에서는
PurchaseOrder
및PurchaseOrderLineItem
의 두 데이터 계약을 보여 줍니다. 이 두 형식은 서비스로 전송되는 데이터를 정의합니다. 또한 이 데이터 계약을 정의하는 클래스에서 여러 메서드도 정의합니다. 이러한 메서드는 데이터 계약의 일부로 간주되지 않습니다. DataMember 특성을 사용하여 선언된 해당 멤버만이 데이터 계약의 일부가 됩니다.<DataContract(Namespace := "http://Microsoft.ServiceModel.Samples")> _ Public Class PurchaseOrder Private Shared ReadOnly OrderStates() As String = { "Pending", "Processed", "Shipped" } Private Shared statusIndexer As New Random(137) <DataMember> _ Public PONumber As String <DataMember> _ Public CustomerId As String <DataMember> _ Public orderLineItems() As PurchaseOrderLineItem Public ReadOnly Property TotalCost() As Single Get Dim totalCost_Renamed As Single = 0 For Each lineItem In orderLineItems totalCost_Renamed += lineItem.TotalCost Next lineItem Return totalCost_Renamed End Get End Property Public ReadOnly Property Status() As String Get Return OrderStates(statusIndexer.Next(3)) End Get End Property Public Overrides Function ToString() As String Dim strbuf As New System.Text.StringBuilder("Purchase Order: " & PONumber & Constants.vbLf) strbuf.Append(Constants.vbTab & "Customer: " & CustomerId & Constants.vbLf) strbuf.Append(Constants.vbTab & "OrderDetails" & Constants.vbLf) For Each lineItem In orderLineItems strbuf.Append(Constants.vbTab + Constants.vbTab + lineItem.ToString()) Next lineItem strbuf.Append(Constants.vbTab & "Total cost of this order: $" & TotalCost + Constants.vbLf) strbuf.Append(Constants.vbTab & "Order status: " & Status + Constants.vbLf) Return strbuf.ToString() End Function End Class
[DataContract(Namespace = "http://Microsoft.ServiceModel.Samples")] public class PurchaseOrder { static readonly string[] OrderStates = { "Pending", "Processed", "Shipped" }; static Random statusIndexer = new Random(137); [DataMember] public string PONumber; [DataMember] public string CustomerId; [DataMember] public PurchaseOrderLineItem[] orderLineItems; public float TotalCost { get { float totalCost = 0; foreach (PurchaseOrderLineItem lineItem in orderLineItems) totalCost += lineItem.TotalCost; return totalCost; } } public string Status { get { return OrderStates[statusIndexer.Next(3)]; } } public override string ToString() { System.Text.StringBuilder strbuf = new System.Text.StringBuilder("Purchase Order: " + PONumber + "\n"); strbuf.Append("\tCustomer: " + CustomerId + "\n"); strbuf.Append("\tOrderDetails\n"); foreach (PurchaseOrderLineItem lineItem in orderLineItems) { strbuf.Append("\t\t" + lineItem.ToString()); } strbuf.Append("\tTotal cost of this order: $" + TotalCost + "\n"); strbuf.Append("\tOrder status: " + Status + "\n"); return strbuf.ToString(); } }
클래스에서 인터페이스에 정의된 서비스 계약의 메서드를 구현합니다.
Public Class OrderProcessorService Implements IOrderProcessor <OperationBehavior(TransactionScopeRequired := True, TransactionAutoComplete := True)> _ Public Sub SubmitPurchaseOrder(ByVal po As PurchaseOrder) Implements IOrderProcessor.SubmitPurchaseOrder Orders.Add(po) Console.WriteLine("Processing {0} ", po) End Sub End Class
public class OrderProcessorService : IOrderProcessor { [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] public void SubmitPurchaseOrder(PurchaseOrder po) { Orders.Add(po); Console.WriteLine("Processing {0} ", po); } }
OperationBehaviorAttribute는
SubmitPurchaseOrder
메서드에 배치됩니다. 따라서 이 작업은 트랜잭션 내에서 호출해야 하며 메서드가 완료되면 트랜잭션도 자동으로 완료되도록 지정됩니다.System.Messaging을 사용하여 트랜잭션 큐를 만듭니다. MSMQ(Microsoft Message Queuing) MMC(Microsoft Management Console)를 대신 사용하여 큐를 만들 수 있습니다. 이 경우에는 트랜잭션 큐를 만들어야 합니다.
' Create the transacted MSMQ queue if necessary. If (Not MessageQueue.Exists(queueName)) Then MessageQueue.Create(queueName, True) End If
// Create the transacted MSMQ queue if necessary. if (!MessageQueue.Exists(queueName)) MessageQueue.Create(queueName, true);
서비스 주소를 지정하고 표준 NetMsmqBinding 바인딩을 사용하는 구성에서 ServiceEndpoint를 정의합니다. WCF 구성을 사용하는 방법에 대한 자세한 내용은 Configuring Windows Communication Foundation Applications을 참조하십시오.
<services> <service name="Microsoft.ServiceModel.Samples.OrderProcessorService" behaviorConfiguration="CalculatorServiceBehavior"> <host> <baseAddresses> <add baseAddress="https://localhost:8000/ServiceModelSamples/service"/> </baseAddresses> </host> <!-- Define NetMsmqEndpoint --> <endpoint address="net.msmq://localhost/private/ServiceModelSamplesTransacted" binding="netMsmqBinding" contract="Microsoft.ServiceModel.Samples.IOrderProcessor" /> <!-- the mex endpoint is exposed at https://localhost:8000/ServiceModelSamples/service/mex --> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services>
큐에서 메시지를 읽어 이를 처리하는 ServiceHost를 사용하여
OrderProcessing
서비스의 호스트를 만듭니다. 서비스를 사용할 수 있도록 서비스 호스트를 엽니다. 사용자에게 아무 키나 누르면 서비스를 종료할 수 있음을 알리는 메시지를 표시합니다.ReadLine
을 호출하여 키를 누를 때까지 기다린 후에 서비스를 닫습니다.' Create a ServiceHost for the OrderProcessorService type. Using serviceHost As New ServiceHost(GetType(OrderProcessorService)) ' 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 ServiceHostB to shutdown the service. serviceHost.Close() End Using
// Create a ServiceHost for the OrderProcessorService type. using (ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService))) { // 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 ServiceHostB to shutdown the service. serviceHost.Close(); }
대기 중인 서비스의 클라이언트를 만들려면
다음 예제에서는 호스팅 응용 프로그램을 실행하고 Svcutil.exe 도구를 사용해 WCF 클라이언트를 만드는 방법을 보여 줍니다.
svcutil https://localhost:8000/ServiceModelSamples/service
다음 예제와 같이 주소를 지정하고 표준 NetMsmqBinding 바인딩을 사용하는 구성에서 ServiceEndpoint를 정의합니다.
<client> <!-- Define NetMsmqEndpoint --> <endpoint address="net.msmq://localhost/private/ServiceModelSamplesTransacted" binding="netMsmqBinding" contract="Microsoft.ServiceModel.Samples.IOrderProcessor" /> </client>
다음예제와 같이 트랜잭션 큐에 쓸 트랜잭션 범위를 만들고
SubmitPurchaseOrder
작업을 호출한 다음 WCF 클라이언트를 닫습니다.'Create a transaction scope. Using scope As New TransactionScope(TransactionScopeOption.Required) ' Make a queued call to submit the purchase order. client.SubmitPurchaseOrder(po) ' Complete the transaction. scope.Complete() End Using 'Closing the client gracefully closes the connection and cleans up resources. client.Close()
//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(); } //Closing the client gracefully closes the connection and cleans up resources. client.Close();
예제
다음 예제에서는 이 예제에 포함된 서비스 코드, 호스팅 응용 프로그램, App.config 파일 및 클라이언트 코드를 보여 줍니다.
' This is the service code
' Copyright (c) Microsoft Corporation. All Rights Reserved.
Imports System
Imports System.ServiceModel.Channels
Imports System.Configuration
Imports System.Messaging
Imports System.ServiceModel
Imports System.Transactions
Imports System.Runtime.Serialization
Imports System.Collections.Generic
Namespace Microsoft.ServiceModel.Samples
' Define the purchase order line item.
<DataContract(Namespace := "http://Microsoft.ServiceModel.Samples")> _
Public Class PurchaseOrderLineItem
<DataMember> _
Public ProductId As String
<DataMember> _
Public UnitCost As Single
<DataMember> _
Public Quantity As Integer
Public Overrides Function ToString() As String
Dim displayString As String = "Order LineItem: " & Quantity & " of " & ProductId & " @unit price: $" & UnitCost + Constants.vbLf
Return displayString
End Function
Public ReadOnly Property TotalCost() As Single
Get
Return UnitCost * Quantity
End Get
End Property
End Class
' Define the purchase order.
<DataContract(Namespace := "http://Microsoft.ServiceModel.Samples")> _
Public Class PurchaseOrder
Private Shared ReadOnly OrderStates() As String = { "Pending", "Processed", "Shipped" }
Private Shared statusIndexer As New Random(137)
<DataMember> _
Public PONumber As String
<DataMember> _
Public CustomerId As String
<DataMember> _
Public orderLineItems() As PurchaseOrderLineItem
Public ReadOnly Property TotalCost() As Single
Get
Dim totalCost_Renamed As Single = 0
For Each lineItem In orderLineItems
totalCost_Renamed += lineItem.TotalCost
Next lineItem
Return totalCost_Renamed
End Get
End Property
Public ReadOnly Property Status() As String
Get
Return OrderStates(statusIndexer.Next(3))
End Get
End Property
Public Overrides Function ToString() As String
Dim strbuf As New System.Text.StringBuilder("Purchase Order: " & PONumber & Constants.vbLf)
strbuf.Append(Constants.vbTab & "Customer: " & CustomerId & Constants.vbLf)
strbuf.Append(Constants.vbTab & "OrderDetails" & Constants.vbLf)
For Each lineItem In orderLineItems
strbuf.Append(Constants.vbTab + Constants.vbTab + lineItem.ToString())
Next lineItem
strbuf.Append(Constants.vbTab & "Total cost of this order: $" & TotalCost + Constants.vbLf)
strbuf.Append(Constants.vbTab & "Order status: " & Status + Constants.vbLf)
Return strbuf.ToString()
End Function
End Class
' Order Processing Logic
' Can replace with transaction-aware resource such as SQL or transacted hashtable to hold the purchase orders.
' This example uses a non-transactional resource.
Public Class Orders
Private Shared purchaseOrders As New Dictionary(Of String, PurchaseOrder)()
Public Shared Sub Add(ByVal po As PurchaseOrder)
purchaseOrders.Add(po.PONumber, po)
End Sub
Public Shared Function GetOrderStatus(ByVal poNumber As String) As String
Dim po As PurchaseOrder = Nothing
If purchaseOrders.TryGetValue(poNumber, po) Then
Return po.Status
Else
Return Nothing
End If
End Function
Public Shared Sub DeleteOrder(ByVal poNumber As String)
If purchaseOrders(poNumber) IsNot Nothing Then
purchaseOrders.Remove(poNumber)
End If
End Sub
End Class
' Define a service contract.
<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples")> _
Public Interface IOrderProcessor
<OperationContract(IsOneWay := True)> _
Sub SubmitPurchaseOrder(ByVal po As PurchaseOrder)
End Interface
' Service class that implements the service contract.
' Added code to write output to the console window.
Public Class OrderProcessorService
Implements IOrderProcessor
<OperationBehavior(TransactionScopeRequired := True, TransactionAutoComplete := True)> _
Public Sub SubmitPurchaseOrder(ByVal po As PurchaseOrder) Implements IOrderProcessor.SubmitPurchaseOrder
Orders.Add(po)
Console.WriteLine("Processing {0} ", po)
End Sub
End Class
End Namespace
// This is the service code
// Copyright (c) Microsoft Corporation. All Rights Reserved.
using System;
using System.ServiceModel.Channels;
using System.Configuration;
using System.Messaging;
using System.ServiceModel;
using System.Transactions;
using System.Runtime.Serialization;
using System.Collections.Generic;
namespace Microsoft.ServiceModel.Samples
{
// Define the purchase order line item.
[DataContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public class PurchaseOrderLineItem
{
[DataMember]
public string ProductId;
[DataMember]
public float UnitCost;
[DataMember]
public int Quantity;
public override string ToString()
{
String displayString = "Order LineItem: " + Quantity + " of " + ProductId + " @unit price: $" + UnitCost + "\n";
return displayString;
}
public float TotalCost
{
get { return UnitCost * Quantity; }
}
}
// Define the purchase order.
[DataContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public class PurchaseOrder
{
static readonly string[] OrderStates = { "Pending", "Processed", "Shipped" };
static Random statusIndexer = new Random(137);
[DataMember]
public string PONumber;
[DataMember]
public string CustomerId;
[DataMember]
public PurchaseOrderLineItem[] orderLineItems;
public float TotalCost
{
get
{
float totalCost = 0;
foreach (PurchaseOrderLineItem lineItem in orderLineItems)
totalCost += lineItem.TotalCost;
return totalCost;
}
}
public string Status
{
get
{
return OrderStates[statusIndexer.Next(3)];
}
}
public override string ToString()
{
System.Text.StringBuilder strbuf = new System.Text.StringBuilder("Purchase Order: " + PONumber + "\n");
strbuf.Append("\tCustomer: " + CustomerId + "\n");
strbuf.Append("\tOrderDetails\n");
foreach (PurchaseOrderLineItem lineItem in orderLineItems)
{
strbuf.Append("\t\t" + lineItem.ToString());
}
strbuf.Append("\tTotal cost of this order: $" + TotalCost + "\n");
strbuf.Append("\tOrder status: " + Status + "\n");
return strbuf.ToString();
}
}
// Order Processing Logic
// Can replace with transaction-aware resource such as SQL or transacted hashtable to hold the purchase orders.
// This example uses a non-transactional resource.
public class Orders
{
static Dictionary<string, PurchaseOrder> purchaseOrders = new Dictionary<string, PurchaseOrder>();
public static void Add(PurchaseOrder po)
{
purchaseOrders.Add(po.PONumber, po);
}
public static string GetOrderStatus(string poNumber)
{
PurchaseOrder po;
if (purchaseOrders.TryGetValue(poNumber, out po))
return po.Status;
else
return null;
}
public static void DeleteOrder(string poNumber)
{
if(purchaseOrders[poNumber] != null)
purchaseOrders.Remove(poNumber);
}
}
// Define a service contract.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true)]
void SubmitPurchaseOrder(PurchaseOrder po);
}
// Service class that implements the service contract.
// Added code to write output to the console window.
public class OrderProcessorService : IOrderProcessor
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po)
{
Orders.Add(po);
Console.WriteLine("Processing {0} ", po);
}
}
}
' This is the hosting application.
Imports System
Imports System.ServiceModel.Channels
Imports System.Configuration
Imports System.Messaging
Imports System.ServiceModel
Imports System.Transactions
Imports System.Runtime.Serialization
Imports System.Collections.Generic
Namespace Microsoft.ServiceModel.Samples
Friend Class hostApp
' Host the service within this EXE console application.
Public Shared Sub Main()
' Get MSMQ queue name from appsettings in configuration.
Dim queueName As String = ConfigurationManager.AppSettings("queueName")
' Create the transacted MSMQ queue if necessary.
If (Not MessageQueue.Exists(queueName)) Then
MessageQueue.Create(queueName, True)
End If
' Create a ServiceHost for the OrderProcessorService type.
Using serviceHost As New ServiceHost(GetType(OrderProcessorService))
' 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 ServiceHostB to shutdown the service.
serviceHost.Close()
End Using
End Sub
End Class
End Namespace
// This is the hosting application.
using System;
using System.ServiceModel.Channels;
using System.Configuration;
using System.Messaging;
using System.ServiceModel;
using System.Transactions;
using System.Runtime.Serialization;
using System.Collections.Generic;
namespace Microsoft.ServiceModel.Samples
{
class hostApp
{
// Host the service within this EXE console application.
public static void Main()
{
// Get MSMQ queue name from appsettings 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 OrderProcessorService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService)))
{
// 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 ServiceHostB to shutdown the service.
serviceHost.Close();
}
}
}
}
<!-- This is the app.config for the service -->
<configuration>
<appSettings>
<!-- use appSetting to configure MSMQ queue name -->
<add key="queueName" value=".\private$\ServiceModelSamplesTransacted" />
</appSettings>
<system.serviceModel>
<services>
<service
name="Microsoft.ServiceModel.Samples.OrderProcessorService"
behaviorConfiguration="CalculatorServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://localhost:8000/ServiceModelSamples/service"/>
</baseAddresses>
</host>
<!-- Define NetMsmqEndpoint -->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesTransacted"
binding="netMsmqBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
<!-- the mex endpoint is exposed at https://localhost:8000/ServiceModelSamples/service/mex -->
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
' This is the client code.
' Copyright (c) Microsoft Corporation. All Rights Reserved.
Imports System
Imports System.Configuration
Imports System.Messaging
Imports System.ServiceModel
Imports System.Transactions
Namespace Microsoft.ServiceModel.Samples
'The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.
'Client implementation code.
Friend Class Client
Shared Sub Main()
' Create a client.
Dim client As New OrderProcessorClient()
' Create the purchase order.
Dim po As New PurchaseOrder()
po.CustomerId = "somecustomer.com"
po.PONumber = Guid.NewGuid().ToString()
Dim lineItem1 As New PurchaseOrderLineItem()
lineItem1.ProductId = "Blue Widget"
lineItem1.Quantity = 54
lineItem1.UnitCost = 29.99F
Dim lineItem2 As New PurchaseOrderLineItem()
lineItem2.ProductId = "Red Widget"
lineItem2.Quantity = 890
lineItem2.UnitCost = 45.89F
po.orderLineItems = New PurchaseOrderLineItem(1){}
po.orderLineItems(0) = lineItem1
po.orderLineItems(1) = lineItem2
'Create a transaction scope.
Using scope As New TransactionScope(TransactionScopeOption.Required)
' Make a queued call to submit the purchase order.
client.SubmitPurchaseOrder(po)
' Complete the transaction.
scope.Complete()
End Using
'Closing the client gracefully closes the connection and cleans up resources.
client.Close()
Console.WriteLine()
Console.WriteLine("Press <ENTER> to terminate client.")
Console.ReadLine()
End Sub
End Class
End Namespace
// This is the client code.
// Copyright (c) Microsoft Corporation. All Rights Reserved.
using System;
using System.Configuration;
using System.Messaging;
using System.ServiceModel;
using System.Transactions;
namespace Microsoft.ServiceModel.Samples
{
//The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.
//Client implementation code.
class Client
{
static void Main()
{
// Create a client.
OrderProcessorClient client = new OrderProcessorClient();
// 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();
}
//Closing the client gracefully closes the connection and cleans up resources.
client.Close();
Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
}
}
}
<!-- This is the app.config for the client app -->
<configuration>
<system.serviceModel>
<client>
<!-- Define NetMsmqEndpoint -->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesTransacted"
binding="netMsmqBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
</client>
</system.serviceModel>
</configuration>
참고 항목
작업
Transacted MSMQ Binding
방법: WCF 끝점 및 메시지 큐 응용 프로그램과 메시지 교환
Windows Communication Foundation to Message Queuing
Message Queuing to Windows Communication Foundation
Message Security over Message Queuing