Cómo: Realizar una transacción distribuida con un proveedor de .NET utilizando ServicedComponent en .NET Visual C#

Para una versión de Microsoft Visual Basic .NET de este artículo, consulte 316627 .


En este artículo se refiere a los siguientes espacios de nombres de biblioteca de clases de Microsoft.NET Framework:

  • System.Data.SqlClient
  • System.EnterpriseServices
  • System.Runtime.CompilerServices
  • System.Reflection

EN ESTA TAREA

Resumen

En este artículo paso a paso se muestra cómo realizar una transacción distribuida mediante un proveedor de .NET con la clase ServicedComponent . Aunque este artículo utiliza el proveedor SqlClient .NET contra un servidor de Microsoft SQL Server, también puede utilizar el proveedor administrado de ODBC u OLE DB. NET.

Requisitos

La lista siguiente describe el hardware recomendado, software, infraestructura de red y service packs que se necesitan:

  • Microsoft Windows 2000 Professional, Microsoft Windows 2000 Server, Microsoft Windows 2000 Advanced Server
  • Microsoft Visual Studio .NET
  • Microsoft SQL Server 7.0 o Microsoft SQL Server 2000

Información general

Instancias de una clase de.NET Framework pueden participar en una transacción automática si prepara la clase para ello. Cada recurso que tiene acceso una instancia de clase o un objeto se inscribe en la transacción. Por ejemplo, si un objeto utiliza ADO.NET para enviar dinero a una cuenta en una base de datos, el Administrador de recursos de la base de datos determina si el objeto se ejecuta en una transacción. Si el objeto se debe ejecutar en una transacción, el Administrador de recursos inscribe automáticamente la base de datos en la transacción.

Utilice el proceso siguiente para preparar una clase para participar en una transacción automática:

  1. La clase TransactionAttribute se aplican a la clase para especificar el tipo de transacción automática que solicite el componente.

    El tipo de transacción debe ser un miembro de la enumeración TransactionOption .
  2. Derive la clase de la clase ServicedComponent . ServicedComponent es la clase base de todas las clases que utilizan servicios COM +.
  3. Firmar el ensamblado con un nombre seguro para asegurarse de que el ensamblado contiene un único par de claves.
  4. Registre el ensamblado que contiene la clase con el catálogo de COM +.

    Nota: si el cliente que llama a una instancia de la clase es administrado por common language runtime, el registro se realiza automáticamente. Este paso es necesario sólo si un llamador no administrado crea y llama a instancias de su clase. Utilice la herramienta de instalación de servicios de .NET (Regsvcs.exe) para registrar manualmente el ensamblado.
Para obtener más información acerca de cómo firmar un ensamblado con un nombre seguro, vea el tema siguiente en la Guía del desarrollador de Microsoft.NET Framework:

Firmar un ensamblado con un nombre seguro
http://msdn.microsoft.com/en-us/library/xc31ft41.aspx
Para obtener más información acerca de este proceso, consulte el tema siguiente en la Guía del desarrollador de Microsoft.NET Framework:

Transacciones automáticas y clases de.NET Framework
http://msdn.microsoft.com/en-us/library/ms123400.aspx

