Implemente um gestor de lógica de negócio para um artigo de fusão

Aplica-se a:SQL Server

Este artigo descreve como implementar um manipulador de lógica de negócio para um artigo de fusão no SQL Server utilizando programação de replicação ou Objetos de Gestão de Replicação (RMO).

O Microsoft.SqlServer.Replication.BusinessLogicSupport namespace implementa uma interface que pode usar para escrever lógica de negócio complexa para lidar com eventos que ocorrem durante o processo de sincronização Merge Replication. O processo de replicação invoca métodos no processador da lógica de negócio para cada linha alterada replicada durante a sincronização.

O processo geral para implementar um manipulador de lógica de negócios é:

  1. Crie a assemblagem do manipulador de lógica de negócios.

  2. Registe a montagem do produto no Distribuidor.

  3. Implante o assembly no servidor no qual o Merge Agent é executado. Para uma subscrição de solicitação, o agente é executado no Assinante. Para uma subscrição push, o agente corre no Distribuidor. Quando usa sincronização Web, o agente corre no servidor Web.

  4. Crie um artigo que use o manipulador de lógica de negócios ou modifique um artigo existente para usar o manipulador de lógica de negócios.

O manipulador de lógica de negócios especificado é executado para cada linha sincronizada. Lógica complexa e chamadas para outras aplicações ou serviços de rede podem afetar o desempenho. Para obter mais informações sobre manipuladores de lógica de negócios, consulte Executar lógica de negócios durante a sincronização de mesclagem.

Utilização da programação de replicação

Para criar e implantar um manipulador de lógica de negócios

  1. No Microsoft Visual Studio, crie um novo projeto para o assembly .NET que contém o código que implementa o manipulador de lógica de negócios.

  2. Adicione referências ao projeto para os namespaces a seguir.

    Referência de montagem Localização
    Microsoft.SqlServer.Replication.BusinessLogicSupport < unidade>:\Arquivos de Programas\Microsoft SQL Server\nnn\COM (instalação padrão)
    System.Data GAC (componente do Framework .NET)
    System.Data.Common GAC (componente do Framework .NET)
  3. Adicione uma classe que substitua a classe BusinessLogicModule.

  4. Implemente a HandledChangeStates propriedade para indicar os tipos de alterações que o handler gere.

  5. Substitua um ou mais dos seguintes métodos da classe BusinessLogicModule:

    • CommitHandler - invocado quando uma alteração de dados é confirmada durante a sincronização.

    • DeleteErrorHandler - invocado se ocorrer um erro durante o carregamento ou transferência de uma declaração DELETE.

    • DeleteHandler - chamados quando as instruções DELETE estão a ser carregadas ou descarregadas.

    • InsertErrorHandler - invocado quando ocorre um erro durante o carregamento ou descarregamento de uma declaração INSERT.

    • InsertHandler - chamados quando as instruções INSERT estão a ser carregadas ou descarregadas.

    • UpdateConflictsHandler - invocado quando ocorrem instruções UPDATE conflitantes no Publisher e no Subscriber.

    • UpdateDeleteConflictHandler - invocado quando as instruções UPDATE entram em conflito com as instruções DELETE no Publicador e no Subscritor.

    • UpdateErrorHandler - invocado quando ocorre um erro durante o carregamento ou descarregamento de uma declaração UPDATE.

    • UpdateHandler - chamados quando as instruções UPDATE estão a ser carregadas ou descarregadas.

  6. Compile o projeto para criar o assembly do manipulador de lógica de negócios.

  7. Implante o assembly no diretório que contém o arquivo executável do Merge Agent (replmerg.exe), que para uma instalação padrão é <drive>:\Program Files\Microsoft SQL Server\nnn\COM, ou instale-o no cache de assembly global (GAC) do .NET. Só instale o conjunto no GAC se aplicações que não o Merge Agent exigirem acesso ao conjunto. Utilize a ferramenta da Global Assembly Cache (Gacutil.exe), fornecida com o SDK do .NET Framework, para instalar o assembly no GAC.

    Observação

    Tens de implementar um handler de lógica de negócio em cada servidor onde o Merge Agent corre. Este requisito inclui o servidor IIS que aloja o replisapi.dll quando se utiliza a sincronização Web.

Para registrar um manipulador de lógica de negócios

  1. No Publisher, execute sp_enumcustomresolvers (Transact-SQL) para verificar se o assembly não está já registado como um handler de lógica de negócio.

  2. No Distribuidor, execute sp_registercustomresolver (Transact-SQL), especificando um nome descritivo para o manipulador de lógica de negócio para @article_resolver, o valor true para @is_dotnet_assembly, o nome do assembly para @dotnet_assembly_name e o nome totalmente qualificado da classe que substitui BusinessLogicModule para @dotnet_class_name.

    Observação

    Se não implementares o assembly no mesmo diretório do executável Merge Agent, no mesmo diretório da aplicação que inicia o Merge Agent sincronizadamente, ou na cache global assembly (GAC), precisas de especificar o caminho completo com o nome assembly para @dotnet_assembly_name. Ao usar sincronização Web, deve especificar a localização do assembly no servidor Web.

