다음을 통해 공유


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

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

어댑터가 폴링을 지원하는 방법에 대한 자세한 내용은 SQL 어댑터를 사용하여 SQL Server 폴링을 참조하세요.

참고

이 항목에서는 폴링 인바운드 작업을 사용하여 폴링 메시지를 사용하는 방법을 보여 줍니다. 폴링 작업에 대한 메시지는 강력한 형식이 아닙니다. 강력한 형식의 폴링 메시지를 받으려면 TypedPolling 작업을 사용해야 합니다. 또한 TypedPolling 작업을 사용하여 단일 애플리케이션에서 여러 폴링 작업을 수행해야 합니다. TypedPolling 작업을 수행하는 방법에 대한 지침은 WCF 서비스 모델을 사용하여 SQL Server 강력한 형식의 폴링 기반 데이터 변경 메시지 받기를 참조하세요.

중요

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

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

이 항목에서는 SQL 어댑터가 데이터 변경 메시지 수신을 지원하는 방법을 보여 주기 위해 .NET 애플리케이션을 만들고 폴링 작업에 대한 WCF 서비스 계약을 생성합니다. WCF 서비스 계약을 생성하는 동안 폴링 관련 바인딩 속성을 지정하려면 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 폴링하는 방법에 대한 전체 설명은 자세히 읽어보기.

WCF 서비스 모델에서 폴링 구성

WCF 서비스 모델을 사용할 때 폴링 작업을 받으려면 다음을 수행해야 합니다.

  1. 어댑터에 의해 노출된 메타데이터에서 폴링 작업에 대한 WCF 서비스 계약(인터페이스)을 생성합니다. 이렇게 하려면 어댑터 서비스 참조 Visual Studio 플러그 인 추가를 사용할 수 있습니다.

  2. 이 인터페이스에서 WCF 서비스를 구현합니다.

  3. 서비스 호스트(System.ServiceModel.ServiceHost)를 사용하여 이 WCF 서비스를 호스트합니다.

이 항목에 사용된 예제 정보

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

WCF 서비스 계약 및 클래스

어댑터 서비스 참조 플러그 인 추가를 사용하여 폴링 작업에 대한 WCF 서비스 계약(인터페이스) 및 지원 클래스를 만들 수 있습니다. WCF 서비스 계약을 생성하는 방법에 대한 자세한 내용은 SQL Server 아티팩트용 WCF 클라이언트 또는 WCF 서비스 계약 생성을 참조하세요.

WCF 서비스 계약(인터페이스)

다음 코드는 폴링 작업에 대해 생성된 WCF 서비스 계약(인터페이스)을 보여 줍니다.

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://schemas.microsoft.com/Sql/2008/05/", ConfigurationName="PollingOperation")]
public interface PollingOperation {

    // CODEGEN: Generating message contract since the wrapper namespace (https://schemas.microsoft.com/Sql/2008/05/Polling/) of message Polling
    // does not match the default value (https://schemas.microsoft.com/Sql/2008/05/)
    [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="Polling")]
    [System.ServiceModel.XmlSerializerFormatAttribute()]
    void Polling(Polling request);
}

메시지 계약

메시지 계약 네임스페이스는 지정된 경우 연결 URI의 InboundID 매개 변수에 의해 수정됩니다. 이 예제에서는 연결 URI에 인바운드 ID를 지정하지 않았습니다. 요청 메시지는 DataSet을 반환합니다.

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="Polling", WrapperNamespace="http://schemas.microsoft.com/Sql/2008/05/Polling/", IsWrapped=true)]
public partial class Polling {

[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/Sql/2008/05/Polling/", Order=0)]
    [System.Xml.Serialization.XmlArrayAttribute(IsNullable=true)]
    [System.Xml.Serialization.XmlArrayItemAttribute("DataSet", Namespace="http://schemas.datacontract.org/2004/07/System.Data", IsNullable=false)]
    public System.Data.DataSet[] PolledData;

    public Polling() {
    }

    public Polling(System.Data.DataSet[] PolledData) {
        this.PolledData = PolledData;
    }
}

WCF 서비스 클래스

어댑터 서비스 참조 추가 플러그 인은 서비스 계약(인터페이스)에서 구현된 WCF 서비스 클래스에 대한 스텁이 있는 파일도 생성합니다. 파일의 이름은 SqlAdapterBindingService.cs입니다. 논리를 삽입하여 폴링 작업을 이 클래스에 직접 처리할 수 있습니다. 다음 코드는 어댑터 서비스 참조 플러그 인 추가에서 생성된 WCF 서비스 클래스를 보여줍니다.

namespace SqlAdapterBindingNamespace {

