다음을 통해 공유


WCF 채널 모델을 사용하여 SQL Server 폴링 기반 데이터 변경 메시지 수신

SQL SERVER 테이블 또는 뷰에 대한 주기적인 데이터 변경 메시지를 받도록 SQL 어댑터를 구성할 수 있습니다. 어댑터가 데이터베이스를 폴링하기 위해 실행하는 폴링 문을 지정할 수 있습니다. 폴링 문은 SELECT 문 또는 결과 집합을 반환하는 저장 프로시저일 수 있습니다.

어댑터가 폴링을 지원하는 방법에 대한 자세한 내용은 폴링을 사용한 인바운드 호출 지원을 참조하세요.

중요

단일 애플리케이션에서 둘 이상의 폴링 작업을 수행하려면 연결 URI의 일부로 InboundID 연결 속성을 지정하여 고유하게 만들어야 합니다. 지정한 인바운드 ID는 작업 네임스페이스에 추가되어 고유하게 만듭니다.

이 항목에서 폴링을 보여 주는 방법

이 항목에서는 SQL 어댑터가 데이터 변경 메시지 수신을 지원하는 방법을 보여 주려면 폴링 작업에 대한 .NET 애플리케이션을 만듭니다. 이 항목의 경우 PolledDataAvailableStatement 를 다음과 같이 지정합니다.

SELECT COUNT(*) FROM Employee  

PolledDataAvailableStatement는 양수 값을 포함하는 첫 번째 셀이 있는 결과 집합을 반환해야 합니다. 첫 번째 셀에 양수 값이 없으면 어댑터가 폴링 문을 실행하지 않습니다.

폴링 문의 일부로 다음 작업을 수행합니다.

  1. Employee 테이블에서 모든 행을 선택합니다.

  2. 저장 프로시저(MOVE_EMP_DATA)를 실행하여 Employee 테이블에서 EmployeeHistory 테이블로 모든 레코드를 이동합니다.

  3. 저장 프로시저(ADD_EMP_DETAILS)를 실행하여 Employee 테이블에 새 레코드를 추가합니다. 이 절차에서는 직원 이름, 지정 및 급여를 매개 변수로 사용합니다.

    이러한 작업을 수행하려면 PollingStatement 바인딩 속성에 대해 다음을 지정해야 합니다.

SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000   

폴링 문이 실행되면 Employee 테이블의 모든 레코드가 선택되고 SQL Server 메시지가 수신됩니다. 어댑터에서 MOVE_EMP_DATA 저장 프로시저를 실행하면 모든 레코드가 EmployeeHistory 테이블로 이동됩니다. 그런 다음 ADD_EMP_DETAILS 저장 프로시저가 실행되어 Employee 테이블에 새 레코드를 추가합니다. 다음 폴링 실행은 단일 레코드만 반환합니다. 이 주기는 채널 수신기를 닫을 때까지 계속됩니다.

SQL 어댑터 바인딩 속성을 사용하여 폴링 쿼리 구성

다음 표에서는 데이터 변경 메시지를 수신하도록 어댑터를 구성하는 데 사용하는 SQL 어댑터 바인딩 속성을 요약합니다. 폴링을 위해 .NET 애플리케이션의 일부로 이러한 바인딩 속성을 지정해야 합니다.