Para usar um manipulador de lógica de negócios com um novo artigo de tabela

  1. Execute sp_addmergearticle (Transact-SQL) para definir um artigo, especificando o nome amigável do manipulador de lógica de negócios para @article_resolver. Para obter mais informações, consulte Definição de um artigo.

Para usar um manipulador de lógica de negócios com um elemento de tabela existente

  1. Execute sp_changemergearticle (Transact-SQL) e especifique @publication, @article, article_resolver para @property e o nome amigável do handler de lógica de negócio para @value.

Exemplos (programação de replicação)

Este exemplo mostra um manipulador de lógica de negócios que cria um log de auditoria.

using System;
using System.Text;
using System.Data;
using System.Data.Common;
using Microsoft.SqlServer.Replication.BusinessLogicSupport;
using Microsoft.Samples.SqlServer.BusinessLogicHandler;

namespace Microsoft.Samples.SqlServer.BusinessLogicHandler
{
    public class OrderEntryBusinessLogicHandler :
      Microsoft.SqlServer.Replication.BusinessLogicSupport.BusinessLogicModule
    {
        // Variables to hold server names.
        private string publisherName;
        private string subscriberName;

        public OrderEntryBusinessLogicHandler()
        {
        }

        // Implement the Initialize method to get publication 
        // and subscription information.
        public override void Initialize(
            string publisher,
            string subscriber,
            string distributor,
            string publisherDB,
            string subscriberDB,
            string articleName)
        {
            // Set the Publisher and Subscriber names.
            publisherName = publisher;
            subscriberName = subscriber;
        }

        // Declare what types of row changes, conflicts, or errors to handle.
        override public ChangeStates HandledChangeStates
        {
            get
            {
                // Handle Subscriber inserts, updates and deletes.
                return ChangeStates.SubscriberInserts |
                  ChangeStates.SubscriberUpdates | ChangeStates.SubscriberDeletes;
            }
        }

        public override ActionOnDataChange InsertHandler(SourceIdentifier insertSource,
          DataSet insertedDataSet, ref DataSet customDataSet, ref int historyLogLevel,
          ref string historyLogMessage)
        {
            if (insertSource == SourceIdentifier.SourceIsSubscriber)
            {
                // Build a line item in the audit message to log the Subscriber insert.
                StringBuilder AuditMessage = new StringBuilder();
                AuditMessage.Append(String.Format("A new order was entered at {0}. " +
                  "The SalesOrderID for the order is :", subscriberName));
                AuditMessage.Append(insertedDataSet.Tables[0].Rows[0]["SalesOrderID"].ToString());
                AuditMessage.Append("The order must be shipped by :");
                AuditMessage.Append(insertedDataSet.Tables[0].Rows[0]["DueDate"].ToString());

                // Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString();
                
                // Set the history log level to the default verbose level.
                historyLogLevel = 1;

                // Accept the inserted data in the Subscriber's data set and 
                // apply it to the Publisher.
                return ActionOnDataChange.AcceptData;
            }
            else
            {
                return base.InsertHandler(insertSource, insertedDataSet, ref customDataSet,
                  ref historyLogLevel, ref historyLogMessage);
            }
        }

        public override ActionOnDataChange UpdateHandler(SourceIdentifier updateSource,
          DataSet updatedDataSet, ref DataSet customDataSet, ref int historyLogLevel,
          ref string historyLogMessage)
        {
            if (updateSource == SourceIdentifier.SourceIsPublisher)
            {
                // Build a line item in the audit message to log the Subscriber update.
                StringBuilder AuditMessage = new StringBuilder();
                AuditMessage.Append(String.Format("An existing order was updated at {0}. " +
                  "The SalesOrderID for the order is ", subscriberName));
                AuditMessage.Append(updatedDataSet.Tables[0].Rows[0]["SalesOrderID"].ToString());
                AuditMessage.Append("The order must now be shipped by :");
                AuditMessage.Append(updatedDataSet.Tables[0].Rows[0]["DueDate"].ToString());

                // Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString();
                // Set the history log level to the default verbose level.
                historyLogLevel = 1;

                // Accept the updated data in the Subscriber's data set and apply it to the Publisher.
                return ActionOnDataChange.AcceptData;
            }
            else
            {
                return base.UpdateHandler(updateSource, updatedDataSet,
                  ref customDataSet, ref historyLogLevel, ref historyLogMessage);
            }
        }

        public override ActionOnDataDelete DeleteHandler(SourceIdentifier deleteSource,
          DataSet deletedDataSet, ref int historyLogLevel, ref string historyLogMessage)
        {
            if (deleteSource == SourceIdentifier.SourceIsSubscriber)
            {
                // Build a line item in the audit message to log the Subscriber deletes.
                // Note that the rowguid is the only information that is 
                // available in the dataset.
                StringBuilder AuditMessage = new StringBuilder();
                AuditMessage.Append(String.Format("An existing order was deleted at {0}. " +
                  "The rowguid for the order is ", subscriberName));
                AuditMessage.Append(deletedDataSet.Tables[0].Rows[0]["rowguid"].ToString());

                // Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString();
                // Set the history log level to the default verbose level.
                historyLogLevel = 1;

                // Accept the delete and apply it to the Publisher.
                return ActionOnDataDelete.AcceptDelete;
            }
            else
            {
                return base.DeleteHandler(deleteSource, deletedDataSet,
                  ref historyLogLevel, ref historyLogMessage);
            }
        }
    }
}
Imports System
Imports System.Text
Imports System.Data
Imports System.Data.Common
Imports Microsoft.SqlServer.Replication.BusinessLogicSupport