    public class SqlAdapterBindingService : PollingOperation {

        // CODEGEN: Generating message contract since the wrapper namespace (https://schemas.microsoft.com/Sql/2008/05/Polling/) of message Polling
        // does not match the default value (https://schemas.microsoft.com/Sql/2008/05/)
        public virtual void Polling(Polling request) {
            throw new System.NotImplementedException("The method or operation is not implemented.");
        }
    }
}

폴링 작업에 대한 인바운드 메시지 수신

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

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

  1. 어댑터 서비스 참조 플러그 인 추가를 사용하여 폴링 작업에 대한 WCF 서비스 계약(인터페이스) 및 도우미 클래스를 생성합니다. 자세한 내용은 SQL Server 아티팩트용 WCF 클라이언트 또는 WCF 서비스 계약 생성을 참조하세요. 필요에 따라 서비스 계약 및 도우미 클래스를 생성하는 동안 바인딩 속성을 지정할 수 있습니다. 이렇게 하면 생성된 구성 파일에서 올바르게 설정됩니다.

  2. 1단계에서 생성된 인터페이스 및 도우미 클래스에서 WCF 서비스를 구현합니다. 이 클래스의 폴링 메서드는 폴링 작업에서 받은 데이터를 처리하는 동안 오류가 발생하면 예외를 throw하여 폴링 트랜잭션을 중단할 수 있습니다. 그렇지 않으면 메서드는 아무것도 반환하지 않습니다. 다음과 같이 WCF 서비스 클래스의 특성을 지정해야 합니다.

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    

    폴링 메서드 내에서 애플리케이션 논리를 직접 구현할 수 있습니다. 이 클래스는 SqlAdapterBindingService.cs에서 찾을 수 있습니다. 이 예제의 이 코드는 SqlAdapterBindingService 클래스를 하위 클래스로 지정합니다. 이 코드에서는 DataSet으로 받은 폴링 메시지가 콘솔에 기록됩니다.

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    
    public class PollingService : SqlAdapterBindingNamespace.SqlAdapterBindingService
    {
    
    public override void Polling(Polling request)
    {
        Console.WriteLine("\nNew Polling Records Received");
        Console.WriteLine("*************************************************");
        DataSet[] dataArray = request.PolledData;
        foreach (DataTable tab in dataArray[0].Tables)
        {
            foreach (DataRow row in tab.Rows)
            {
                for (int i = 0; i < tab.Columns.Count; i++)
                {
                    Console.WriteLine(row[i]);
                }
            }
        }
        Console.WriteLine("*************************************************");
        Console.WriteLine("\nHit <RETURN> to stop polling");
        }
    }
    
  3. SQL 어댑터는 연결 URI의 일부로 자격 증명을 허용하지 않으므로 다음 클래스를 구현하여 SQL Server 데이터베이스에 대한 자격 증명을 전달해야 합니다. 애플리케이션의 후반부에서는 이 클래스를 인스턴스화하여 SQL Server 자격 증명을 전달합니다.

    class PollingCredentials : ClientCredentials, IServiceBehavior
    {
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            bindingParameters.Add(this);
        }
    
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        { }
    
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        { }
    
        protected override ClientCredentials CloneCore()
        {
            ClientCredentials clone = new PollingCredentials();
            clone.UserName.UserName = this.UserName.UserName;
            clone.UserName.Password = this.UserName.Password;
            return clone;
        }
    }
    
  4. SqlAdapterBinding을 만들고 바인딩 속성을 지정하여 폴링 작업을 구성합니다. 코드에서 명시적으로 또는 구성에서 선언적으로 이 작업을 수행할 수 있습니다. 최소한 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";
    
  5. 3단계에서 만든 PollingCredentials 클래스를 인스턴스화하여 SQL Server 데이터베이스 자격 증명을 지정합니다.

    PollingCredentials credentials = new PollingCredentials();
    credentials.UserName.UserName = "<Enter user name here>";
    credentials.UserName.Password = "<Enter password here>";
    
  6. 2단계에서 만든 WCF 서비스의 instance 만듭니다.

    // create service instance
    PollingService service = new PollingService();
    
  7. WCF 서비스 및 기본 연결 URI를 사용하여 System.ServiceModel.ServiceHost의 instance 만듭니다. 기본 연결 URI는 지정된 경우 인바운드 ID를 포함할 수 없습니다. 여기에서 자격 증명을 지정해야 합니다.

    // Enable service host
    Uri[] baseUri = new Uri[] { new Uri("mssql://mysqlserver//mydatabase") };
    ServiceHost serviceHost = new ServiceHost(service, baseUri);
    serviceHost.Description.Behaviors.Add(credentials);
    
    
  8. 서비스 호스트에 서비스 엔드포인트를 추가합니다. 가상 하드 디스크 파일에 대한 중요 정보를 제공하려면

    • 4단계에서 만든 바인딩을 사용합니다.

    • 자격 증명을 포함하고 필요한 경우 인바운드 ID를 포함하는 연결 URI를 지정합니다.

    • 계약을 "PollingOperation"으로 지정합니다.

    // Add service endpoint: be sure to specify PollingOperation as the contract
    Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");
    serviceHost.AddServiceEndpoint("PollingOperation", binding, ConnectionUri);
    
  9. 폴링 데이터를 받으려면 서비스 호스트를 엽니다. 어댑터는 쿼리가 결과 집합을 반환할 때마다 데이터를 반환합니다.

    // Open the service host to begin polling
    serviceHost.Open();
    
  10. 폴링을 종료하려면 서비스 호스트를 닫습니다.

    중요

    어댑터는 서비스 호스트가 닫을 때까지 계속 폴링됩니다.

    serviceHost.Close();
    

