Implementazione di un gestore della logica di business per un articolo di mergeImplement a Business Logic Handler for a Merge Article

In questo argomento viene descritto come implementare un gestore della logica di business per un articolo di tipo merge in SQL Server 2017SQL Server 2017 tramite la programmazione della replica o RMO (Replication Management Objects).This topic describes how to implement a business logic handler for a merge article in SQL Server 2017SQL Server 2017 by using replication programming or Replication Management Objects (RMO).

Lo spazio dei nomi Microsoft.SqlServer.Replication.BusinessLogicSupport implementa un'interfaccia che consente di scrivere logica di business complessa per gestire gli eventi che si verificano durante il processo di sincronizzazione della replica di tipo merge.The Microsoft.SqlServer.Replication.BusinessLogicSupport namespace implements an interface that enables you to write complex business logic to handle events that occur during the merge replication synchronization process. I metodi del gestore della logica di business possono essere richiamati dal processo di replica per ogni riga modificata che viene replicata durante la sincronizzazione.Methods in the business logic handler can be invoked by the replication process for each changed row that is replicated during synchronization.

Il processo generale per l'implementazione di un gestore della logica di business è il seguente:The general process for implementing a business logic handler is:

  1. Creazione dell'assembly del gestore della logica di business.Create the business logic hander assembly.

  2. Registrazione dell'assembly nel server di distribuzione.Register the assembly at the Distributor.

  3. Distribuzione dell'assembly nel server in cui viene eseguito l'agente di merge.Deploy the assembly at the server on which the Merge Agent runs. Per una sottoscrizione pull, l'agente viene eseguito nel Sottoscrittore, mentre per una sottoscrizione push nel server di distribuzione.For a pull subscription the agent runs on the Subscriber, and for a push subscription the agent runs on the Distributor. Quando si utilizza la sincronizzazione tramite il Web, l'agente viene eseguito nel server Web.When you are using Web synchronization, the agent runs on the Web server.

  4. Creazione di un articolo che utilizza il gestore della logica di business o modifica di un articolo esistente per l'utilizzo del gestore della logica di business.Create an article that uses the business logic handler or modify an existing article to use the business logic handler.

    Il gestore della logica di business specificato viene eseguito per ogni riga sincronizzata.The business logic handler you specify is executed for every row that is synchronized. La complessità della logica e le chiamate ad altre applicazioni o servizi di rete possono ridurre le prestazioni.Complex logic and calls to other applications or network services can impact performance. Per altre informazioni sui gestori della logica di business, vedere Eseguire logiche di business durante la sincronizzazione di tipo merge.For more information about business logic handlers, see Execute Business Logic During Merge Synchronization.

    Contenuto dell'argomentoIn This Topic

Utilizzo della programmazione della replica Using Replication Programming

