다음을 통해 공유


거래된 MSMQ 바인딩

거래된 샘플은 MSMQ(메시지 큐)를 사용하여 트랜잭션 큐에 대기된 통신을 수행하는 방법을 보여 줍니다.

비고

이 샘플에 대한 설치 절차 및 빌드 지침은 이 항목의 끝에 있습니다.

대기 중인 통신에서 클라이언트는 큐를 사용하여 서비스와 통신합니다. 보다 정확하게 말하자면, 클라이언트는 큐에 메시지를 보냅니다. 서비스는 큐에서 메시지를 받습니다. 따라서 서비스와 클라이언트는 큐를 사용하여 통신하기 위해 동시에 실행될 필요가 없습니다.

트랜잭션을 사용하여 메시지를 보내고 받는 경우 실제로 두 개의 별도 트랜잭션이 있습니다. 클라이언트가 트랜잭션 범위 내에서 메시지를 보내면 트랜잭션은 클라이언트 및 클라이언트 큐 관리자에 로컬입니다. 서비스가 트랜잭션 범위 내에서 메시지를 받으면 트랜잭션은 서비스 및 수신 큐 관리자에 로컬입니다. 클라이언트와 서비스가 동일한 트랜잭션에 참여하지 않는다는 점을 기억하는 것이 매우 중요합니다. 오히려 큐에서 작업(예: 보내기 및 받기)을 수행할 때 서로 다른 트랜잭션을 사용합니다.

이 샘플에서 클라이언트는 트랜잭션 범위 내에서 서비스로 메시지 일괄 처리를 보냅니다. 큐에 전송된 메시지는 서비스에서 정의한 트랜잭션 범위 내의 서비스에서 수신됩니다.

서비스 계약은 IOrderProcessor다음 샘플 코드와 같이 표시됩니다. 인터페이스는 큐에 사용하기에 적합한 단방향 서비스를 정의합니다.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
    [OperationContract(IsOneWay = true)]
    void SubmitPurchaseOrder(PurchaseOrder po);
}

서비스 동작은 TransactionScopeRequiredtrue로 설정된 작업 동작을 정의합니다. 이렇게 하면 큐에서 메시지를 검색할 때 사용하는 동일한 트랜잭션 범위를 메서드에서 액세스하는 모든 리소스 관리자가 사용할 수 있도록 합니다. 또한 메서드가 예외를 throw하는 경우 메시지가 큐에 반환되도록 보장합니다. 이 작업 동작을 설정하지 않으면 대기 중인 채널은 큐에서 메시지를 읽는 트랜잭션을 만들고 디스패치하기 전에 자동으로 커밋하므로 작업이 실패하면 메시지가 손실됩니다. 가장 일반적인 시나리오는 다음 코드에 설명된 대로 서비스 작업이 큐에서 메시지를 읽는 데 사용되는 트랜잭션에 참여하는 것입니다.

 // This service class that implements the service contract.
 // This added code writes 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);
     }
  …
}

서비스가 자체 호스팅됩니다. MSMQ 전송을 사용하는 경우 사용되는 큐를 미리 만들어야 합니다. 이 작업은 수동으로 또는 코드를 통해 수행할 수 있습니다. 이 샘플에서 서비스에는 큐가 있는지 확인하고 큐가 없는 경우 큐를 만드는 코드가 포함되어 있습니다. 큐 이름은 구성 파일에서 읽습니다. 기본 주소는 ServiceModel 메타데이터 유틸리티 도구(Svcutil.exe) 에서 서비스에 대한 프록시를 생성하는 데 사용됩니다.

// Host the service within this EXE console application.
public static void Main()
{
    // Get the 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 ServiceHost to shut down the service.
        serviceHost.Close();
    }
}

MSMQ 큐 이름은 다음 샘플 구성과 같이 구성 파일의 appSettings 섹션에 지정됩니다.

<appSettings>
    <add key="queueName" value=".\private$\ServiceModelSamplesTransacted" />
</appSettings>

비고

큐 이름은 로컬 컴퓨터의 경우 점(.)을 사용하고, 큐의 경로에서는 백슬래시 구분 기호를 사용하여 System.Messaging로 큐를 생성합니다. Windows Communication Foundation(WCF) 엔드포인트는 net.msmq 스키마의 큐 주소를 사용하며, 로컬 컴퓨터를 나타내기 위해 "localhost"를 사용하고, 경로에는 슬래시를 사용합니다.