Namespace Microsoft.Samples.SqlServer.BusinessLogicHandler
    Public Class OrderEntryBusinessLogicHandler
        Inherits BusinessLogicModule

        ' Variables to hold server names.
        Private publisherName As String
        Private subscriberName As String

        ' Implement the Initialize method to get publication 
        ' and subscription information.
        Public Overrides Sub Initialize( _
        ByVal publisher As String, _
        ByVal subscriber As String, _
        ByVal distributor As String, _
        ByVal publisherDB As String, _
        ByVal subscriberDB As String, _
        ByVal articleName As String _
      )
            ' Set the Publisher and Subscriber names.
            publisherName = publisher
            subscriberName = subscriber
        End Sub

        ' Declare what types of row changes, conflicts, or errors to handle.
        Public Overrides ReadOnly Property HandledChangeStates() As ChangeStates
            Get
                ' Handle Subscriber inserts, updates and deletes.
                Return (ChangeStates.SubscriberInserts Or _
                 ChangeStates.SubscriberUpdates Or ChangeStates.SubscriberDeletes)
            End Get
        End Property

        Public Overrides Function InsertHandler(ByVal insertSource As SourceIdentifier, _
        ByVal insertedDataSet As DataSet, ByRef customDataSet As DataSet, _
        ByRef historyLogLevel As Integer, ByRef historyLogMessage As String) _
        As ActionOnDataChange

            If insertSource = SourceIdentifier.SourceIsSubscriber Then
                ' Build a line item in the audit message to log the Subscriber insert.
                Dim AuditMessage As StringBuilder = New StringBuilder()
                AuditMessage.Append(String.Format("A new order was entered at {0}. " + _
                 "The SalesOrderID for the order is :", subscriberName))
                AuditMessage.Append(insertedDataSet.Tables(0).Rows(0)("SalesOrderID").ToString())
                AuditMessage.Append("The order must be shipped by :")
                AuditMessage.Append(insertedDataSet.Tables(0).Rows(0)("DueDate").ToString())

                ' Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString()

                ' Set the history log level to the default verbose level.
                historyLogLevel = 1

                ' Accept the inserted data in the Subscriber's data set and 
                ' apply it to the Publisher.
                Return ActionOnDataChange.AcceptData
            Else
                Return MyBase.InsertHandler(insertSource, insertedDataSet, customDataSet, _
                 historyLogLevel, historyLogMessage)
            End If
        End Function
        Public Overrides Function UpdateHandler(ByVal updateSource As SourceIdentifier, _
        ByVal updatedDataSet As DataSet, ByRef customDataSet As DataSet, _
        ByRef historyLogLevel As Integer, ByRef historyLogMessage As String) _
        As ActionOnDataChange

            If updateSource = SourceIdentifier.SourceIsPublisher Then
                ' Build a line item in the audit message to log the Subscriber update.
                Dim AuditMessage As StringBuilder = New StringBuilder()
                AuditMessage.Append(String.Format("An existing order was updated at {0}. " + _
                 "The SalesOrderID for the order is ", subscriberName))
                AuditMessage.Append(updatedDataSet.Tables(0).Rows(0)("SalesOrderID").ToString())
                AuditMessage.Append("The order must now be shipped by :")
                AuditMessage.Append(updatedDataSet.Tables(0).Rows(0)("DueDate").ToString())

                ' Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString()
                ' Set the history log level to the default verbose level.
                historyLogLevel = 1

                ' Accept the updated data in the Subscriber's data set and apply it to the Publisher.
                Return ActionOnDataChange.AcceptData
            Else
                Return MyBase.UpdateHandler(updateSource, updatedDataSet, _
                 customDataSet, historyLogLevel, historyLogMessage)
            End If
        End Function
        Public Overrides Function DeleteHandler(ByVal deleteSource As SourceIdentifier, _
        ByVal deletedDataSet As DataSet, ByRef historyLogLevel As Integer, _
         ByRef historyLogMessage As String) As ActionOnDataDelete
            If deleteSource = SourceIdentifier.SourceIsSubscriber Then
                ' Build a line item in the audit message to log the Subscriber deletes.
                ' Note that the rowguid is the only information that is 
                ' available in the dataset.
                Dim AuditMessage As StringBuilder = New StringBuilder()
                AuditMessage.Append(String.Format("An existing order was deleted at {0}. " + _
                 "The rowguid for the order is ", subscriberName))
                AuditMessage.Append(deletedDataSet.Tables(0).Rows(0)("rowguid").ToString())

                ' Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString()
                ' Set the history log level to the default verbose level.
                historyLogLevel = 1

                ' Accept the delete and apply it to the Publisher.
                Return ActionOnDataDelete.AcceptDelete
            Else
                Return MyBase.DeleteHandler(deleteSource, deletedDataSet, _
                 historyLogLevel, historyLogMessage)
            End If
        End Function
    End Class