Binding 속성 Description
InboundOperationType 폴링, TypedPolling 또는 알림 인바운드 작업을 수행할지 여부를 지정합니다. 기본값은 폴링입니다.
PolledDataAvailableStatement 어댑터가 실행하여 폴링에 사용할 수 있는 데이터가 있는지 여부를 결정하는 SQL 문을 지정합니다. SQL 문은 행과 열로 구성된 결과 집합을 반환해야 합니다. 행을 사용할 수 있는 경우에만 PollingStatement 바인딩 속성에 지정된 SQL 문이 실행됩니다.
PollingIntervalInSeconds SQL 어댑터가 PolledDataAvailableStatement 바인딩 속성에 지정된 문을 실행하는 간격(초)을 지정합니다. 기본값은 30초입니다. 폴링 간격은 연속된 폴링 간의 시간 간격을 결정합니다. 문이 지정된 간격 내에 실행되면 어댑터는 간격의 남은 시간을 기다립니다.
PollingStatement SQL Server 데이터베이스 테이블을 폴링할 SQL 문을 지정합니다. 간단한 SELECT 문 또는 폴링 문에 대한 저장 프로시저를 지정할 수 있습니다. 기본값은 null입니다. 폴링을 사용하도록 설정하려면 PollingStatement 에 대한 값을 지정해야 합니다. 폴링 문은 PolledDataAvailableStatement 바인딩 속성에 의해 결정되는 폴링에 사용할 수 있는 데이터가 있는 경우에만 실행됩니다. 세미콜론으로 구분된 SQL 문 수를 지정할 수 있습니다.
PollWhileDataFound 폴링되는 테이블에서 데이터를 사용할 수 있는 경우 SQL 어댑터가 폴링 간격을 무시하고 PolledDataAvailableStatement 바인딩 속성에 지정된 SQL 문을 지속적으로 실행할지 여부를 지정합니다. 테이블에서 사용할 수 있는 데이터가 없으면 어댑터가 되돌려 지정된 폴링 간격으로 SQL 문을 실행합니다. 기본값은 false입니다.

이러한 속성에 대한 자세한 설명은 SQL Server 어댑터 바인딩 속성에 대한 BizTalk 어댑터에 대한 읽기를 참조하세요. SQL 어댑터를 사용하여 SQL Server 폴링하는 방법에 대한 자세한 내용은 이 항목의 나머지 부분을 참조하세요.

폴링 요청 메시지 사용

어댑터는 코드에서 폴링 작업을 호출하여 SQL Server 데이터베이스를 폴링합니다. 즉, 어댑터는 IInputChannel 채널 셰이프를 통해 수신하는 폴링 요청 메시지를 보냅니다. 폴링 요청 메시지에는 PollingStatement 바인딩 속성에 지정된 쿼리의 결과 집합이 포함됩니다. 다음 두 가지 방법 중 하나로 폴링 메시지를 사용할 수 있습니다.

  • 노드 값 스트리밍을 사용하여 메시지를 사용하려면 응답 메시지에서 WriteBodyContents 메서드를 호출하고 노드 값 스트리밍을 구현하는 XmlDictionaryWriter 를 전달해야 합니다.

  • 노드 스트리밍을 사용하여 메시지를 사용하려면 응답 메시지에서 GetReaderAtBodyContents 를 호출하여 XmlReader를 가져올 수 있습니다.

이 항목에 사용된 예제 정보

이 항목의 예제는 Employee 테이블을 폴링합니다. 이 예제에서는 MOVE_EMP_DATA 및 ADD_EMP_DETAILS 저장 프로시저도 사용합니다. 이러한 아티팩트 생성 스크립트는 샘플과 함께 제공됩니다. 샘플에 대한 자세한 내용은 SQL 어댑터에 대한 샘플을 참조하세요. 이 항목을 기반으로 하는 샘플 Polling_ChannelModel SQL 어댑터 샘플도 제공됩니다.

WCF 채널 모델을 사용하여 폴링 작업에 대한 인바운드 메시지 수신

이 섹션에서는 SQL 어댑터를 사용하여 인바운드 폴링 메시지를 수신하는 .NET 애플리케이션(채널 모델)을 작성하는 방법에 대한 지침을 제공합니다.