클라이언트는 트랜잭션 범위를 만듭니다. 큐와의 통신은 트랜잭션 범위 내에서 발생하므로 모든 메시지가 큐로 전송되거나 큐로 전송되지 않는 원자성 단위로 처리됩니다. 트랜잭션은 트랜잭션 범위를 호출 Complete 하여 커밋됩니다.

// 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();

트랜잭션이 작동하는지 확인하려면 다음 샘플 코드와 같이 트랜잭션 범위를 주석으로 처리하여 클라이언트를 수정하고, 솔루션을 다시 빌드하고, 클라이언트를 실행합니다.

//scope.Complete();

트랜잭션이 완료되지 않았으므로 메시지가 큐로 전송되지 않습니다.

샘플을 실행하면 서비스 및 클라이언트 콘솔 창에 클라이언트 및 서비스 활동이 모두 표시됩니다. 서비스가 클라이언트에서 메시지를 수신하는 것을 볼 수 있습니다. 각 콘솔 창에서 Enter 키를 눌러 서비스 및 클라이언트를 종료합니다. 큐 시스템이 사용되고 있기 때문에, 클라이언트와 서비스가 동시에 가동될 필요가 없습니다. 클라이언트를 실행하고 종료한 다음 서비스를 시작하고 메시지를 계속 받을 수 있습니다.

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

Processing Purchase Order: 7b31ce51-ae7c-4def-9b8b-617e4288eafd
        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

샘플을 설정, 빌드 및 실행하려면

  1. Windows Communication Foundation 샘플 에 대한One-Time 설정 절차를 수행했는지 확인합니다.

  2. 서비스가 먼저 실행되면 큐가 있는지 확인합니다. 큐가 존재하지 않으면 서비스가 큐를 생성합니다. 서비스를 먼저 실행하여 큐를 만들거나 MSMQ 큐 관리자를 통해 만들 수 있습니다. 다음 단계에 따라 Windows 2008에서 큐를 만듭니다.

    1. Visual Studio 2012에서 서버 관리자를 엽니다.

    2. 기능 탭을 확장합니다.

    3. 프라이빗 메시지 큐 마우스 오른쪽 단추로 클릭하고 새 프라이빗 큐선택합니다.

    4. 트랜잭션 체크박스를 선택하세요.

    5. 새 큐의 이름으로 ServiceModelSamplesTransacted 입력합니다.

  3. 솔루션의 C# 또는 Visual Basic .NET 버전을 빌드하려면 Windows Communication Foundation 샘플빌드의 지침을 따릅니다.

  4. 단일 또는 컴퓨터 간 구성에서 샘플을 실행하려면 Windows Communication Foundation 샘플 실행의 지침을 따릅니다.

기본적으로 NetMsmqBinding 전송 보안이 활성화됩니다. MSMQ 전송 보안과 관련된 두 가지 속성이 MsmqAuthenticationMode 있습니다 MsmqProtectionLevel. 기본적으로 인증 모드는 로 Windows 설정되고 보호 수준은 .로 Sign설정됩니다. MSMQ가 인증 및 서명 기능을 제공하려면 도메인의 일부여야 하며 MSMQ에 대한 Active Directory 통합 옵션을 설치해야 합니다. 이러한 조건을 충족하지 않는 컴퓨터에서 이 샘플을 실행하면 오류가 발생합니다.

작업 그룹에 조인된 컴퓨터에서 또는 Active Directory 통합 없이 샘플을 실행하려면

  1. 컴퓨터가 도메인에 속하지 않거나 Active Directory 통합이 설치되어 있지 않은 경우 다음 샘플 구성 코드와 같이 인증 모드 및 보호 수준을 설정하여 None 전송 보안을 해제합니다.

    <system.serviceModel>
      <services>
        <service name="Microsoft.ServiceModel.Samples.OrderProcessorService"
                 behaviorConfiguration="OrderProcessorServiceBehavior">
          <host>
            <baseAddresses>
              <add baseAddress="http://localhost:8000/ServiceModelSamples/service"/>
            </baseAddresses>
          </host>
          <!-- Define NetMsmqEndpoint. -->
          <endpoint
              address="net.msmq://localhost/private/ServiceModelSamplesTransacted"
              binding="netMsmqBinding"
              bindingConfiguration="Binding1"
           contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
          <!-- 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="OrderProcessorServiceBehavior">
              <serviceMetadata httpGetEnabled="True"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    
      </system.serviceModel>
    
  2. 샘플을 실행하기 전에 서버와 클라이언트 모두에서 구성을 변경해야 합니다.

    비고

    security modeNone로 설정하는 것은 MsmqAuthenticationMode, MsmqProtectionLevel, 및 Message의 보안을 None로 설정하는 것과 같습니다.