End Namespace

O exemplo a seguir regista um conjunto de manipulador de lógica empresarial no Distribuidor e altera um artigo de fusão existente para usar essa lógica de negócios personalizada.

DECLARE @publication AS sysname;
DECLARE @article AS sysname;
DECLARE @friendlyname AS sysname;
DECLARE @assembly AS nvarchar(500);
DECLARE @class AS sysname;
SET @publication = N'AdvWorksCustomers';
SET @article = N'Customers';
SET @friendlyname = N'OrderEntryLogic';
SET @assembly = N'C:\Program Files\Microsoft SQL Server\120\COM\CustomLogic.dll';
SET @class = N'Microsoft.Samples.SqlServer.BusinessLogicHandler.OrderEntryBusinessLogicHandler';

-- Register the business logic handler at the Distributor.
EXEC sys.sp_registercustomresolver 
    @article_resolver = @friendlyname,
    @resolver_clsid = NULL,
    @is_dotnet_assembly = N'true',
    @dotnet_assembly_name = @assembly,
    @dotnet_class_name = @class;

-- Add an article that uses the business logic handler
-- at the Publisher.
EXEC sp_changemergearticle 
    @publication = @publication, 
    @article = @article,
    @property = N'article_resolver', 
    @value = @friendlyname,
    @force_invalidate_snapshot = 0,
    @force_reinit_subscription = 0;
GO

Usando RMO (Replication Management Objects, objetos de gerenciamento de replicação)

Para criar um manipulador de lógica de negócios

  1. No Microsoft Visual Studio, crie um novo projeto para o assembly .NET que contém o código que implementa o manipulador de lógica de negócios.

  2. Adicione referências ao projeto para os namespaces a seguir.

    Referência de montagem Localização
    Microsoft.SqlServer.Replication.BusinessLogicSupport < unidade>:\Arquivos de Programas\Microsoft SQL Server\nnn\COM (instalação padrão)
    System.Data GAC (componente do Framework .NET)
    System.Data.Common GAC (componente do Framework .NET)
  3. Adicione uma classe que substitua a classe BusinessLogicModule.

  4. Implemente a HandledChangeStates propriedade para indicar os tipos de alterações que o handler gere.

  5. Substitua um ou mais dos seguintes métodos da classe BusinessLogicModule:

    • CommitHandler - invocado quando uma alteração de dados é confirmada durante a sincronização.

    • DeleteErrorHandler - invocado se ocorrer um erro enquanto uma DELETE instrução está a ser carregada ou descarregada.

    • DeleteHandler - chamados quando as instruções DELETE estão a ser carregadas ou descarregadas.

    • InsertErrorHandler - invocado se ocorrer um erro quando uma INSERT instrução está a ser carregada ou descarregada.

    • InsertHandler - chamados quando as instruções INSERT estão a ser carregadas ou descarregadas.

    • UpdateConflictsHandler - invocado quando ocorrem instruções UPDATE conflitantes no Publisher e no Subscriber.

    • UpdateDeleteConflictHandler - invocado quando as instruções UPDATE entram em conflito com as instruções DELETE no Publicador e no Subscritor.

    • UpdateErrorHandler - invocado se ocorrer um erro quando uma UPDATE instrução está a ser carregada ou descarregada.

    • UpdateHandler - chamados quando as instruções UPDATE estão a ser carregadas ou descarregadas.

    Observação

    O resolvedor padrão do artigo trata de quaisquer conflitos de artigo que a sua lógica de negócio personalizada não gere explicitamente.

  6. Compile o projeto para criar o assembly do manipulador de lógica de negócios.

