Infraestructura System.Transactions en el mundo .NET


¿Has visto una construcción como using (var scope = new TransactionScope(TransactionScopeOption.Required)) en C #? Esto significa que el código que se ejecuta en el bloque de using está en la transacción y después de salir de este bloque, los cambios se confirmarán o revertirán. Suena comprensible hasta que comiences a cavar más profundo. Y cuanto más profundizas, más "extraño y extraño" se vuelve. En cualquier caso, cuando me familiaricé más con la clase TransactionScope y, en general, con las transacciones .NET, surgieron muchas preguntas.

¿Qué es la clase TransactionScope ? Tan pronto como usamos la construcción using (var scope = new TransactionScope()) , ¿todo en nuestro programa se vuelve transaccional inmediatamente? ¿Qué son "Administrador de recursos" y "Administrador de transacciones"? ¿Puedo escribir mi propio administrador de recursos y cómo se "conecta" a la instancia de TransactionScope creada? ¿Qué es una transacción distribuida y es cierto que una transacción distribuida en SQL Server u Oracle Database es lo mismo que una transacción distribuida .NET?

En esta publicación, traté de recopilar material que ayude a encontrar respuestas a estas preguntas y a comprender las transacciones en el mundo .NET.


Introduccion


¿Qué son las transacciones y qué problemas resuelven?


Las transacciones en cuestión aquí son operaciones que transfieren el sistema de un estado aceptable a otro y se garantiza que no dejarán el sistema en un estado inaceptable, incluso si surgen situaciones imprevistas. Qué tipo de condiciones aceptables son, en el caso general, depende del contexto. Aquí consideraremos una situación aceptable en la que los datos que procesamos son integrales. Se entiende que los cambios que conforman la transacción se comprometen juntos o no. Además, los cambios en una transacción pueden aislarse de los cambios realizados en el sistema por otra transacción. Los requisitos básicos para las transacciones se denotan con el acrónimo ACID. Para el primer contacto con ellos, un artículo en Wikipedia es adecuado.


Un ejemplo clásico de una transacción es la transferencia de dinero entre dos cuentas. En esta situación, retirar dinero de la cuenta No. 1 sin acreditar a la cuenta No. 2 es inaceptable, al igual que acreditar a la cuenta No. 2 sin retirar de la cuenta No. 1. En otras palabras, queremos que ambas operaciones sean tanto retiradas como acreditadas. - Realizado de inmediato. Si uno de ellos falla, entonces la segunda operación no debe realizarse. Puedes llamar a este principio "todo o nada". Además, es deseable que las operaciones se realicen sincrónicamente incluso en caso de fallas sistémicas, como un corte de energía, es decir, que veamos el sistema en un estado aceptable tan pronto como esté disponible después de la restauración.

En términos matemáticos, podemos decir que con respecto al sistema hay una invariante que definitivamente nos gustaría preservar. Por ejemplo, el monto en ambas cuentas: es necesario que después de la transacción (transferencia de dinero) el monto permanezca igual que antes. Por cierto, en el ejemplo clásico de transferencia de dinero, también aparece la contabilidad, un área temática donde surgió naturalmente el concepto de transacción.

Ilustramos el ejemplo de transferir dinero entre dos cuentas. La primera imagen muestra la situación cuando la transferencia de 50 rublos de la cuenta No. 1 a la cuenta No. 2 se completó con éxito. El color verde indica que el sistema está en un estado aceptable (los datos están completos).


Ahora imagine que la transferencia se realiza fuera de la transacción y después de retirar el dinero de la cuenta No. 1, ocurrió una falla, debido a la cual el dinero retirado no fue acreditado a la cuenta No. 2. El sistema estará en un estado inaceptable (color rojo).


Si se produjo un error entre las operaciones de retiro y acreditación, pero la transferencia se realizó como parte de una transacción, la operación de retiro se cancelará. Como resultado, el sistema permanecerá en su estado original aceptable.


Daré ejemplos de situaciones de la experiencia de nuestra compañía en las que las transacciones son útiles: contabilizar bienes (contabilizar el número de bienes de varios tipos que están en ciertas tiendas y en el camino), contabilizar los recursos de almacenamiento (contabilizar el volumen de una habitación ocupada por bienes de un cierto tipo, volumen de una habitación, gratis para la colocación de bienes, la cantidad de bienes que los empleados y los sistemas de almacenamiento automatizados pueden mover por día).

Los problemas que surgen cuando se viola la integridad de los datos son obvios. La información proporcionada por el sistema no solo se vuelve falsa, sino que pierde contacto con la realidad y se convierte en una tontería.

Qué transacciones se consideran aquí


Los beneficios proporcionados por las transacciones son conocidos. Entonces, para mantener la integridad de los datos, ¿necesitamos una base de datos relacional, porque ahí es donde se realizan las transacciones? En realidad no Se dijo anteriormente que el concepto de una transacción depende del contexto, y ahora consideraremos brevemente de qué transacciones podemos hablar al discutir los sistemas de información.

Para comenzar, separamos los conceptos de transacciones de dominio de materia (transacciones comerciales) y transacciones del sistema. El segundo puede implementarse en diferentes lugares y de diferentes maneras.

Vayamos desde el nivel más alto: el área temática. La persona interesada puede declarar que hay algunos estados aceptables y que no quiere ver el sistema de información fuera de estos estados. No presentaremos ejemplos adicionales: aquí es adecuado transferir dinero entre cuentas. Solo aclaramos que una transferencia no es necesariamente una transferencia de dinero entre las cuentas de liquidación de dos clientes bancarios. No menos importante es la tarea de contabilidad, cuando las cuentas deben reflejar las fuentes y el propósito de los fondos de la organización, y la transferencia debe reflejar el cambio en la distribución de fondos por estas fuentes y propósito. Este fue un ejemplo de una transacción de dominio sujeto .

Ahora veamos los ejemplos más comunes e interesantes de la implementación de las transacciones del sistema. En las transacciones del sistema, varios medios técnicos proporcionan los requisitos del área temática. Una solución clásica probada de este tipo es una transacción de DBMS relacional (primer ejemplo). Los sistemas modernos de administración de bases de datos (tanto relacionales como no muy ) proporcionan un mecanismo de transacción que le permite guardar (confirmar) todos los cambios realizados durante el período de trabajo especificado o descartarlos (revertirlos). Cuando se utiliza dicho mecanismo, las operaciones de retirar dinero de una cuenta y acreditar a otra cuenta que conforman la transacción del área temática, los medios DBMS se combinarán en una transacción del sistema y se ejecutarán juntos o no se realizarán en absoluto.