Per creare e distribuire un gestore della logica di businessTo create and deploy a business logic handler

  1. In MicrosoftMicrosoft Visual Studio creare un nuovo progetto per l'assembly .NET contenente il codice che implementa il gestore della logica di business.In MicrosoftMicrosoft Visual Studio, create a new project for the .NET assembly that contains the code that implements the business logic handler.

  2. Aggiungere i riferimenti al progetto per gli spazi dei nomi seguenti.Add references to the project for the following namespaces.

    Riferimento all'assemblyAssembly Reference PercorsoLocation
    Microsoft.SqlServer.Replication.BusinessLogicSupport C:\Program Files\Microsoft SQL Server\nnn\C:\Program Files\Microsoft SQL Server\nnn\COM (installazione predefinita)COM (default installation)
    System.Data GAC (componente di .NET Framework)GAC (component of the .NET Framework)
    System.Data.Common GAC (componente di .NET Framework)GAC (component of the .NET Framework)
  3. Aggiungere una classe che esegue l'override della classe BusinessLogicModule .Add a class that overrides the BusinessLogicModule class.

  4. Implementare la proprietà HandledChangeStates per indicare i tipi di modifiche gestite.Implement the HandledChangeStates property to indicate the types of changes that are handled.

  5. Eseguire l'override di uno o più dei seguenti metodi della classe BusinessLogicModule :Override one or more of the following methods of the BusinessLogicModule class:

    • CommitHandler : viene richiamato quando si esegue il commit di una modifica ai dati durante la sincronizzazione.CommitHandler - invoked when a data change is committed during synchronization.

    • DeleteErrorHandler : viene richiamato se si verifica un errore durante il caricamento o il download di un'istruzione DELETE.DeleteErrorHandler - invoked when an error occurs when a DELETE statement is being uploaded or downloaded.

    • DeleteHandler : viene richiamato durante il caricamento o il download delle istruzioni DELETE.DeleteHandler - invoked when DELETE statements are being uploaded or downloaded.

    • InsertErrorHandler : viene richiamato se si verifica un errore durante il caricamento o il download di un'istruzione INSERT.InsertErrorHandler - invoked when an error occurs when an INSERT statement is being uploaded or downloaded.

    • InsertHandler : viene richiamato durante il caricamento o il download delle istruzioni INSERT.InsertHandler - invoked when INSERT statements are being uploaded or downloaded.

    • UpdateConflictsHandler : viene richiamato quando si verificano conflitti di istruzioni UPDATE nel server di pubblicazione e nel Sottoscrittore.UpdateConflictsHandler - invoked when conflicting UPDATE statements occur at the Publisher and Subscriber.

    • UpdateDeleteConflictHandler : viene richiamato quando si verificano conflitti tra istruzioni UPDATE e istruzioni DELETE nel server di pubblicazione e nel Sottoscrittore.UpdateDeleteConflictHandler - invoked when UPDATE statements conflict with DELETE statements at the Publisher and Subscriber.

    • UpdateErrorHandler : viene richiamato se si verifica un errore durante il caricamento o il download di un'istruzione UPDATE.UpdateErrorHandler - invoked when an error occurs when an UPDATE statement is being uploaded or downloaded.

    • UpdateHandler : viene richiamato durante il caricamento o il download delle istruzioni UPDATE.UpdateHandler - invoked when UPDATE statements are being uploaded or downloaded.

  6. Compilare il progetto per creare l'assembly del gestore della logica di business.Build the project to create the business logic handler assembly.

  7. Distribuire l'assembly nella directory che contiene il file eseguibile dell'agente di merge (replmerg.exe), che per un'installazione predefinita è C:\Program Files\Microsoft SQL Server\nnn\C:\Program Files\Microsoft SQL Server\nnn\COM, o installarlo nella Global Assembly Cache (GAC) .NET.Deploy the assembly in the directory that contains the Merge Agent executable file (replmerg.exe), which for a default installation is C:\Program Files\Microsoft SQL Server\nnn\C:\Program Files\Microsoft SQL Server\nnn\COM, or install it in the .NET global assembly cache (GAC). È necessario installare l'assembly nella GAC solo se applicazioni diverse dall'agente di merge richiedono l'accesso all'assembly.You should only install the assembly in the GAC if applications other than the Merge Agent require access to the assembly. L'assembly può essere installato nella GAC tramite lo strumento Global Assembly Cache (Gacutil.exe) disponibile in .NET Framework SDK.The assembly can be installed into the GAC using the Global Assembly Cache tool (Gacutil.exe) provided in the .NET Framework SDK.

    Nota

    È necessario distribuire un gestore della logica di business su ogni server in cui viene eseguito l'agente di merge, incluso il server IIS che ospita il file replisapi.dll quando si utilizza la sincronizzazione tramite il Web.A business logic handler must be deployed on every server on which the Merge Agent runs, which includes the IIS server that hosts the replisapi.dll when using Web synchronization.