Crear el proyecto

  1. Siga estos pasos para crear un nuevo proyecto de aplicación de consola en Visual .NET C#:
    1. Inicie Visual Studio. NET.
    2. En el menú archivo, elija nuevo y, a continuación, haga clic en proyecto.
    3. En el cuadro de diálogo Nuevo proyecto , haga clic en Proyectos de Visual C# en Tipos de proyecto, haga clic en Aplicación de consola en plantillasy, a continuación, haga clic en Aceptar.
    4. En el Explorador de soluciones, cambie el nombre del archivo Class1.cs DistributedTransaction.cs.
  2. Elimine todo el código desde el archivo DistributedTransaction.cs.
  3. En el menú proyecto , haga clic en Agregar referenciay, a continuación, agregue las siguientes referencias:
    • System.EnterpriseServices
    • System.Data.dll

  4. En el archivo AssemblyInfo.cs, comente las líneas siguientes de código:
    [assembly: AssemblyKeyFile("")][assembly: AssemblyKeyName("")]

  5. Agregue el código siguiente al archivo DistributedTransaction.cs:
    using System;using System.Data.SqlClient;
    using System.EnterpriseServices;
    using System.Runtime.CompilerServices;
    using System.Reflection;

    [assembly: ApplicationName("DistributedTransaction")]
    [assembly: AssemblyKeyFileAttribute("..\..\DistributedTransaction.snk")]


    namespace DistributedTransaction
    {
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    class Class1
    {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
    try
    {
    DistributedTran myDistributedTran = new DistributedTran();
    myDistributedTran.TestDistributedTransaction();
    }
    catch (System.Data.SqlClient.SqlException e)
    {
    System.Console.WriteLine("Transaction Aborted: Error returned: " + e.Message);
    }
    }
    }
    /// <summary>
    /// Summary description for TestApp.
    /// </summary>
    [Transaction(TransactionOption.Required)]
    public class DistributedTran: ServicedComponent
    {
    public DistributedTran()
    {
    }
    [AutoComplete]
    public string TestDistributedTransaction()
    {
    // The following Insert statement goes to the first server.
    // This Insert statement does not produce any errors.
    String insertCmdSql = "Insert Into TestTransaction (Col1, Col2) Values (1,'Sql Test')";

    // The following Delete statement goes to the second server.
    // Because the table does not exist, this code throws an exception.
    String exceptionCausingCmdSQL = "Delete from NonExistentTable";

    // The following connection strings create instances of two SqlConnection objects
    // to connect to two different SQL Server servers in your environment.
    // Modify the connection strings as necessary for your environment.
    SqlConnection SqlConn1 = new SqlConnection("Server=Server_Name;uid=User_Id;database=DatabaseName;pwd=Password");
    SqlConnection SqlConn2 = new SqlConnection("Server=Server_Name;uid=User_Id;database=DatabaseName;pwd=Password");

    try
    {
    SqlCommand insertCmd = new SqlCommand(insertCmdSql,SqlConn1);
    SqlCommand exceptionCausingCmd = new SqlCommand(exceptionCausingCmdSQL,SqlConn2);

    // This command runs properly.
    insertCmd.Connection.Open();
    insertCmd.ExecuteNonQuery();


    // This command results in an exception, which automatically rolls back
    // the first command (the insertCmd command).
    exceptionCausingCmd.Connection.Open();
    int cmdResult = exceptionCausingCmd.ExecuteNonQuery();

    SqlConn1.Close();
    SqlConn2.Close();

    Console.WriteLine("Hello");

    }
    catch (System.Data.SqlClient.SqlException ex)
    {
    // After you catch the exception in this function, throw it.
    // The service component receives this exception and
    // aborts the transaction. The service component then
    // throws the same exception, and the calling function
    // receives the error message.
    Console.WriteLine (ex.Message);
    throw (ex);
    }
    finally
    {
    // Close the connection.
    if (SqlConn1.State.ToString() == "Open")
    SqlConn1.Close();

    if (SqlConn2.State.ToString() == "Open")
    SqlConn2.Close();
    }

    return "Success";

    }

    }
    }

  6. En el menú archivo , haga clic en Guardar todo.
  7. Haga clic en Inicio, seleccione programas, Microsoft Visual Studio. NET, Herramientas de Visual Studio .NETy, a continuación, haga clic en símbolo del sistema de Visual Studio. NET.
  8. Abra la carpeta que contiene el proyecto y, a continuación, ejecute el comando siguiente para firmar el ensamblado con un nombre seguro:
    sn -k DistributedTransaction.snk
  9. Generar la aplicación.
  10. En el primer servidor de SQL Server, cree la siguiente tabla:
    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[TestTransaction]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)drop table [dbo].[TestTransaction]
    GO

    CREATE TABLE [dbo].[TestTransaction] (
    [Col1] [int] NULL ,
    [Col2] [varchar] (100) NULL
    ) ON [PRIMARY]
    GO

  11. Ejecutar la aplicación. Observe que recibe el siguiente mensaje de error (que es el comportamiento esperado):
    Transacción anulada: Mensaje de error: nombre de objeto no válido 'NonExistentTable'.
  12. Abra el analizador de consultas de SQL Server, agregue el código siguiente y, a continuación, presione F5 para ejecutar la consulta:
    USE NORTHWIND;SELECT * FROM TestTransaction WHERE Col1=1 AND Col2='Sql Test'

    Tenga en cuenta que la consulta no devuelve ninguna fila porque se anuló la transacción.
  13. Busque el código siguiente en el proyecto de Visual C#:
    String exceptionCausingCmdSQL = "Delete from NonExistentTable";
    y reemplace la instrucción SQL con una consulta válida que no cause la transacción anular la operación. Por ejemplo:
    String exceptionCausingCmdSQL = "Select @@Identity from customers";
  14. Presione F5 para compilar y ejecutar la aplicación de nuevo.
  15. Ejecute de nuevo el comando del paso 12 en Analizador de consultas. Observe que la consulta devuelve una fila porque fue capaz de completar la transacción.
Notas:

  • En este ejemplo no realiza el control de errores.
  • Deben ejecutar SQL Server y el Coordinador de transacciones distribuidas de Microsoft (MS DTC) en todos los servidores y clientes.

Referencias

Para obtener información adicional, haga clic en el número de artículo siguiente para verlo en Microsoft Knowledge Base:

306296 Cómo: crear un componente con servicios .NET que utiliza transacciones en .NET Visual C#
Propiedades

Id. de artículo: 316247 - Última revisión: 17 ene. 2017 - Revisión: 1

Comentarios