Usar un DBMS, por supuesto, no es necesario. Hablando en términos generales, generalmente puede implementar el mecanismo de transacción DBMS en su lenguaje de programación favorito y disfrutar del análogo inestable y con errores de las herramientas existentes. Pero su "bicicleta" se puede optimizar para situaciones específicas en el área temática.

Hay más opciones interesantes. Los lenguajes modernos de programación industrial (C # y Java en primer lugar) ofrecen herramientas diseñadas específicamente para organizar transacciones que involucran subsistemas completamente diferentes, y no solo el DBMS. En esta publicación, llamaremos a dichas transacciones de software. En el caso de C #, estas son transacciones del espacio de nombres System.Transactions (el segundo ejemplo), y se describen a continuación.

Antes de pasar a las transacciones de System.Transactions , uno no puede dejar de mencionar un fenómeno más interesante. System.Transactions herramientas System.Transactions permiten al programador implementar de forma independiente la memoria de transacciones programáticas . En este caso, las operaciones de programa que afectan el estado del sistema (en el caso de los lenguajes de programación imperativos clásicos, esta es una operación de asignación) se incluyen por defecto en las transacciones que pueden confirmarse y revertirse de la misma manera que las transacciones DBMS. Con este enfoque, la necesidad de utilizar mecanismos de sincronización (en C # - lock , en Java - synchronized ) se reduce significativamente. Otro desarrollo de esta idea es la memoria transaccional de software, compatible a nivel de plataforma (tercer ejemplo). Se espera que tal milagro se encuentre en un lenguaje cuya elegancia sobrepasa su aplicabilidad industrial: Clojure. Y para los lenguajes de trabajadores y campesinos, hay bibliotecas de complementos que proporcionan la funcionalidad de la memoria transaccional programática.

Las transacciones del sistema pueden incluir varios sistemas de información, en cuyo caso se distribuyen. Distribuido puede ser tanto transacciones DBMS como software; todo depende de la funcionalidad que admita una herramienta de transacción en particular. Las transacciones distribuidas más detalladas se analizan en la sección correspondiente. Daré una imagen para que sea más fácil entender los temas discutidos.


TL; sección DR


Hay procesos que consisten en varias operaciones indivisibles (atómicas) aplicadas al sistema, en el caso general no necesariamente informativo. Cada operación indivisible puede dejar el sistema en un estado inaceptable cuando la integridad de los datos se ve comprometida. Por ejemplo, si una transferencia de dinero entre dos cuentas está representada por dos operaciones indivisibles de retirar de la cuenta No. 1 y acreditar a la cuenta No. 2, entonces solo una de estas operaciones violará la integridad de los datos. El dinero desaparece en medio de la nada o aparece en medio de la nada. Una transacción combina operaciones indivisibles para que se realicen todas juntas (por supuesto, secuencialmente, si es necesario) o no se realicen en absoluto. Podemos hablar sobre transacciones de dominio y transacciones en sistemas técnicos que típicamente implementan transacciones de dominio.

Transacciones basadas en el sistema.


Que es esto


En el mundo .NET, existe un marco de software diseñado por los creadores de una plataforma de gestión de transacciones. Desde la perspectiva de un programador transaccional, este marco consiste en los System.Transactions TransactionScope , TransactionScopeOption , TransactionScopeAsyncFlowOption y TransactionOptions System.Transactions nombres System.Transactions . Si hablamos de .NET Standard, todo esto está disponible a partir de la versión 2.0 .

Transacciones del sistema. El System.Transactions nombres de transacciones se basa en el estándar X / Open XA de The Open Group . Este estándar presenta muchos de los términos que se analizan a continuación y, lo que es más importante, describe las transacciones distribuidas, que también se tratan en esta publicación en una sección especial. La implementación de transacciones de software en otras plataformas, por ejemplo , Java, se basa en el mismo estándar.

Un caso de uso de transacción típico para un programador de C # es el siguiente:

 using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required)) { // -  ,    . scope.Complete(); } 

Dentro del bloque de using está el código que hace el trabajo, cuyos resultados deben confirmarse o cancelarse todos juntos. Ejemplos clásicos de tal trabajo son leer y escribir en la base de datos o enviar y recibir mensajes desde la cola. Cuando el control abandona el bloque de using , la transacción se confirmará. Si elimina la llamada Complete , la transacción se revertirá. Bastante simple

Resulta que durante la reversión de una transacción, ¿se cancelarán todas las operaciones realizadas dentro de dicho bloque de using ? ¿Y si asigné a una variable un valor diferente, entonces esta variable restaurará el valor anterior? Cuando vi por primera vez un diseño similar, pensé que sí. De hecho, por supuesto, no todos los cambios se revertirán, sino solo algunos muy especiales . Si todos los cambios fueran revertidos, esta sería la memoria transaccional de software descrita anteriormente. Ahora veamos cuáles son estos cambios especiales que pueden participar en las transacciones del programa basadas en System.Transactions .

Administradores de recursos


Para que algo respalde las transacciones basadas en System.Transactions , es necesario que posea información de que una transacción está actualmente en curso y que está registrada en algún registro de participantes de la transacción. Puede obtener información sobre si el trabajo transaccional está en marcha al verificar la propiedad estática Current de la clase System.Transactions.Transaction . Ingresar el bloque de uso del tipo indicado anteriormente solo establece esta propiedad, si no se ha establecido antes. Y para registrarse como participante en una transacción, puede usar métodos del tipo Transaction.Enlist Smth . Además, debe implementar la interfaz requerida por estos métodos. Administrador de recursos: este es un "algo" que admite la interacción con las transacciones de System.Transactions (a continuación se ofrece una definición más específica).

¿Qué son los administradores de recursos? Si trabajamos desde C # con un DBMS, por ejemplo, SQL Server u Oracle Database, usualmente usamos los controladores apropiados, y son los recursos de gestión. En el código, están representados por los tipos System.Data.SqlClient.SqlConnection y Oracle.ManagedDataAccess.Client.OracleConnection . También dicen que MSMQ admite transacciones basadas en System.Transactions . Guiado por el conocimiento y los ejemplos extraídos de Internet, puede crear su propio administrador de recursos. El ejemplo más simple se da en la siguiente sección.

Además de los administradores de recursos, también debemos tener un Administrador de transacciones, que supervisará la transacción y dará órdenes a los administradores de recursos de manera oportuna. Dependiendo de qué administradores de recursos estén involucrados en la transacción (qué características tienen y dónde se encuentran), diferentes administradores de transacciones están conectados al trabajo. En este caso, la selección de la versión adecuada es automática y no requiere la intervención de un programador.

Más específicamente, el administrador de recursos es una instancia de una clase que implementa la interfaz especial System.Transactions.IEnlistmentNotification . La instancia de clase, según las indicaciones del cliente, se registra como participante en la transacción utilizando la propiedad estática System.Transactions.Transaction.Current . Posteriormente, el administrador de transacciones llama a los métodos de la interfaz especificada según sea necesario.


Está claro que en tiempo de ejecución, el conjunto de administradores de recursos involucrados en la transacción puede cambiar. Por ejemplo, después de ingresar el bloque using , primero podemos hacer algo en SQL Server y luego en Oracle Database. Dependiendo de este conjunto de administradores de recursos, se determina el administrador de transacciones utilizado. Para ser más precisos, el protocolo de transacción utilizado está determinado por el conjunto de administradores de recursos, y el administrador de transacciones que lo respalda se determina en función del protocolo. Examinaremos los protocolos transaccionales más adelante cuando hablemos de transacciones distribuidas. El mecanismo para seleccionar automáticamente el administrador de transacciones apropiado en tiempo de ejecución al cambiar los administradores de recursos involucrados en la transacción se llama Promoción de transacción.

Tipos de gerentes de recursos


Los administradores de recursos se pueden dividir en dos grandes grupos: duraderos y variables.

Administrador de recursos duraderos: un administrador de recursos que admite una transacción incluso si el sistema de información no está disponible (por ejemplo, cuando la computadora se reinicia). Administrador de recursos volátiles: un administrador de recursos que no admite una transacción si el sistema de información no está disponible. Un administrador de recursos inconsistente solo admite transacciones en la memoria.

Los administradores de recursos clásicos a largo plazo son el DBMS (o el controlador DBMS para la plataforma de software). Pase lo que pase, al menos un mal funcionamiento en el sistema operativo, al menos un corte de energía, el DBMS garantizará la integridad de los datos una vez que vuelva a funcionar. Para esto, por supuesto, debe pagar algunos inconvenientes, pero en este artículo no los consideraremos. Un ejemplo de un administrador de recursos no persistente es la memoria transaccional de software mencionada anteriormente.

Usando TransactionScope


Al crear un objeto de tipo TransactionScope puede especificar algunos parámetros.

En primer lugar, hay una configuración que le dice al tiempo de ejecución lo que necesita:

  1. Use una transacción que ya existe en este momento;
  2. Asegúrese de crear uno nuevo;
  3. por el contrario, ejecute código dentro de un bloque de using fuera de una transacción.

La enumeración System.Transactions.TransactionScopeOption es responsable de todo esto.

En segundo lugar, puede establecer el nivel de aislamiento de la transacción. Este es un parámetro que le permite encontrar un compromiso entre la independencia del cambio y la velocidad. El nivel más independiente, serializable, asegura que no haya situaciones en las que los cambios realizados dentro de una transacción que aún no se hayan confirmado puedan verse en otra transacción. Cada nivel siguiente agrega una situación específica, cuando las transacciones simultáneas se pueden afectar entre sí.Por defecto, una transacción se abre en el nivel serializable, lo que puede ser desagradable (ver, por ejemplo, este comentario ).

Establecer el nivel de aislamiento de la transacción durante la creación TransactionScopees una recomendación para los administradores de recursos. Es posible que ni siquiera admitan todos los niveles enumerados System.Transactions.IsolationLevel. Además, debe tenerse en cuenta que cuando se usa el grupo de conexiones para trabajar con la base de datos, la conexión para la cual se ha cambiado el nivel de aislamiento de la transacción retendrá este nivel al regresar al grupo . Ahora, cuando el programador recibe esta conexión del grupo y se basa en los valores predeterminados, observará un comportamiento inesperado.

Escenarios de trabajo típicos cTransactionScopey las trampas significativas (a saber, transacciones anidadas) están bien cubiertas en este artículo sobre "Habr" .

Aplicabilidad de transacción de software


Debe decirse que en casi cualquier sistema de información en operación comercial, se inician procesos que pueden llevar al sistema a un estado inaceptable. Por lo tanto, puede ser necesario controlar estos procesos, averiguar si el estado actual del sistema es aceptable y, si no, restaurarlo. Transacciones de software: una herramienta preparada para mantener el sistema en un estado aceptable.

En cada caso, sería constructivo considerar el costo:

  1. integrar procesos en la infraestructura de transacciones de software (estos procesos también deben ser conscientes TransactionScopede muchas otras cosas);
  2. mantener esta infraestructura (por ejemplo, el costo de alquilar equipos con Windows a bordo);
  3. capacitación de empleados (ya que el tema de las transacciones .NET no es común).

No debemos olvidar que el proceso de transacción puede ser requerido para informar su progreso al "mundo exterior", por ejemplo, para mantener un diario de acciones fuera de la transacción.

Obviamente, el rechazo de las transacciones de software requerirá la creación o implementación de algún otro medio para mantener la integridad de los datos, que también tendrá su valor. Al final, puede haber casos en que las violaciones de la integridad de los datos sean tan raras que sea más fácil restaurar un estado aceptable del sistema mediante intervenciones quirúrgicas que mantener un mecanismo de recuperación automática.

Ejemplo de gestor de recursos voluble


Ahora veamos un ejemplo de un administrador de recursos simple que no admite la recuperación de una falla del sistema. Tendremos un bloque de memoria transaccional de software que almacena algún valor que puede leerse y escribirse. En ausencia de una transacción, este bloque se comporta como una variable regular y, en presencia de una transacción, almacena el valor inicial, que puede restaurarse después de que la transacción se revierta. El código para dicho administrador de recursos se presenta a continuación:

 internal sealed class Stm<T> : System.Transactions.IEnlistmentNotification { private T _current; private T _original; private bool _enlisted; public T Value { get { return _current; } set { if (!Enlist()) { _original = value; } _current = value; } } public Stm(T value) { _current = value; _original = value; } private bool Enlist() { if (_enlisted) return true; var currentTx = System.Transactions.Transaction.Current; if (currentTx == null) return false; currentTx.EnlistVolatile(this, System.Transactions.EnlistmentOptions.None); _enlisted = true; return true; } #region IEnlistmentNotification public void Commit(System.Transactions.Enlistment enlistment) { _original = _current; _enlisted = false; } public void InDoubt(System.Transactions.Enlistment enlistment) { _enlisted = false; } public void Prepare(System.Transactions.PreparingEnlistment preparingEnlistment) { preparingEnlistment.Prepared(); } public void Rollback(System.Transactions.Enlistment enlistment) { _current = _original; _enlisted = false; } #endregion IEnlistmentNotification } 

Se puede ver que el único requisito formal es la implementación de la interfaz System.Transactions.IEnlistmentNotification. De los interesantes, los métodos Enlist(que no son parte System.Transactions.IEnlistmentNotification) y Prepare. El método Enlistsolo verifica si el código dado funciona dentro del marco de la transacción y, si es así, registra una instancia de su clase como un administrador de recursos no constante. El Prepareadministrador de transacciones llama al método antes de confirmar los cambios. Nuestro administrador de recursos señala su disposición para comprometerse llamando a un método System.Transactions.PreparingEnlistment.Prepared.

El siguiente es un código que muestra un ejemplo del uso de nuestro administrador de recursos:

 var stm = new Stm<int>(1); using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required)) { stm.Value = 2; scope.Complete(); } 