Para registrar um manipulador de lógica de negócios

  1. Crie uma conexão com o Distribuidor usando a classe ServerConnection.

  2. Crie uma instância da classe ReplicationServer. Passe o ServerConnection do passo 1.

  3. Chame EnumBusinessLogicHandlers e verifique o objeto ArrayList devolvido para garantir que a assemblagem ainda não está registada como processador de lógica de negócio.

  4. Crie uma instância da classe BusinessLogicHandler. Especifique as seguintes propriedades:

    • DotNetAssemblyName - o nome da montagem .NET. Se não implementares o assembly no mesmo diretório do executável Merge Agent, no mesmo diretório da aplicação que inicia sincronizadamente o Merge Agent, ou no GAC, inclui o caminho completo com o nome assembly. Você deve incluir o caminho completo com o nome do assembly ao usar um manipulador de lógica de negócios com sincronização da Web.

    • DotNetClassName - o nome totalmente qualificado da classe que sobrepõe BusinessLogicModule e implementa o manipulador de lógica de negócio.

    • FriendlyName - um nome amigável que você usa quando acessa o manipulador de lógica de negócios.

    • IsDotNetAssembly - um valor de verdadeiro.

Para implantar um manipulador de lógica de negócios

  1. Implemente o conjunto no servidor onde o Merge Agent é executado, na localização do ficheiro especificada aquando do registo do processador de lógica de negócio no Distribuidor. Numa subscrição pull, o agente é executado no Subscritor. Para uma subscrição push, o agente corre no Distribuidor. Quando usa sincronização Web, o agente corre no servidor Web. Se não incluir o caminho completo com o nome assembly ao registar o gestor de lógica de negócio, implemente o assembly no mesmo diretório do executável Merge Agent ou no mesmo diretório da aplicação que inicia o Merge Agent de forma síncrona. Se várias aplicações usarem o mesmo conjunto, instale o conjunto no GAC.

Para usar um manipulador de lógica de negócios com um novo artigo de tabela

  1. Crie uma conexão com o Publisher usando a classe ServerConnection.

  2. Crie uma instância da classe MergeArticle. Defina as seguintes propriedades:

  3. Chame o método Create. Para obter mais informações, consulte Definição de um artigo.

Para usar um manipulador de lógica de negócios com um elemento de tabela existente

  1. Crie uma conexão com o Publisher usando a classe ServerConnection.

  2. Crie uma instância da classe MergeArticle.

  3. Defina as propriedades Name, PublicationNamee DatabaseName.

  4. Defina a conexão da etapa 1 para a propriedade ConnectionContext.

  5. Chame o método LoadProperties para obter as propriedades do objeto. Se este método devolver falso, ou definiste incorretamente as propriedades do artigo no passo 3 ou o artigo não existe. Para obter mais informações, consulte Exibir e modificar propriedades do artigo.

  6. Defina o nome amigável do manipulador de lógica de negócios para ArticleResolver. Este valor é a FriendlyName propriedade que especifica ao registar o gestor de lógica de negócio.

Exemplos (RMO)

Este exemplo é um manipulador de lógica de negócios que registra informações sobre inserções, atualizações e exclusões no Assinante.

using System;
using System.Text;
using System.Data;
using System.Data.Common;
using Microsoft.SqlServer.Replication.BusinessLogicSupport;
using Microsoft.Samples.SqlServer.BusinessLogicHandler;