SQL 어댑터에서 폴링 메시지를 받으려면

  1. Visual Studio에서 Microsoft Visual C# 프로젝트를 만듭니다. 이 항목의 경우 콘솔 애플리케이션을 만듭니다.

  2. 솔루션 탐색기 , , Microsoft.ServiceModel.ChannelsSystem.ServiceModelSystem.Runtime.Serialization에 대한 참조를 Microsoft.Adapters.Sql추가합니다.

  3. Program.cs 파일을 열고 다음 네임스페이스를 추가합니다.

    • Microsoft.Adapters.Sql

    • System.ServiceModel

    • System.ServiceModel.Description

    • System.ServiceModel.Channels

    • System.Xml

  4. 연결 URI를 지정합니다. 어댑터 연결 URI에 대한 자세한 내용은 SQL Server 연결 URI 만들기를 참조하세요.

    Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");  
    
  5. SqlAdapterBinding의 instance 만들고 폴링을 구성하는 데 필요한 바인딩 속성을 설정합니다. 최소한 InboundOperationType, PolledDataAvailableStatementPollingStatement 바인딩 속성을 설정해야 합니다. 폴링을 구성하는 데 사용되는 바인딩 속성에 대한 자세한 내용은 폴 링을 사용하여 인바운드 호출 지원을 참조하세요.

    SqlAdapterBinding binding = new SqlAdapterBinding();  
    binding.InboundOperationType = InboundOperation.Polling;  
    binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM EMPLOYEE";  
    binding.PollingStatement = "SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000";  
    
  6. 바인딩 매개 변수 컬렉션을 만들고 자격 증명을 설정합니다.

    ClientCredentials credentials = new ClientCredentials();  
    credentials.UserName.UserName = "<Enter user name here>";  
    credentials.UserName.Password = "<Enter password here>";  
    
    BindingParameterCollection bindingParams = new BindingParameterCollection();  
    bindingParams.Add(credentials);  
    
  7. 채널 수신기를 만들고 엽니다. SqlAdapterBinding에서 BuildChannelListener<IInputChannel> 메서드를 호출하여 수신기를 만듭니다.

    IChannelListener<IInputChannel> listener = binding.BuildChannelListener<IInputChannel>(connectionUri, bindingParams);  
    listener.Open();  
    
  8. 수신기에서 AcceptChannel 메서드를 호출하여 IInputChannel 채널을 가져와서 엽니다.

    IInputChannel channel = listener.AcceptChannel();  
    channel.Open();  
    
  9. 채널에서 Receive 를 호출하여 어댑터에서 다음 POLLINGSTMT 메시지를 가져옵니다.

    Message message = channel.Receive();  
    
  10. POLLINGSTMT 작업에서 반환된 결과 집합을 사용합니다. XmlReader 또는 XmlDictionaryWriter를 사용하여 메시지를 사용할 수 있습니다.

    XmlReader reader = message.GetReaderAtBodyContents();  
    
  11. 요청 처리를 완료하면 채널을 닫습니다.

    channel.Close()  
    

    중요

    POLLINGSTMT 작업 처리를 완료한 후 채널을 닫아야 합니다. 채널을 닫지 못하면 코드의 동작에 영향을 줄 수 있습니다.

  12. 데이터 변경 메시지 수신이 완료되면 수신기를 닫습니다.

    listener.Close()  
    

    중요

    수신기를 닫으면 수신기를 사용하여 만든 채널이 닫히지 않습니다. 수신기를 사용하여 만든 각 채널을 명시적으로 닫아야 합니다.

예제

다음 예제에서는 Employee 테이블을 실행하는 폴링 쿼리를 보여 줍니다. 폴링 문은 다음 작업을 수행합니다.

  • Employee 테이블에서 모든 레코드를 선택합니다.

  • MOVE_EMP_DATA 저장 프로시저를 실행하여 모든 레코드를 Employee 테이블에서 EmployeeHistory 테이블로 이동합니다.

  • ADD_EMP_DETAILS 저장 프로시저를 실행하여 Employee 테이블에 단일 레코드를 추가합니다.

    폴링 메시지는 에 C:\PollingOutput.xml저장됩니다.