예제

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

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

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

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

    첫 번째 폴링 메시지에는 Employee 테이블의 모든 레코드가 포함됩니다. 후속 폴링 메시지에는 ADD_EMP_DETAILS 저장 프로시저에서 삽입한 마지막 레코드만 포함됩니다. 어댑터는 를 눌러 <RETURN>서비스 호스트를 닫을 때까지 계속 폴링합니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Adapters.Sql;
using Microsoft.ServiceModel.Channels;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.Collections.ObjectModel;
using System.Data;

namespace Polling_ServiceModel
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

    public class PollingService : SqlAdapterBindingNamespace.SqlAdapterBindingService
    {

        public override void Polling(Polling request)
        {
            Console.WriteLine("\nNew Polling Records Received");
            Console.WriteLine("*************************************************");
            DataSet[] dataArray = request.PolledData;
            foreach (DataTable tab in dataArray[0].Tables)
            {
                foreach (DataRow row in tab.Rows)
                {
                    for (int i = 0; i < tab.Columns.Count; i++)
                    {
                        Console.WriteLine(row[i]);
                    }
                }
            }
            Console.WriteLine("*************************************************");
            Console.WriteLine("\nHit <RETURN> to stop polling");
        }
    }

    class PollingCredentials : ClientCredentials, IServiceBehavior
    {
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            bindingParameters.Add(this);
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        { }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        { }

        protected override ClientCredentials CloneCore()
        {
            ClientCredentials clone = new PollingCredentials();
            clone.UserName.UserName = this.UserName.UserName;
            clone.UserName.Password = this.UserName.Password;
            return clone;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost serviceHost = null;
            try
            {
                Console.WriteLine("Sample started...");
                Console.WriteLine("Press any key to start polling...");
                Console.ReadLine();

                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";
                Console.WriteLine("Binding properties assigned...");

                // This URI is used to specify the address for the ServiceEndpoint
                // It must contain the InboundId (if any) that was used to generate
                // the WCF service callback interface
                Uri ConnectionUri = new Uri("mssql://mysqlserver//mydatabase?");

                // This URI is used to initialize the ServiceHost. It cannot contain
                // a query_string (InboundID); otherwise,an exception is thrown when
                // the ServiceHost is initialized.
                Uri[] baseUri = new Uri[] { new Uri("mssql://mysqlserver//mydatabase") };

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

                Console.WriteLine("Opening service host...");
                PollingService service = new PollingService();
                serviceHost = new ServiceHost(service, baseUri);
                serviceHost.Description.Behaviors.Add(credentials);
                serviceHost.AddServiceEndpoint("PollingOperation", binding, ConnectionUri);
                serviceHost.Open();
                Console.WriteLine("Service host opened...");
                Console.WriteLine("Polling started...");
                Console.ReadLine();
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception :" + e.Message);
                Console.ReadLine();

                /* If there is an error it will be specified in the inner exception */
                if (e.InnerException != null)
                {
                    Console.WriteLine("InnerException: " + e.InnerException.Message);
                    Console.ReadLine();
                }
            }
            finally
            {
                // IMPORTANT: you must close the ServiceHost to stop polling
                if (serviceHost.State == CommunicationState.Opened)
                    serviceHost.Close();
                else
                    serviceHost.Abort();
            }
        }
    }
}

참고 항목

WCF 서비스 모델에서 SQL 어댑터를 사용하여 SQL Server 폴링