namespace Microsoft.Samples.SqlServer.BusinessLogicHandler
{
    public class OrderEntryBusinessLogicHandler :
      Microsoft.SqlServer.Replication.BusinessLogicSupport.BusinessLogicModule
    {
        // Variables to hold server names.
        private string publisherName;
        private string subscriberName;

        public OrderEntryBusinessLogicHandler()
        {
        }

        // Implement the Initialize method to get publication 
        // and subscription information.
        public override void Initialize(
            string publisher,
            string subscriber,
            string distributor,
            string publisherDB,
            string subscriberDB,
            string articleName)
        {
            // Set the Publisher and Subscriber names.
            publisherName = publisher;
            subscriberName = subscriber;
        }

        // Declare what types of row changes, conflicts, or errors to handle.
        override public ChangeStates HandledChangeStates
        {
            get
            {
                // Handle Subscriber inserts, updates and deletes.
                return ChangeStates.SubscriberInserts |
                  ChangeStates.SubscriberUpdates | ChangeStates.SubscriberDeletes;
            }
        }

        public override ActionOnDataChange InsertHandler(SourceIdentifier insertSource,
          DataSet insertedDataSet, ref DataSet customDataSet, ref int historyLogLevel,
          ref string historyLogMessage)
        {
            if (insertSource == SourceIdentifier.SourceIsSubscriber)
            {
                // Build a line item in the audit message to log the Subscriber insert.
                StringBuilder AuditMessage = new StringBuilder();
                AuditMessage.Append(String.Format("A new order was entered at {0}. " +
                  "The SalesOrderID for the order is :", subscriberName));
                AuditMessage.Append(insertedDataSet.Tables[0].Rows[0]["SalesOrderID"].ToString());
                AuditMessage.Append("The order must be shipped by :");
                AuditMessage.Append(insertedDataSet.Tables[0].Rows[0]["DueDate"].ToString());

                // Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString();
                
                // Set the history log level to the default verbose level.
                historyLogLevel = 1;

                // Accept the inserted data in the Subscriber's data set and 
                // apply it to the Publisher.
                return ActionOnDataChange.AcceptData;
            }
            else
            {
                return base.InsertHandler(insertSource, insertedDataSet, ref customDataSet,
                  ref historyLogLevel, ref historyLogMessage);
            }
        }

        public override ActionOnDataChange UpdateHandler(SourceIdentifier updateSource,
          DataSet updatedDataSet, ref DataSet customDataSet, ref int historyLogLevel,
          ref string historyLogMessage)
        {
            if (updateSource == SourceIdentifier.SourceIsPublisher)
            {
                // Build a line item in the audit message to log the Subscriber update.
                StringBuilder AuditMessage = new StringBuilder();
                AuditMessage.Append(String.Format("An existing order was updated at {0}. " +
                  "The SalesOrderID for the order is ", subscriberName));
                AuditMessage.Append(updatedDataSet.Tables[0].Rows[0]["SalesOrderID"].ToString());
                AuditMessage.Append("The order must now be shipped by :");
                AuditMessage.Append(updatedDataSet.Tables[0].Rows[0]["DueDate"].ToString());

                // Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString();
                // Set the history log level to the default verbose level.
                historyLogLevel = 1;

                // Accept the updated data in the Subscriber's data set and apply it to the Publisher.
                return ActionOnDataChange.AcceptData;
            }
            else
            {
                return base.UpdateHandler(updateSource, updatedDataSet,
                  ref customDataSet, ref historyLogLevel, ref historyLogMessage);
            }
        }

        public override ActionOnDataDelete DeleteHandler(SourceIdentifier deleteSource,
          DataSet deletedDataSet, ref int historyLogLevel, ref string historyLogMessage)
        {
            if (deleteSource == SourceIdentifier.SourceIsSubscriber)
            {
                // Build a line item in the audit message to log the Subscriber deletes.
                // Note that the rowguid is the only information that is 
                // available in the dataset.
                StringBuilder AuditMessage = new StringBuilder();
                AuditMessage.Append(String.Format("An existing order was deleted at {0}. " +
                  "The rowguid for the order is ", subscriberName));
                AuditMessage.Append(deletedDataSet.Tables[0].Rows[0]["rowguid"].ToString());

                // Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString();
                // Set the history log level to the default verbose level.
                historyLogLevel = 1;

                // Accept the delete and apply it to the Publisher.
                return ActionOnDataDelete.AcceptDelete;
            }
            else
            {
                return base.DeleteHandler(deleteSource, deletedDataSet,
                  ref historyLogLevel, ref historyLogMessage);
            }
        }
    }
}
Imports System
Imports System.Text
Imports System.Data
Imports System.Data.Common
Imports Microsoft.SqlServer.Replication.BusinessLogicSupport