using System;  
using Microsoft.Adapters.Sql;  
using System.ServiceModel;  
using System.ServiceModel.Description;  
using System.ServiceModel.Channels;  

using System.Xml;  

namespace ConsoleApplication1  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            Console.WriteLine("Sample started. This sample will poll 5 times and will perform the following tasks:");  
            Console.WriteLine("Press any key to start polling...");  
            Console.ReadLine();  
            IChannelListener<IInputChannel> listener = null;  

            IInputChannel channel = null;  

            try  
            {  
                TimeSpan messageTimeout = new TimeSpan(0, 0, 30);  

                SqlAdapterBinding binding = new SqlAdapterBinding();  
                binding.InboundOperationType = InboundOperation.Polling;  
                binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM EMPLOYEE";  
                binding.PollingStatement = "SELECT * FROM Employee;EXEC MOVE_EMP_DATA;EXEC ADD_EMP_DETAILS John, Tester, 100000";  

                Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");  

                ClientCredentials credentials = new ClientCredentials();  
                credentials.UserName.UserName = "<Enter user name here>";  
                credentials.UserName.Password = "<Enter password here>";  

                BindingParameterCollection bindingParams = new BindingParameterCollection();  
                bindingParams.Add(credentials);  

                listener = binding.BuildChannelListener<IInputChannel>(ConnectionUri, bindingParams);  
                listener.Open();  

                channel = listener.AcceptChannel();  
                channel.Open();  

                Console.WriteLine("Channel and Listener opened...");  
                Console.WriteLine("\nWaiting for polled data...");  
                Console.WriteLine("Receive request timeout is {0}", messageTimeout);  

                // Poll five times with the specified message timeout   
                // If a timeout occurs polling will be aborted  
                for (int i = 0; i < 5; i++)  
                {  
                    Console.WriteLine("Polling: " + i);  
                    Message message = null;  
                    XmlReader reader = null;  
                    try  
                    {  
                        //Message is received so process the results  
                        message = channel.Receive(messageTimeout);  
                    }  
                    catch (System.TimeoutException toEx)  
                    {  
                        Console.WriteLine("\nNo data for request number {0}: {1}", i + 1, toEx.Message);  
                        continue;  
                    }  

                    // Get the query results using an XML reader  
                    try  
                    {  
                        reader = message.GetReaderAtBodyContents();  
                    }  
                    catch (Exception ex)  
                    {  
                        Console.WriteLine("Exception :" + ex);  
                        throw;  
                    }  

                    XmlDocument doc = new XmlDocument();  
                    doc.Load(reader);  
                    using (XmlWriter writer = XmlWriter.Create("C:\\PollingOutput.xml"))  
                    {  
                        doc.WriteTo(writer);  
                        Console.WriteLine("The polling response is saved at 'C:\\PollingOutput.xml'");  
                    }  

                    // return the cursor  
                    Console.WriteLine();  

                    // close the reader  
                    reader.Close();  

                    message.Close();  
                }  
                Console.WriteLine("\nPolling done -- hit <RETURN> to finish");  
                Console.ReadLine();  
            }  
            catch (Exception ex)  
            {  
                Console.WriteLine("Exception is: " + ex.Message);  
                if (ex.InnerException != null)  
                {  
                    Console.WriteLine("Inner Exception is: " + ex.InnerException.Message);  
                }  
            }  
            finally  
            {  
                // IMPORTANT: close the channel and listener to stop polling  
                if (channel != null)  
                {  
                    if (channel.State == CommunicationState.Opened)  
                        channel.Close();  
                    else  
                        channel.Abort();  
                }  

                if (listener != null)  
                {  
                    if (listener.State == CommunicationState.Opened)  
                        listener.Close();  
                    else  
                        listener.Abort();  
                }  
            }  
        }  
    }  
}  

참고 항목

WCF 채널 모델을 사용하여 SQL 애플리케이션 개발