Si usinglee la propiedad inmediatamente después de salir del bloque stm.Value, se esperará allí el valor esperado 2. Y si elimina la llamada scope.Complete, la transacción se revertirá y la propiedad stm.Valuetendrá el valor 1establecido antes del inicio de la transacción.

En System.Transactionsel siguiente diagrama se muestra una secuencia simplificada de llamadas cuando se trabaja con transacciones .


Se puede ver que en este ejemplo, no se consideran todas las posibilidades proporcionadas por la infraestructura System.Transactions. Los consideraremos más a fondo una vez que nos familiaricemos con los protocolos transaccionales y las transacciones distribuidas en la siguiente sección.

TL; sección DR


Un programador puede usar una clase TransactionScopepara ejecutar algún código dentro de una transacción existente o nueva. Una transacción se confirma si y solo si TransactionScopese llama al método en una instancia existente de la clase Dispose, incluso si el método se llamó antesComplete. Un programador puede indicar si desea comenzar una nueva transacción, aprovechar una existente o, por el contrario, ejecutar código fuera de una transacción existente. Solo los administradores de recursos están involucrados en la transacción: componentes de software que implementan cierta funcionalidad. Los administradores de recursos pueden ser a largo plazo (recuperación de una falla del sistema) e intermitentes (no recuperación). Un DBMS es un ejemplo de un administrador de recursos de larga duración. El administrador de recursos es coordinado por un administrador de transacciones, un componente de software que el tiempo de ejecución selecciona automáticamente sin la participación de un programador.