Per registrare un gestore della logica di businessTo register a business logic handler

  1. Nel server di pubblicazione eseguire sp_enumcustomresolvers (Transact-SQL) per verificare che l'assembly non sia già stato registrato come gestore della logica di business.At the Publisher, execute sp_enumcustomresolvers (Transact-SQL) to verify that the assembly has not already been registered as a business logic handler.

  2. Nel database di distribuzione eseguire sp_registercustomresolver (Transact-SQL), specificando un nome descrittivo per il gestore della logica di business per @article_resolver, un valore true per @is_dotnet_assembly, il nome dell'assembly per @dotnet_assembly_name e il nome completo della classe che esegue l'override di BusinessLogicModule per @dotnet_class_name.At the Distributor, execute sp_registercustomresolver (Transact-SQL), specifying a friendly name for the business logic handler for @article_resolver, a value of true for @is_dotnet_assembly, the name of the assembly for @dotnet_assembly_name, and the fully-qualified name of the class that overrides BusinessLogicModule for @dotnet_class_name.

    Nota

    Se l'assembly non viene distribuito nella stessa directory dell'eseguibile dell'agente di merge, nella stessa directory dell'applicazione che avvia in modo sincrono l'agente di merge o nella Global Assembly Cache (GAC), è necessario specificare il percorso completo con il nome dell'assembly per @dotnet_assembly_name.If the assembly is not deployed in the same directory as the Merge Agent executable, in the same directory as the application that synchronously starts the Merge Agent, or in the global assembly cache (GAC), you need to specify the full path with the assembly name for @dotnet_assembly_name. Quando si utilizza la sincronizzazione tramite il Web, è necessario specificare il percorso dell'assembly nel server Web.When using Web synchronization, you must specify the location of assembly at the Web server.

Per utilizzare un gestore della logica di business con un nuovo articolo di tabellaTo use a business logic handler with a new table article

  1. Eseguire sp_addmergearticle (Transact-SQL) per definire l'articolo, specificando il nome descrittivo del gestore della logica di business per @article_resolver.Execute sp_addmergearticle (Transact-SQL) to define an article, specifying the friendly name of the business logic handler for @article_resolver. Per altre informazioni, vedere Define an Article.For more information, see Define an Article.

Per utilizzare un gestore della logica di business con un articolo di tabella esistenteTo use a business logic handler with an existing table article

  1. Eseguire sp_addmergearticle (Transact-SQL), specificando @publication, @article, il valore article_resolver per @property e il nome descrittivo del gestore della logica di business per @value.Execute sp_changemergearticle (Transact-SQL), specifying @publication, @article, a value of article_resolver for @property, and the friendly name of the business logic handler for @value.

Esempi (programmazione della replica) Examples (Replication Programming)

In questo esempio è illustrato un gestore della logica di business che crea un log di controllo.This example shows a business logic handler that creates an audit log.

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

Nell'esempio seguente viene registrato un assembly del gestore della logica di business nel database di distribuzione e viene modificato un articolo di merge esistente per l'utilizzo di questa logica di business personalizzata.The following example registers a business logic handler assembly at the Distributor and changes an existing merge article to use this custom business logic.

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

Utilizzo di RMO (Replication Management Objects) Using Replication Management Objects (RMO)