Namespace Microsoft.Samples.SqlServer.BusinessLogicHandler
    Public Class OrderEntryBusinessLogicHandler
        Inherits BusinessLogicModule

        ' Variables to hold server names.
        Private publisherName As String
        Private subscriberName As String

        ' Implement the Initialize method to get publication 
        ' and subscription information.
        Public Overrides Sub Initialize( _
        ByVal publisher As String, _
        ByVal subscriber As String, _
        ByVal distributor As String, _
        ByVal publisherDB As String, _
        ByVal subscriberDB As String, _
        ByVal articleName As String _
      )
            ' Set the Publisher and Subscriber names.
            publisherName = publisher
            subscriberName = subscriber
        End Sub

        ' Declare what types of row changes, conflicts, or errors to handle.
        Public Overrides ReadOnly Property HandledChangeStates() As ChangeStates
            Get
                ' Handle Subscriber inserts, updates and deletes.
                Return (ChangeStates.SubscriberInserts Or _
                 ChangeStates.SubscriberUpdates Or ChangeStates.SubscriberDeletes)
            End Get
        End Property

        Public Overrides Function InsertHandler(ByVal insertSource As SourceIdentifier, _
        ByVal insertedDataSet As DataSet, ByRef customDataSet As DataSet, _
        ByRef historyLogLevel As Integer, ByRef historyLogMessage As String) _
        As ActionOnDataChange

            If insertSource = SourceIdentifier.SourceIsSubscriber Then
                ' Build a line item in the audit message to log the Subscriber insert.
                Dim AuditMessage As StringBuilder = New StringBuilder()
                AuditMessage.Append(String.Format("A new order was entered at {0}. " + _
                 "The SalesOrderID for the order is :", subscriberName))
                AuditMessage.Append(insertedDataSet.Tables(0).Rows(0)("SalesOrderID").ToString())
                AuditMessage.Append("The order must be shipped by :")
                AuditMessage.Append(insertedDataSet.Tables(0).Rows(0)("DueDate").ToString())

                ' Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString()

                ' Set the history log level to the default verbose level.
                historyLogLevel = 1

                ' Accept the inserted data in the Subscriber's data set and 
                ' apply it to the Publisher.
                Return ActionOnDataChange.AcceptData
            Else
                Return MyBase.InsertHandler(insertSource, insertedDataSet, customDataSet, _
                 historyLogLevel, historyLogMessage)
            End If
        End Function
        Public Overrides Function UpdateHandler(ByVal updateSource As SourceIdentifier, _
        ByVal updatedDataSet As DataSet, ByRef customDataSet As DataSet, _
        ByRef historyLogLevel As Integer, ByRef historyLogMessage As String) _
        As ActionOnDataChange

            If updateSource = SourceIdentifier.SourceIsPublisher Then
                ' Build a line item in the audit message to log the Subscriber update.
                Dim AuditMessage As StringBuilder = New StringBuilder()
                AuditMessage.Append(String.Format("An existing order was updated at {0}. " + _
                 "The SalesOrderID for the order is ", subscriberName))
                AuditMessage.Append(updatedDataSet.Tables(0).Rows(0)("SalesOrderID").ToString())
                AuditMessage.Append("The order must now be shipped by :")
                AuditMessage.Append(updatedDataSet.Tables(0).Rows(0)("DueDate").ToString())

                ' Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString()
                ' Set the history log level to the default verbose level.
                historyLogLevel = 1

                ' Accept the updated data in the Subscriber's data set and apply it to the Publisher.
                Return ActionOnDataChange.AcceptData
            Else
                Return MyBase.UpdateHandler(updateSource, updatedDataSet, _
                 customDataSet, historyLogLevel, historyLogMessage)
            End If
        End Function
        Public Overrides Function DeleteHandler(ByVal deleteSource As SourceIdentifier, _
        ByVal deletedDataSet As DataSet, ByRef historyLogLevel As Integer, _
         ByRef historyLogMessage As String) As ActionOnDataDelete
            If deleteSource = SourceIdentifier.SourceIsSubscriber Then
                ' Build a line item in the audit message to log the Subscriber deletes.
                ' Note that the rowguid is the only information that is 
                ' available in the dataset.
                Dim AuditMessage As StringBuilder = New StringBuilder()
                AuditMessage.Append(String.Format("An existing order was deleted at {0}. " + _
                 "The rowguid for the order is ", subscriberName))
                AuditMessage.Append(deletedDataSet.Tables(0).Rows(0)("rowguid").ToString())

                ' Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString()
                ' Set the history log level to the default verbose level.
                historyLogLevel = 1

                ' Accept the delete and apply it to the Publisher.
                Return ActionOnDataDelete.AcceptDelete
            Else
                Return MyBase.DeleteHandler(deleteSource, deletedDataSet, _
                 historyLogLevel, historyLogMessage)
            End If
        End Function
    End Class
End Namespace

Este exemplo registra um manipulador de lógica de negócios no Distribuidor.

// Specify the Distributor name and business logic properties.
string distributorName = publisherInstance;
string assemblyName = @"C:\Program Files\Microsoft SQL Server\110\COM\CustomLogic.dll";
string className = "Microsoft.Samples.SqlServer.BusinessLogicHandler.OrderEntryBusinessLogicHandler";
string friendlyName = "OrderEntryLogic";

ReplicationServer distributor;
BusinessLogicHandler customLogic;

    // Create a connection to the Distributor.
ServerConnection distributorConn = new ServerConnection(distributorName);