El administrador de recursos inconsistente es una clase que implementa la interfaz System.Transactions.IEnlistmentNotificationen el métodoPrepareconfirmando su disponibilidad para cometer cambios o, por el contrario, señalando una reversión de los cambios. Cuando la persona que llama hace algo con el administrador de recursos, comprueba si la transacción está abierta ahora y, si está abierta, inicia sesión con el método System.Transactions.Transaction.EnlistVolatile.

Transacciones distribuidas


Que es esto


Una transacción distribuida involucra varios subsistemas de información (de hecho, no todo es tan simple, más sobre esto a continuación). Se entiende que los cambios en todos los sistemas involucrados en una transacción distribuida deben confirmarse o revertirse.

Anteriormente se presentaron varios medios para implementar transacciones: DBMS, infraestructura System.Transactionsy memoria transaccional programática integrada en la plataforma. Las transacciones distribuidas también se pueden proporcionar con estas herramientas. Por ejemplo, en la base de datos Oracle, el cambio (y la lectura real) de datos en varias bases de datos dentro de una sola transacción la convierte automáticamente en una distribuida. A continuación, hablaremos sobre las transacciones distribuidas por software, que pueden incluir administradores de recursos heterogéneos.

Protocolos transaccionales


Un protocolo transaccional es un conjunto de principios por los cuales interactúan las aplicaciones involucradas en una transacción. En el mundo .NET, los siguientes protocolos se encuentran más comúnmente.

Ligero No se utiliza más de un administrador de recursos duradero. Todas las interacciones transaccionales ocurren dentro del mismo dominio de aplicación, o el administrador de recursos admite la promoción y el compromiso de fase única (implementa IPromotableSinglePhaseNotification).

OleTx. Se permite la interoperabilidad entre múltiples dominios de aplicación y múltiples computadoras. Puede usar muchos administradores de recursos duraderos. Todas las computadoras participantes deben estar ejecutando Windows. Use llamadas a procedimiento remoto (RPC).

WS-AT.Se permite la interoperabilidad entre múltiples dominios de aplicación y múltiples computadoras. Puede usar muchos administradores de recursos duraderos. Las computadoras participantes pueden estar ejecutando varios sistemas operativos, no solo Windows. Se utiliza el Protocolo de transmisión de hipertexto (HTTP).

Se señaló anteriormente que el protocolo de transacción actual afecta la elección del administrador de la transacción, y las características de los recursos de control involucrados en la transacción influyen en la elección del protocolo. Ahora enumeramos los gestores de transacciones conocidos.

Administrador de transacciones ligeras (LTM) . Introducido en .NET Framework 2.0 y versiones posteriores. Gestiona transacciones utilizando el protocolo Lightweight.

Kernel Transaction Manager (KTM). Introducido en Windows Vista y Windows Server 2008. Administra las transacciones utilizando el protocolo Lightweight. Puede invocar un Sistema de archivos transaccionales (TxF) y un Registro transaccional (TxR) en Windows Vista y Windows 2008.

Coordinador de transacciones distribuidas (MSDTC) . Gestiona transacciones utilizando los protocolos OleTx y WS-AT.

También debe tenerse en cuenta que algunos administradores de recursos no son compatibles con todos los protocolos enumerados. Por ejemplo, MSMQ y SQL Server 2000 no son compatibles con Lightweight, por lo que las transacciones que involucran MSMQ o SQL Server 2000 serán administradas por MSDTC, incluso si son los únicos participantes. Técnicamente, esta limitación surge del hecho de que los administradores de recursos especificados, implementando, por supuesto, la interfazSystem.Transactions.IEnlistmentNotificationNo implemente la interfaz System.Transactions.IPromotableSinglePhaseNotification. Contiene, entre otras cosas, un método Promoteque el tiempo de ejecución invoca, si es necesario, para cambiar a un administrador de transacciones más empinado.