Per creare un gestore della logica di businessTo create a business logic handler

  1. In MicrosoftMicrosoft Visual Studio creare un nuovo progetto per l'assembly .NET contenente il codice che implementa il gestore della logica di business.In MicrosoftMicrosoft Visual Studio, create a new project for the .NET assembly that contains the code that implements the business logic handler.

  2. Aggiungere i riferimenti al progetto per gli spazi dei nomi seguenti.Add references to the project for the following namespaces.

    Riferimento all'assemblyAssembly Reference PercorsoLocation
    Microsoft.SqlServer.Replication.BusinessLogicSupport C:\Program Files\Microsoft SQL Server\nnn\C:\Program Files\Microsoft SQL Server\nnn\COM (installazione predefinita)COM (default installation)
    System.Data GAC (componente di .NET Framework)GAC (component of the .NET Framework)
    System.Data.Common GAC (componente di .NET Framework)GAC (component of the .NET Framework)
  3. Aggiungere una classe che esegue l'override della classe BusinessLogicModule .Add a class that overrides the BusinessLogicModule class.

  4. Implementare la proprietà HandledChangeStates per indicare i tipi di modifiche gestite.Implement the HandledChangeStates property to indicate the types of changes that are handled.

  5. Eseguire l'override di uno o più dei seguenti metodi della classe BusinessLogicModule :Override one or more of the following methods of the BusinessLogicModule class:

    • CommitHandler : viene richiamato quando si esegue il commit di una modifica ai dati durante la sincronizzazione.CommitHandler - invoked when a data change is committed during synchronization.

    • DeleteErrorHandler : viene richiamato se si verifica un errore durante il caricamento o il download di un'istruzione DELETE.DeleteErrorHandler - invoked if an error occurs while a DELETE statement is being uploaded or downloaded.

    • DeleteHandler : viene richiamato durante il caricamento o il download delle istruzioni DELETE.DeleteHandler - invoked when DELETE statements are being uploaded or downloaded.

    • InsertErrorHandler : viene richiamato se si verifica un errore durante il caricamento o il download di un'istruzione INSERT.InsertErrorHandler - invoked if an error occurs when an INSERT statement is being uploaded or downloaded.

    • InsertHandler : viene richiamato durante il caricamento o il download delle istruzioni INSERT.InsertHandler - invoked when INSERT statements are being uploaded or downloaded.

    • UpdateConflictsHandler : viene richiamato quando si verificano conflitti di istruzioni UPDATE nel server di pubblicazione e nel Sottoscrittore.UpdateConflictsHandler - invoked when conflicting UPDATE statements occur at the Publisher and Subscriber.

    • UpdateDeleteConflictHandler : viene richiamato quando si verificano conflitti tra istruzioni UPDATE e istruzioni DELETE nel server di pubblicazione e nel Sottoscrittore.UpdateDeleteConflictHandler - invoked when UPDATE statements conflict with DELETE statements at the Publisher and Subscriber.

    • UpdateErrorHandler : viene richiamato se si verifica un errore durante il caricamento o il download di un'istruzione UPDATE.UpdateErrorHandler - invoked if an error occurs when an UPDATE statement is being uploaded or downloaded.

    • UpdateHandler : viene richiamato durante il caricamento o il download delle istruzioni UPDATE.UpdateHandler - invoked when UPDATE statements are being uploaded or downloaded.

    Nota

    I conflitti di articoli non gestiti in modo esplicito dalla logica di business personalizzata vengono gestiti dal sistema di risoluzione predefinito per l'articolo.Any article conflicts not explicitly handled by your custom business logic are handled by the default resolver for the article.

  6. Compilare il progetto per creare l'assembly del gestore della logica di business.Build the project to create the business logic handler assembly.

Per registrare un gestore della logica di businessTo register a business logic handler

  1. Creare una connessione al server di distribuzione tramite la classe ServerConnection .Create a connection to the Distributor by using the ServerConnection class.

  2. Creare un'istanza della classe ReplicationServer .Create an instance of the ReplicationServer class. Passare il valore di ServerConnection ottenuto al passaggio 1.Pass the ServerConnection from step 1.

  3. Chiamare EnumBusinessLogicHandlers e controllare l'oggetto ArrayList restituito per verificare che l'assembly non sia già stato registrato come gestore della logica di business.Call EnumBusinessLogicHandlers and check the returned ArrayList object to ensure that the assembly has not already been registered as a business logic handler.

  4. Creare un'istanza della classe BusinessLogicHandler .Create an instance of the BusinessLogicHandler class. Specificare le proprietà seguenti:Specify the following properties:

    • DotNetAssemblyName : nome dell'assembly .NET.DotNetAssemblyName - the name of the .NET assembly. Se l'assembly non viene distribuito nella stessa directory del file eseguibile dell'agente di merge, nella stessa directory dell'applicazione che avvia in modo sincrono l'agente di merge o nella GAC (Global Assembly Cache), è necessario includere il percorso completo con il nome dell'assembly.If the assembly is not deployed in the same directory as the Merge Agent executable, in the same directory as the application that synchronously starts the Merge Agent, or in the GAC, you must include the full path with the assembly name. È necessario includere il percorso completo con il nome dell'assembly quando si utilizza un gestore della logica di business con la sincronizzazione tramite il Web.You must include the full path with the assembly name when using a business logic handler with Web synchronization.

    • DotNetClassName : nome completo della classe che esegue l'override di BusinessLogicModule e implementa il gestore della logica di business.DotNetClassName - the fully-qualified name of the class that overrides BusinessLogicModule and implements the business logic handler.

    • FriendlyName : nome descrittivo utilizzato per l'accesso al gestore della logica di business.FriendlyName - a friendly name you use when you access the business logic handler.

    • IsDotNetAssembly : valore true.IsDotNetAssembly - a value of true.