try
{
    // Connect to the Distributor.
    distributorConn.Connect();

    // Set the Distributor properties.
    distributor = new ReplicationServer(distributorConn);

    // Set the business logic handler properties.
    customLogic = new BusinessLogicHandler();
    customLogic.DotNetAssemblyName = assemblyName;
    customLogic.DotNetClassName = className;
    customLogic.FriendlyName = friendlyName;
    customLogic.IsDotNetAssembly = true;

    Boolean isRegistered = false;

    // Check if the business logic handler is already registered at the Distributor.
    foreach (BusinessLogicHandler registeredLogic
        in distributor.EnumBusinessLogicHandlers())
    {
        if (registeredLogic == customLogic)
        {
            isRegistered = true;
        }
    }

    // Register the custom logic.
    if (!isRegistered)
    {
        distributor.RegisterBusinessLogicHandler(customLogic);
    }
}
catch (Exception ex)
{
    // Do error handling here.
    throw new ApplicationException(string.Format(
        "The {0} assembly could not be registered.",
        assemblyName), ex);
}
finally
{
    distributorConn.Disconnect();
}
' Specify the Distributor name and business logic properties.
Dim distributorName As String = publisherInstance
Dim assemblyName As String = "C:\Program Files\Microsoft SQL Server\110\COM\CustomLogic.dll"
Dim className As String = "Microsoft.Samples.SqlServer.BusinessLogicHandler.OrderEntryBusinessLogicHandler"
Dim friendlyName As String = "OrderEntryLogic"

Dim distributor As ReplicationServer
Dim customLogic As BusinessLogicHandler

' Create a connection to the Distributor.
Dim distributorConn As ServerConnection = New ServerConnection(distributorName)

Try
    ' Connect to the Distributor.
    distributorConn.Connect()

    ' Set the Distributor properties.
    distributor = New ReplicationServer(distributorConn)

    ' Set the business logic handler properties.
    customLogic = New BusinessLogicHandler()
    customLogic.DotNetAssemblyName = assemblyName
    customLogic.DotNetClassName = className
    customLogic.FriendlyName = friendlyName
    customLogic.IsDotNetAssembly = True

    Dim isRegistered As Boolean = False

    ' Check if the business logic handler is already registered at the Distributor.
    For Each registeredLogic As BusinessLogicHandler _
    In distributor.EnumBusinessLogicHandlers
        If registeredLogic Is customLogic Then
            isRegistered = True
        End If
    Next

    ' Register the custom logic.
    If Not isRegistered Then
        distributor.RegisterBusinessLogicHandler(customLogic)
    End If
Catch ex As Exception
    ' Do error handling here.
    Throw New ApplicationException(String.Format( _
     "The {0} assembly could not be registered.", _
     assemblyName), ex)
Finally
    distributorConn.Disconnect()
End Try

Este exemplo altera um artigo existente para usar o manipulador de lógica de negócios.

// Define the Publisher, publication, and article names.
string publisherName = publisherInstance;
string publicationName = "AdvWorksSalesOrdersMerge";
string publicationDbName = "AdventureWorks2022";
string articleName = "SalesOrderHeader";

// Set the friendly name of the business logic handler.
string customLogic = "OrderEntryLogic";

MergeArticle article = new MergeArticle();

// Create a connection to the Publisher.
ServerConnection conn = new ServerConnection(publisherName);

try
{
    // Connect to the Publisher.
    conn.Connect();

    // Set the required properties for the article.
    article.ConnectionContext = conn;
    article.Name = articleName;
    article.DatabaseName = publicationDbName;
    article.PublicationName = publicationName;

    // Load the article properties.
    if (article.LoadProperties())
    {
        article.ArticleResolver = customLogic;
    }
    else
    {
        // Throw an exception of the article does not exist.
        throw new ApplicationException(String.Format(
        "{0} is not published in {1}", articleName, publicationName));
    }
    
}
catch (Exception ex)
{
    // Do error handling here and rollback the transaction.
    throw new ApplicationException(String.Format(
        "The business logic handler {0} could not be associated with " +
        " the {1} article.",customLogic,articleName), ex);
}
finally
{
    conn.Disconnect();
}
' Define the Publisher, publication, and article names.
Dim publisherName As String = publisherInstance
Dim publicationName As String = "AdvWorksSalesOrdersMerge"
Dim publicationDbName As String = "AdventureWorks2022"
Dim articleName As String = "SalesOrderHeader"

' Set the friendly name of the business logic handler.
Dim customLogic As String = "OrderEntryLogic"

Dim article As MergeArticle = New MergeArticle()

' Create a connection to the Publisher.
Dim conn As ServerConnection = New ServerConnection(publisherName)

Try
    ' Connect to the Publisher.
    conn.Connect()

    ' Set the required properties for the article.
    article.ConnectionContext = conn
    article.Name = articleName
    article.DatabaseName = publicationDbName
    article.PublicationName = publicationName

    ' Load the article properties.
    If article.LoadProperties() Then
        article.ArticleResolver = customLogic
    Else
        ' Throw an exception of the article does not exist.
        Throw New ApplicationException(String.Format( _
         "{0} is not published in {1}", articleName, publicationName))
    End If

Catch ex As Exception
    ' Do error handling here and rollback the transaction.
    Throw New ApplicationException(String.Format( _
     "The business logic handler {0} could not be associated with " + _
     " the {1} article.", customLogic, articleName), ex)
Finally
    conn.Disconnect()
End Try