La ambigüedad del concepto de transacción distribuida ahora debería ser evidente. Por ejemplo, puede definir una transacción distribuida como una transacción en la que participa:

  1. al menos dos de los administradores de recursos;
  2. administradores de recursos arbitrariamente variables y al menos dos de larga vida;
  3. al menos dos de los administradores de recursos necesariamente ubicados en diferentes computadoras.

Por lo tanto, es mejor aclarar siempre qué transacciones particulares están involucradas.

Y en este contexto, MSDTC se discute principalmente. Es un componente de software de Windows que administra transacciones distribuidas. Hay una interfaz gráfica para configurar y monitorear transacciones, que se puede encontrar en la utilidad "Servicios de componentes", siguiendo la ruta "Computadoras - Mi computadora - Coordinador de transacciones distribuidas - DTC local".


Para la configuración, seleccione el elemento "Propiedades" en el menú contextual del nodo "DTC local", y para supervisar las transacciones distribuidas, seleccione el elemento "Estadísticas de transacciones" en el panel central.

Fijación bifásica


Si varios administradores de recursos participan en la transacción, los resultados de su trabajo pueden diferir: por ejemplo, uno de ellos se completó con éxito, y está listo para confirmar los cambios, y el otro tiene un error, y va a revertir los cambios. Sin embargo, la esencia de una transacción distribuida radica en el hecho de que los cambios en todos los recursos de control involucrados en la transacción se confirman todos juntos o se revierten. Por lo tanto, en tales casos, generalmente se usa un protocolo de fijación de dos fases.

En general, la esencia de este protocolo es la siguiente. Durante la primera faseLos administradores de recursos involucrados en la transacción preparan información suficiente para recuperarse de la falla (si es un administrador de recursos a largo plazo) y para completar con éxito como resultado de una confirmación. Desde un punto de vista técnico, el administrador de recursos señala que ha completado la primera fase llamando al método System.Transactions.PreparingEnlistment.Prepareden el método Prepare. O el administrador de recursos puede notificarle que los cambios fueron revertidos llamando al método ForceRollback.

Cuando todos los administradores de recursos involucrados en la transacción "votaron", es decir, notificaron al administrador de transacciones si desean confirmar o revertir los cambios, comienza la segunda fase. En este momento, los gerentes de recursos tienen instrucciones de confirmar sus cambios (si todos los participantes votaron por la reparación) o de rechazar los cambios (si al menos un participante votó por la reversión). Técnicamente, esto se expresa en la invocación de los métodos Commity en Rollbackla implementación de los administradores de recursos y en la que invocan el método System.Transactions.Enlistment.Done.

El administrador de recursos también puede llamar al método System.Transactions.Enlistment.Donedurante la primera fase. En este caso, se entiende que no va a cometer ningún cambio (por ejemplo, solo trabaja para leer) y no participará en la segunda fase. Lea más sobre la confirmación en dos fases en Microsoft .

Si se pierde la conexión entre el administrador de transacciones y al menos uno de los administradores de recursos, la transacción se congela ("en duda", en duda). El administrador de transacciones, mediante métodos de llamada InDoubt, notifica a los administradores de recursos disponibles de este evento que pueden responder adecuadamente.

Todavía hay una fijación trifásica y sus modificaciones con sus ventajas y desventajas. El protocolo de confirmación de tres fases es menos común, quizás porque requiere aún más costos de comunicación entre los subsistemas que interactúan.

Cheat sheet en las interfaces de System.Transactions


Algo es dificil. Para ordenar un poco las cosas, describiré brevemente las principales interfaces de espacio de nombres System.Transactionsnecesarias para crear un administrador de recursos. Aquí hay un diagrama de clase.



IEnlistmentNotification. El administrador de recursos implementa esta interfaz. El administrador de transacciones llama a los métodos implementados en el siguiente orden. Durante la primera fase, llama al método Prepare(a menos que las estrellas se unan para llamar al método ISinglePhaseNotification.SinglePhaseCommit, como se describe en el siguiente párrafo). Bajo este método, el administrador de recursos guarda la información necesaria para recuperarse de una falla, se prepara para la confirmación final de los cambios de su lado y vota para confirmar o revertir los cambios. Si llega una segunda fase, en función de la disponibilidad de recursos y el control de los resultados de la votación de la operación de control es uno de tres métodos: Commit, InDoubt, Rollback.

ISinglePhaseNotification.El administrador de recursos implementa esta interfaz si desea brindarle al administrador de transacciones la oportunidad de optimizar la ejecución al reducir la segunda fase de confirmación. Si el administrador de transacciones solo ve un administrador de recursos, entonces, en la primera fase de confirmación, intenta llamar al método del administrador de recursos SinglePhaseCommit(en su lugar IEnlistmentNotification.Prepare) y, por lo tanto, excluye la votación y la transición a la segunda fase. Este enfoque tiene ventajas y desventajas, sobre las cuales Microsoft escribió más claramente aquí .

ITransactionPromoter. El administrador de recursos implementa esta interfaz (no solo directamente, sino a través de la interfazIPromotableSinglePhaseNotification), si desea proporcionar al administrador de transacciones la capacidad de adherirse al protocolo Lightweight incluso cuando llama de forma remota, hasta que surjan otras condiciones que requieran una complicación del protocolo. Cuando necesite complicar el protocolo, se llamará al método Promote.

IPromotableSinglePhaseNotification. El administrador de recursos implementa esta interfaz para, en primer lugar, implementar la interfaz ITransactionPromotery, en segundo lugar, para que el administrador de transacciones pueda utilizar la confirmación de una sola fase, métodos de llamada IPromotableSinglePhaseNotification.SinglePhaseCommity IPromotableSinglePhaseNotification.Rollback. El administrador de transacciones llama a un método IPromotableSinglePhaseNotification.Initializepara marcar el registro exitoso del administrador de recursos de manera simplificada. Más o menos, esto se puede entender a partir de un documento de Microsoft .

Miremos un poco másSystem.Transactions.Enlistmenty sus herederos. El administrador de transacciones proporciona este tipo de instancia cuando invoca los métodos de interfaz implementados por el administrador de recursos.



Alistamiento El administrador de recursos puede llamar a un único método de este tipo Done, para indicar la finalización exitosa de su parte del trabajo.