Per distribuire un gestore della logica di businessTo deploy a business logic handler

  1. Distribuire l'assembly nel server in cui viene eseguito l'agente merge, nel percorso file specificato durante la registrazione del gestore della logica di business nel server di distribuzione.Deploy the assembly on the server where the Merge Agent runs in the file location specified when the business logic handler was registered at the Distributor. Per una sottoscrizione pull, l'agente viene eseguito nel Sottoscrittore, mentre per una sottoscrizione push nel server di distribuzione.For a pull subscription the agent runs on the Subscriber, and for a push subscription the agent runs on the Distributor. Quando si utilizza la sincronizzazione tramite il Web, l'agente viene eseguito nel server Web.When you are using Web synchronization, the agent runs on the Web server. Se con il nome dell'assembly non è stato incluso il percorso completo durante la registrazione del gestore della logica di business, distribuire l'assembly nella stessa directory del file eseguibile dell'agente di merge o nella stessa directory dell'applicazione che avvia in modo sincrono l'agente di merge.If the full path was not included with the assembly name when the business logic handler was registered, deploy the assembly in the same directory as the Merge Agent executable, in the same directory as the application that synchronously starts the Merge Agent. È possibile installare l'assembly nella GAC se più applicazioni utilizzano lo stesso assembly.You may install the assembly in the GAC if there are multiple applications that use the same assembly.

Per utilizzare un gestore della logica di business con un nuovo articolo di tabellaTo use a business logic handler with a new table article

  1. Creare una connessione al server di pubblicazione tramite la classe ServerConnection .Create a connection to the Publisher by using the ServerConnection class.

  2. Creare un'istanza della classe MergeArticle .Create an instance of the MergeArticle class. Impostare le proprietà seguenti:Set the following properties:

  3. Chiamare il metodo Create .Call the Create method. Per altre informazioni, vedere Define an Article.For more information, see Define an Article.

Per utilizzare un gestore della logica di business con un articolo di tabella esistenteTo use a business logic handler with an existing table article

  1. Creare una connessione al server di pubblicazione tramite la classe ServerConnection .Create a connection to the Publisher by using the ServerConnection class.

  2. Creare un'istanza della classe MergeArticle .Create an instance of the MergeArticle class.

  3. Impostare le proprietà Name, PublicationNamee DatabaseName .Set the Name, PublicationName, and DatabaseName properties.

  4. Impostare la connessione del passaggio 1 per la proprietà ConnectionContext .Set the connection from step 1 for the ConnectionContext property.

  5. Chiamare il metodo LoadProperties per recuperare le proprietà dell'oggetto.Call the LoadProperties method to get the properties of the object. Se questo metodo restituisce false, le proprietà dell'articolo sono state definite in modo non corretto nel passaggio 3 oppure l'articolo non esiste.If this method returns false, either the article properties in step 3 were defined incorrectly or the article does not exist. Per altre informazioni, vedere View and Modify Article Properties.For more information, see View and Modify Article Properties.

  6. Impostare il nome descrittivo del gestore della logica di business per ArticleResolver.Set the friendly name of the business logic handler for ArticleResolver. Si tratta del valore della proprietà FriendlyName specificato durante la registrazione del gestore della logica di business.This is the value of the FriendlyName property specified when registering the business logic handler.

Esempi (RMO) Examples (RMO)

In questo esempio è illustrato un gestore della logica di business che registra informazioni sulle operazioni di inserimento, aggiornamento ed eliminazione nel Sottoscrittore.This example is a business logic handler that logs information about inserts, updates, and deletes at the Subscriber.

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

In questo esempio viene registrato un gestore della logica di business nel server di distribuzione.This example registers a business logic handler at the Distributor.

// 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

In questo esempio viene modificato un articolo esistente per l'utilizzo del gestore della logica di business.This example changes an existing article to use the business logic handler.

// Define the Publisher, publication, and article names.
string publisherName = publisherInstance;
string publicationName = "AdvWorksSalesOrdersMerge";
string publicationDbName = "AdventureWorks2012";
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 = "AdventureWorks2012"
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

Vedere ancheSee Also

Implementare un sistema di risoluzione dei conflitti personalizzato per un articolo di tipo merge Implement a Custom Conflict Resolver for a Merge Article
Eseguire il debug di un gestore della logica di business (programmazione della replica) Debug a Business Logic Handler (Replication Programming)
Procedure consigliate per la sicurezza della replica Replication Security Best Practices
Concetti di base relativi a RMO (Replication Management Objects)Replication Management Objects Concepts