PreparingEnlistment. Utilizando una instancia de este tipo durante la primera fase de confirmación, el administrador de recursos puede indicar su intención de confirmar o revertir los cambios. Un administrador de recursos de larga duración también puede obtener la información necesaria para recuperarse de una falla del sistema.

SinglePhaseEnlistment. Usando una instancia de este tipo, el administrador de recursos puede transmitir información al administrador de transacciones sobre los resultados de su trabajo utilizando un esquema simplificado (confirmación de fase única).

Limitaciones y alternativas de transacciones distribuidas por software


Un breve estudio de las opiniones encontradas en Internet muestra que en muchas áreas, las transacciones distribuidas están pasadas de moda. Eche un vistazo a este comentario malicioso , por ejemplo . El principal objeto de crítica, que se menciona brevemente aquí , es la naturaleza síncrona (bloqueo) de las transacciones distribuidas. Si el usuario envió una solicitud durante el procesamiento de la cual se organizó una transacción distribuida, recibirá una respuesta solo después (con éxito o con un error) de que todos los subsistemas incluidos en la transacción terminen de funcionar. Al mismo tiempo, existe una opinión respaldada por la investigación de que el protocolo de confirmación de dos fases muestra un rendimiento deficiente, especialmente con un aumento en el número de subsistemas involucrados en la transacción, como se menciona, por ejemplo, enesta publicación sobre "Habré" .

Si el creador del sistema prefiere devolver la respuesta al usuario lo antes posible, posponiendo la coordinación de datos para más adelante, entonces alguna otra solución será más adecuada para él. En el contexto del teorema de Brewer (teorema CAP ), podemos decir que las transacciones distribuidas son adecuadas para casos donde la consistencia de los datos es más importante que la disponibilidad.

Existen otras restricciones prácticas sobre el uso de transacciones distribuidas por software. Por ejemplo, se estableció experimentalmente que las transacciones distribuidas que utilizan el protocolo OleTx no deberían cruzar dominios de red. En cualquier caso, los intentos largos para que funcionen no tuvieron éxito. Además, se reveló que la interacción entre varias instancias de Oracle Database (transacciones de bases de datos distribuidas) impone serias restricciones a la aplicabilidad de las transacciones distribuidas por software (nuevamente, no se pudo iniciar).

¿Cuáles son las alternativas a las transacciones distribuidas? Primero, debo decir que será muy difícil prescindir de transacciones técnicas (normal, no distribuido). Es probable que haya procesos en el sistema que puedan alterar temporalmente la integridad de los datos, y será necesario de alguna manera supervisar dichos procesos. Del mismo modo, en términos del área temática, puede surgir un concepto que incluya un proceso implementado por un conjunto de procesos en diferentes sistemas técnicos, que deben comenzar y terminar en el campo de los datos integrales.

Pasando a las alternativas a las transacciones distribuidas, podemos observar soluciones basadas en servicios de mensajería, como RabbitMQ y Apache Kafka. En esta publicación sobre "Habré" se consideran cuatro de estas soluciones:

  1. , , ;
  2. , (Transaction Log Tailing);
  3. , ;
  4. (Event Sourcing).

Otra alternativa es la plantilla Saga. Implica una cascada de subsistemas con sus transacciones locales. Al finalizar el trabajo, cada sistema llama a lo siguiente (independientemente o con la ayuda de un coordinador). Para cada transacción hay una transacción de cancelación correspondiente, y en lugar de transferir el control, el subsistema puede iniciar la cancelación de los cambios realizados anteriormente por los subsistemas anteriores. En "Habré" hay algunos buenos artículos sobre la plantilla "Saga". Por ejemplo, esta publicación proporciona información general sobre el mantenimiento de los principios de ACID en microservicios, y este artículo detalla un ejemplo de implementación de la plantilla Saga con un coordinador.

En nuestra empresa, algunos productos utilizan con éxito transacciones distribuidas por software a través de WCF, pero hay otras opciones. Una vez, cuando intentamos hacer amigos un nuevo sistema con transacciones distribuidas, tuvimos muchos problemas, incluida una colisión con las limitaciones descritas anteriormente y problemas paralelos con la actualización de la infraestructura del software. Por lo tanto, en condiciones de escasez de recursos para ejecutar otra decisión de capital, aplicamos las siguientes tácticas. La parte llamada captura los cambios en cualquier caso, pero observa que están en un estado borrador, por lo que estos cambios aún no afectan el funcionamiento del sistema llamado. Luego, la persona que llama, al completar su trabajo a través de una transacción distribuida, el DBMS activa los cambios realizados por el sistema llamado. De esta maneraen lugar de transacciones distribuidas por software, utilizamos transacciones DBMS distribuidas, que en este caso resultaron ser mucho más confiables.

Entonces, ¿está en .NET Core?


En .NET Core (e incluso en .NET Standard) existen todos los tipos necesarios para organizar transacciones y crear su propio administrador de recursos. Desafortunadamente, en .NET Core, las transacciones basadas System.Transactionstienen una seria limitación: solo funcionan con el protocolo Lightweight. Por ejemplo, si se usan dos administradores de recursos duraderos en el código, en tiempo de ejecución, el entorno generará una excepción tan pronto como se llame al segundo administrador.

El hecho es que intentan hacer que .NET Core sea independiente del sistema operativo, por lo que se excluye el enlace a los administradores de transacciones como KTM y MSDTC, es decir, son necesarios para admitir transacciones con las propiedades especificadas. Es posible que la conexión de los administradores de transacciones se implemente en forma de complementos, pero hasta ahora esto se ha escrito con un pitchfork, por lo que aún no puede confiar en el uso industrial de las transacciones distribuidas en .NET Core.

Por experiencia, puede verificar las diferencias en las transacciones distribuidas en .NET Framework y en .NET Core escribiendo el mismo código, compilándolo y ejecutándolo en diferentes plataformas.

Un ejemplo de dicho código que invoca SQL Server y Oracle Database secuencialmente.

 private static void Main(string[] args) { using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required)) { MsSqlServer(); Oracle(); scope.Complete(); } } private static void Oracle() { using (var conn = new Oracle.ManagedDataAccess.Client.OracleConnection("User Id=some_user;Password=some_password;Data Source=some_db")) { conn.Open(); using (var cmd = conn.CreateCommand()) { cmd.CommandText = "update t_hello set id_hello = 2 where id_hello = 1"; cmd.ExecuteNonQuery(); } conn.Close(); } } private static void MsSqlServer() { var builder = new System.Data.SqlClient.SqlConnectionStringBuilder { DataSource = "some_computer\\some_db", UserID = "some_user", Password = "some_password", InitialCatalog = "some_scheme", Enlist = true, }; using (var conn = new System.Data.SqlClient.SqlConnection(builder.ConnectionString)) { conn.Open(); using (var cmd = conn.CreateCommand()) { cmd.CommandText = "update t_hello set id_hello = 2 where id_hello = 1"; cmd.ExecuteNonQuery(); } conn.Close(); } } 

Los proyectos listos para construir están en GitHub .

La ejecución del ejemplo de .NET Core falla. El lugar y el tipo de la excepción lanzada dependen del orden de la llamada DBMS, pero en cualquier caso, esta excepción indica una operación de transacción no válida. Ejecutar el ejemplo para .NET Framework tiene éxito si MSDTC se está ejecutando en este momento; sin embargo, en la interfaz gráfica de MSDTC, puede observar el registro de una transacción distribuida.

Transacciones distribuidas y WCF


Windows Communication Foundation (WCF) es el marco .NET para organizar e invocar servicios de red. En comparación con los enfoques REST y ASP.NET Web API más modernos, tiene sus propias ventajas y desventajas. WCF es muy buen amigo de las transacciones .NET, y en el mundo de .NET Framework es conveniente usarlo para organizar transacciones distribuidas entre el cliente y el servicio.

En .NET Core, esta tecnología funciona solo en el lado del cliente, es decir, no puede crear un servicio, pero solo puede referirse a uno existente. Sin embargo, esto no es muy importante porque, como se mencionó anteriormente, con las transacciones distribuidas en .NET Core, las cosas no están funcionando bien.

Cómo funciona WCF

Para los lectores que no están familiarizados con WCF, aquí está la información básica más breve sobre lo que esta tecnología es en la práctica. Contexto: dos sistemas de información llamados cliente y servicio. El cliente en tiempo de ejecución accede a otro sistema de información que admite el servicio de interés para el cliente y requiere que se realice alguna operación. Luego la gestión se devuelve al cliente.

Para crear un servicio en WCF, generalmente necesita escribir una interfaz que describa el contrato para el servicio que se está creando y una clase que implemente esta interfaz. La clase y la interfaz están marcadas con atributos WCF especiales que los distinguen del resto de los tipos y especifican algunos detalles del comportamiento durante el descubrimiento y la invocación del servicio. Estos tipos están envueltos en algo que funciona como un servidor (por ejemplo, en un archivo DLL en el que se establece IIS), y se complementan con un archivo de configuración (hay opciones), donde se indican los detalles de la implementación del servicio. Después de comenzar, se puede acceder al servicio, por ejemplo, en la dirección de red; En el navegador de Internet puede ver los contratos que implementa el servicio solicitado.

Un programador que desea acceder a un servicio WCF existente utiliza una utilidad de consola o una interfaz gráfica integrada en el entorno de desarrollo para formar tipos en C # (o en otro lenguaje compatible) que correspondan a los contratos de servicio en la dirección del servicio. El archivo con los tipos obtenidos se incluye en el proyecto de aplicación del cliente, y luego el programador usa los mismos términos contenidos en la interfaz del servicio, disfrutando de los beneficios del progreso (tipeo estático). Además, el archivo de configuración del cliente especifica las características técnicas del servicio llamado (también se puede configurar en código, sin el archivo de configuración).

WCF admite varios tipos de transporte, cifrado y otros parámetros técnicos más sutiles. La mayoría de ellos están unidos por el concepto de "enlace". Hay tres parámetros importantes para el servicio WCF:

  1. la dirección en la que está disponible;
  2. vinculante
  3. contrato (interfaces).

Todos estos parámetros se establecen en los archivos de configuración del servicio y del cliente.

En nuestra empresa, WCF (con y sin transacciones distribuidas) se usa ampliamente en productos implementados, sin embargo, dadas las tendencias de la moda, su uso en nuevos productos aún está en duda.

Cómo iniciar transacciones distribuidas en WCF

Para iniciar transacciones basadas en WCF System.Transactions, el programador necesita establecer varios atributos en el código, asegurarse de que los enlaces utilizados admitan transacciones distribuidas, transactionFlow="true"que esté escrito en el cliente y en el servicio, y que el administrador de transacciones apropiado se esté ejecutando en todas las computadoras involucradas (muy probablemente , será MSDTC).

Enlaces de transacciones distribuidas: NetTcpBinding, NetNamedPipeBinding, WSHttpBinding, WSDualHttpBinding y WSFederationHttpBinding.

El método (operación) de la interfaz de servicio debe estar marcado con un atributo System.ServiceModel.TransactionFlowAttribute. Luego, con ciertos parámetros de atributo y al establecer el parámetro de TransactionScopeRequiredatributo , la System.ServiceModel.OperationBehaviorAttributetransacción se distribuirá entre el cliente y el servicio. Además, de manera predeterminada, se considera que el servicio vota para confirmar la transacción, a menos que se lance una excepción en tiempo de ejecución. Para cambiar este comportamiento, debe establecer el valor del parámetro de TransactionAutoCompleteatributo correspondiente System.ServiceModel.OperationBehaviorAttribute.

El código para un servicio WCF simple que admite transacciones distribuidas.
 [System.ServiceModel.ServiceContract] public interface IMyService { [System.ServiceModel.OperationContract] [System.ServiceModel.TransactionFlow(System.ServiceModel.TransactionFlowOption.Mandatory)] int DoSomething(string input); } public class MyService : IMyService { [System.ServiceModel.OperationBehavior(TransactionScopeRequired = true)] [System.ServiceModel.TransactionFlow(System.ServiceModel.TransactionFlowOption.Mandatory)] public int DoSomething(string input) { if (input == null) throw new System.ArgumentNullException(nameof(input)); return input.Length; } } 

Obviamente, difiere del código de servicio regular solo en el uso del atributo System.ServiceModel.TransactionFlowy en la configuración especial del atributo System.ServiceModel.OperationBehavior.

Configuración de muestra para este servicio.
 <system.serviceModel> <services> <service name="WcfWithTransactionsExample.MyService" behaviorConfiguration="serviceBehavior"> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="mainWsBinding" contract="WcfWithTransactionsExample.IMyService"/> <endpoint address="mex" contract="IMetadataExchange" binding="mexHttpBinding"/> </service> </services> <bindings> <wsHttpBinding> <binding name="mainWsBinding" maxReceivedMessageSize="209715200" maxBufferPoolSize="209715200" transactionFlow="true" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"> <security mode="None"/> <readerQuotas maxArrayLength="209715200" maxStringContentLength="209715200"/> </binding> </wsHttpBinding> </bindings> </system.serviceModel> 

Tenga en cuenta que el enlace es de tipo WSHttpBinding y se utiliza el atributo transactionFlow="true".

TL; sección DR


Las transacciones distribuidas incluyen varios administradores de recursos, y todos los cambios deben confirmarse o revertirse. Algunos DBMS modernos implementan transacciones distribuidas que proporcionan un mecanismo conveniente para conectar varias bases de datos. Las transacciones distribuidas por software (no implementadas en DBMS) pueden incluir diferentes combinaciones de administradores de recursos en diferentes computadoras que ejecutan diferentes sistemas operativos, pero tienen limitaciones que deben tenerse en cuenta antes de confiar en ellas. Una alternativa moderna a las transacciones distribuidas son las soluciones de mensajería. En .NET Core, las transacciones distribuidas aún no son compatibles.

WCF es una de las herramientas estándar y probadas para crear y acceder a servicios en el mundo .NET, que admite varios tipos de transporte y cifrado. WCF es muy amigo de las transacciones distribuidas basadas en System.Transactions. La configuración de transacciones distribuidas para WCF consiste en marcar el código con varios atributos y agregar un par de palabras en el servicio y los archivos de configuración del cliente. No todos los enlaces WCF admiten transacciones distribuidas. Además, está claro que las transacciones en WCF tienen las mismas limitaciones que sin usar WCF. La plataforma .NET Core hasta ahora solo le permite acceder a servicios en WCF, en lugar de crearlos.

Conclusión Cuna


Esta publicación es una descripción general de los conceptos básicos de las transacciones de software .NET. Algunas conclusiones sobre las tendencias en las transacciones de software se pueden encontrar en las secciones sobre la aplicabilidad y las limitaciones de los temas discutidos, y en conclusión, se recopilan las principales tesis de la publicación. Supongo que se pueden usar como una hoja de trucos cuando se consideran las transacciones de software como una de las opciones para implementar un sistema técnico o para actualizar la información relevante en la memoria.

Transacciones (área temática, DBMS, software). Los requisitos de dominio a veces se formulan en forma de transacciones: operaciones que, comenzando en el campo de los datos integrales, una vez completadas (incluidas las no exitosas) también deberían entrar en el campo de los datos integrales (posiblemente ya diferentes). Estos requisitos generalmente se implementan como transacciones del sistema. Un ejemplo clásico de una transacción es la transferencia de dinero entre dos cuentas, que consta de dos operaciones indivisibles: retirar dinero de una cuenta y acreditarlo a otra. Además de las transacciones bien conocidas implementadas por el DBMS, también hay transacciones de software, por ejemplo, en el mundo .NET. Los administradores de recursos son componentes de software que son conscientes de la existencia de tales transacciones y tienen la capacidad de ser incluidos en ellas, es decir, confirmar o revertir los cambios realizados.Los administradores de recursos reciben instrucciones sobre cómo confirmar y deshacer los cambios del administrador de transacciones, que es la base de la infraestructuraSystem.Transactions.

Administradores de recursos duraderos e intermitentes. Los administradores de recursos a largo plazo admiten la recuperación de datos después de una falla del sistema. Los controladores DBMS para .NET generalmente ofrecen dicha funcionalidad. Los administradores de recursos intermitentes no admiten la recuperación ante desastres. La memoria transaccional programática, una forma de administrar objetos en RAM, puede verse como un ejemplo de un administrador de recursos voluble.

Transacciones y .NET Resource Managers. El programador .NET usa transacciones de software y crea sus propios administradores de recursos usando tipos del espacio de nombresSystem.Transactions. Esta infraestructura permite el uso de transacciones de varios tipos de anidamiento y aislamiento (con limitaciones conocidas). El uso de transacciones no es complicado, y consiste en envolver el código en un bloque usingcon ciertas características. Sin embargo, los administradores de recursos incluidos de esta manera en la transacción deben mantener la funcionalidad requerida por su parte. El uso de administradores de recursos heterogéneos en una transacción o el uso de un administrador de diferentes maneras puede convertir automáticamente una transacción en una distribuida.

Transacciones distribuidas (DBMS, software).Una transacción distribuida cubre varios subsistemas, cuyos cambios deben sincronizarse, es decir, se confirman todos juntos o se revierten. Las transacciones distribuidas se implementan en algunos DBMS modernos. Las transacciones distribuidas por software (estas no son las implementadas por el DBMS) imponen restricciones adicionales en los procesos y plataformas que interactúan. Las transacciones distribuidas pasan de moda gradualmente, dando paso a soluciones basadas en servicios de mensajería. Para convertir una transacción ordinaria en una distribuida, el programador no necesita hacer nada: cuando se incluye un administrador de recursos con ciertas características en la transacción en tiempo de ejecución, el administrador de transacciones automáticamente hará lo que sea necesario. Las transacciones regulares de software están disponibles en .NET Core y .NET Standard, y las transacciones distribuidas no están disponibles.

Transacciones distribuidas a través de WCF. WCF es una de las herramientas estándar de .NET para crear e invocar servicios, que también admite protocolos estandarizados. En otras palabras, se puede acceder a los servicios WCF que están configurados de una manera específica desde cualquier aplicación, no solo .NET o Windows. Para crear una transacción distribuida sobre WCF, debe marcar los tipos que componen el servicio con atributos adicionales y realizar cambios mínimos en el servicio y los archivos de configuración del cliente. No puede crear servicios WCF en .NET Core y .NET Standard, pero puede crear clientes WCF.

Ejemplo para verificar System.Transactions en GitHub

Referencias

Conceptos basicos


ACID ( «»)
( Microsoft)
( Microsoft)
( «»)
( «»)
( «»)


X/Open XA ( The Open Group)
Java Transaction API ( «»)
Cache ( InterSystems)

.NET


.NET ( Tech Blog Collection)
TransactionScope («»)
, ( Microsoft)
.NET Standard 2.0 ( .NET Standard GitHub)
( YarFullStack)


(«»)
(«»)
«» («»)
«» («»)
(«»)

Editorial

Source: https://habr.com/ru/post/es433136/


All Articles