Share via


Este artículo proviene de un motor de traducción automática.

Fundamentos

Flujos de trabajo de control de versiones

Matthew Milner

Descarga de código de la Galería de código de MSDN
Examinar el código en línea

Contenido

Los problemas
Control de versiones de .NET
Control de versiones con las definiciones de flujo de trabajo XOML
Control de versiones de actividad
Servicios de flujo de trabajo de control de versiones
Actualización dinámica

En cualquier aplicación, hay una cosa que puede estar determinado de: cambio ocurre.Uno de los problemas más comunes que encontrar los desarrolladores esfuerzan con es cómo tratar los flujos de trabajo de control de versiones y sus clases relacionadas.En la columna de este mes, se describa los problemas principales relacionados con las versiones de flujo de trabajo y mencionar recomendaciones que mi medidas de realizar cambios en las definiciones de flujo de trabajo, actividades y servicios de flujo de trabajo.

fig01.gif

Figura 1, flujo de trabajo simple que puede conservar

Si crea una aplicación .NET hoy en día, por ejemplo, una aplicación de Windows Presentation Foundation (WPF) o ASP.NET, que es posible que piensas acerca de control de versiones, o es posible que no.Cuando desea implementar actualizaciones a una aplicación ASP.NET, normalmente tiene un proceso para copiar simplemente todos o alguno de los componentes incluidos páginas, archivos binarios y configuración.En algunos escenarios, puede que tenga las preocupaciones de acerca de esta implementación, como asegurándose de que hay solicitudes están ejecutando actualmente, pero este proceso es generalmente manejable.¿Así por qué es implementar nuevas versiones de aplicaciones de flujo de trabajo tan difícil?

Los flujos de trabajo permiten modelar procesos empresariales de larga ejecución o lógica de negocios.Además, Windows Workflow Foundation (WF) proporciona servicios de persistencia que permiten para el estado de instancias individuales de un proceso empresarial se guardado en un almacén permanente, como una base de datos de Microsoft SQL Server.Que guarda el estado se compone de objetos serializados de .NET; y ella encuentra el problema.

Considere la posibilidad de un flujo de trabajo que usa algunos tipos de .NET como datos, por ejemplo, una clase Order.El flujo de trabajo se inicia con un objeto de orden pasado como un parámetro, a continuación, se almacena en la base de datos, su estado del objeto Order serializado.Ahora cambiar la clase de objeto Order y regenerar la biblioteca de aplicación.Cuando que almacena el flujo de trabajo necesita reanudar porque un retraso ha caducado o se provoca algún evento para el flujo de trabajo, el objeto de orden debe que se va a deserializar.Por desgracia, porque ha cambiado ese tipo, la deserialización falla, produce una excepción.

Algunos cambios provocar problemas con la deserialización porque la serialización binaria de .NET estándar se produce un error y otros problemas debido de la implementación de WF de serialización.Independientemente del motivo, el resultado final es el mismo: una excepción al intentar cargar un flujo de trabajo que hace referencia a tipos que han cambiado.Es posible que estos tipos de clases o interfaces que se crea o pueden ser actividades personalizadas que ha escrito.

Para proporcionar un ejemplo concreto, considere el flujo de trabajo en la figura 1 .Sólo se escribe algunos datos en la consola utilizando una actividad WriteLine personalizada, retrasos (que también permite conservar) y, a continuación, escribe más datos en la consola.

Ahora, si inicia una instancia de este flujo de trabajo y permiten que se ejecute hasta el punto de inactividad, el retraso, se conservarán en la base de datos.Puede apagar el motor en tiempo de ejecución y empezar a trabajar en la versión 1.1 del flujo de trabajo.Simplemente va agregar una actividad al final de la definición de flujo de trabajo para escribir más datos en la consola, tal como se muestra en la figura 2 .

Iniciar el motor en tiempo de ejecución sin iniciar otra instancia de flujo de trabajo, hará que el servicio de persistencia para sondear la base de datos buscando temporizadores caducados.Cuando se encuentra la instancia existente, el servicio de persistencia intentará cargar el objeto y obtendrá una excepción.Este error puede detectar por registrar un controlador de eventos para el evento ServicesExceptionNotHandled en WorkflowRuntime.Lo verá es que el servicio de persistencia provocará un evento de la excepción con el mensaje "índice se fuera de los límites de la matriz".

fig02.gif

La Figura 2 modificación de definición de flujo de trabajo

El problema es que ha cambiado la definición del tipo de flujo de trabajo y ya no coincide con la definición que existía cuando se almacena el flujo de trabajo.Cuando el servicio de persistencia intenta deserializar el flujo de trabajo, aparece excepciones porque la nueva definición de tipo contiene campos que no existían cuando se serializa la instancia.Se leer los campos en el nuevo tipo del código de deserialización y se intenta cargar los valores de los datos serializados.Porque algunos campos no existía cuando se serializa la instancia, se produce una excepción cuando intenta tener acceso a los datos.

Control de versiones de .NET

Uno para solucionar los problemas de control de versiones consiste en aprovechar el sistema de control de versiones integrado en .NET Framework.Desde la versión 1.0 de .NET Framework, las versiones de ensamblados ha sido admitida y la sólo manera habilitar la compatibilidad de forma simultánea con varias versiones de los ensamblados.En resumen, cada ensamblado puede tener un número de versión asociado a ella y cuando se firman los ensamblados con una clave, varias versiones del ensamblado pueden implementarse como en la caché de ensamblados global (GAC).Para obtener más información sobre las versiones de ensamblado y ensamblados nombres seguros, consulte elDocumentación de MSDN en ensamblados.

Esto permite crear sus flujos de trabajo y actividades en proyectos con una versión de 1,0, firmarlas y implementarlos en la GAC.Ahora, cuando se inicia un flujo de trabajo y conserva, la información de versión es parte del estado serializado.Si cambia el flujo de trabajo, es importante cambiar la versión del ensamblado y otros ensamblados que el flujo de trabajo depende de si los han cambiado, demasiado.Por ejemplo, si tuviera el flujo de trabajo en el ejemplo anterior y haya realizado un cambio a la actividad WriteLine y la definición de flujo de trabajo, a continuación, deberá incrementar el número de versión de cada proyecto e implementar las actualizaciones a la GAC.

En este momento, deberá versión 1.0 y 1.1 del flujo de trabajo implementado en la GAC.Cuando un flujo de trabajo 1.0 se carga desde el almacén de persistencia, el motor en tiempo de ejecución no podrán resolver la definición de tipo de versión 1.0 y utilizar esa información de tipo al deserializar el flujo de trabajo.Los flujos de trabajo versión 1.1 que también se conservan funcionaría puesto que el motor en tiempo de ejecución podría ser puede encontrar la definición de la versión 1.1 tipos, demasiado.Básicamente, como los ensamblados que contienen los tipos para el flujo de trabajo y sus clases relacionadas se pueden resolver y coincide con la definición original, el flujo de trabajo se deserializar correctamente y puede continuar el procesamiento.Puede ver cómo funciona este proceso en la figura 3 donde las distintas versiones se cargan desde la base de datos y sus tipos de resolver correctamente cuando se encuentra en la GAC.

fig03.gif

La figura 3 versiones de .NET en paralelo

Un punto importante a tener en cuenta es que los flujos de trabajo 1.0 continuará trabajando y procesamiento, pero aún se basan en la definición de versión 1.0 del flujo de trabajo.Esto significa que los cambios que introdujo en la versión 1.1 del flujo de trabajo no estará presentes en la definición de flujo de trabajo.En otras palabras, las actividades de agregado, quitado o modificado en caso contrario, no estarán presentes en la definición de flujo de trabajo y no podrá ver el impacto de los cambios en los flujos de trabajo versión 1.0.Más adelante, explicará una característica conocida como Actualización dinámica, que proporciona la capacidad para cambiar los flujos de trabajo 1.0 existente, en proceso.

Basta con tener versiones de al lado de los flujos de trabajo y ensamblados relacionados no significa que las cosas distribuir a lo largo de un bonito, sin embargo.La aplicación host es probable que se crea con un determinado y probablemente la más reciente, versión de los flujos de trabajo para que puedan interactuar con ellos.Esto puede provocar problemas como un host integrado con la versión 1.1 del flujo de trabajo problemas cuando intenta interactuar con flujos de trabajo de versión 1.0 que se han creado con la versión 1.0 de las clases relacionadas.

Un área que este problema a menudo surge para los desarrolladores es cuando se usa ExternalDataExchangeService junto con las actividades CallExternalMethod y de HandleExternalEvent para las comunicaciones locales.Muchas personas, pensando en que están actuando correctamente para el control de versiones, siga los pasos anteriores para que tanto las versiones 1.0 y 1.1 estén disponibles.Sin embargo, cuando el host intenta enviar datos al flujo de trabajo a través de un evento, el tipo de la interfaz que se utiliza ya no coincide con.El host utiliza la versión 1.1 de la interfaz, mientras que la instancia de flujo de trabajo se creó con la versión 1.0.

Para entender totalmente razones para esto un problema, recuerde las comunicaciones realmente funcionan en WF.(Vea para obtener más las comunicaciones de flujo de trabajo en elEntrega de septiembre de 2007 de fundamentos.) La actividad HandleExternalEvent crea una cola para recibir datos y el nombre de dicha cola incluye la información de tipo de la interfaz.Cuando se envían datos desde el host, se debe enviar a la cola correcta.ExternalDataExchangeService (EDS) utiliza la información de tipo y el nombre del evento para crear lo que cree es el nombre de la cola adecuada.Por desgracia, debido a que se creó en función de versión 1.0 de la interfaz de la cola y los EDS está creando el nombre de cola según la versión 1.1, no coincidirán con los dos objetos IComparable y la cola no se encuentran.

Para evitar totalmente este problema, la aplicación de host necesita provocar eventos en la interfaz de la versión 1.0.Dos formas posibles de lograr este objetivo son reflejo y la herencia.La primera opción implica utilizar reflexión para cargar la versión original de su servicio local y agregarla a los EDS, después del cual se provoca un evento en esa interfaz, nuevo mediante reflexión.

La segunda opción consiste en generar un ensamblado nuevo donde se crear versión 1.1 de la interfaz y que derivan de la interfaz de la versión 1.0, lo que le permite agregar eventos al tipo derivado mientras no se cambia el tipo base.De este modo, si se provocar un evento que se ha definido en la versión 1.0 de la interfaz, el nombre de la cola correcta se obtener crea y entregar el mensaje incluso si invoca esa operación a través del tipo derivado.La clave es que debe permanecer versión 1.0 de la interfaz de implementar y no cambia, y la nueva interfaz y el servicio deben derivar de la interfaz de la versión 1.0.la figura 4 muestra este enfoque.

fig04.gif

La figura 4 derivada interfaces para comunicaciones locales

Observe que sólo el servicio derivada y una interfaz se agregan a los EDS.Esto permite que el host interactuar con un único servicio pero provocar eventos basándose en varias interfaces.El objetivo es mantener la interfaz de versión 1.0 alrededor y en uso, por lo que la EDS crea nombres de cola que coincida con lo que se esté creando los flujos de trabajo.Además, observe que esto implica crear un conjunto nuevo proyecto en lugar de simplemente crear una nueva versión de la biblioteca de comunicación.Untenable es la palabra que se incluye en cuenta al pensar en esta solución a largo plazo.

Por lo general, la recomendación alrededor de las comunicaciones es evitar las actividades de comunicación local por este motivo muy y usar las actividades personalizadas que crear colas basadas en nombres más sencillos, como las cadenas, eliminar gran parte de la dependencia del tipo entre el flujo de trabajo y el host.La otra sugerencia es usar servicios de flujo de trabajo que proporcionan funciones adicionales alrededor de recibir solicitudes y enrutamiento a la versión correcta del flujo de trabajo, tal como tratará más adelante.

Control de versiones con las definiciones de flujo de trabajo XOML

El primer paso de hacer vida más fácil en cuanto al control de versiones es utilizar flujos de trabajo en función de XOML sin compilarlos.Este modelo declarativo realmente proporciona muchas ventajas adicionales a las versiones.Busque en el de 2008 de mayo de MSDN Magazine para obtener más información "Cargar los modelos de flujo de trabajo de WF").Me centraré en las ventajas de las versiones aquí.

Al crear flujos de trabajo a través de un enfoque de código, que está definiendo un nuevo tipo.Por ejemplo, si crea un flujo de trabajo nuevo de código con la plantilla de proyecto o elemento Visual Studio, que está definiendo una nueva clase que deriva de un tipo en los ensamblados WF.Esto es el motivo principal para los problemas descrito anteriormente, ya que al cambiar el flujo de trabajo agregando o quitando las actividades, se cambia el tipo.No Esto ocurrir cuando se crean flujos de trabajo XOML.

Un flujo de trabajo XOML que no se compila es simplemente un documento XML que describe una colección de los tipos existentes.Esto puede parecer una diferencia sutil, pero describir los tipos existentes en lugar de crear un nuevo tipo hace una gran diferencia.

Ésta es una definición de flujo de trabajo XOML:

<SequentialWorkflowActivity x:Name="Workflow2" 
    xmlns:ns0="clr-namespace:SimpleWorkflows" 
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/workflow">
  <ns0:WriteLineActivity x:Name="Hello" OutputText="Hello" />
  <DelayActivity TimeoutDuration="00:00:03" x:Name="SmallDelay" />
  <ns0:WriteLineActivity x:Name="World" OutputText="World" />
</SequentialWorkflowActivity>

Puede ver que el elemento raíz es SequentialWorkflowActivity, que se define en el ensamblado System.Workflow.Activities.Este tipo es versiones, como 3.0 tanto nonchanging.Si crear un flujo de trabajo utilizando este tipo como la actividad de raíz y el flujo de trabajo se serializa y conserva, pueda estar seguros que, cuando el flujo de trabajo es cargar y deserializar, el motor en tiempo de ejecución podrán encontrar versión 3.0 de la SequentialWorkflowActivity en la GAC.

¿Qué va cambiar la definición de flujo de trabajo agregando o quitando las actividades?En una definición de flujo de trabajo XOML, simplemente va a cambiar algunas XML, lo que no cambia ningún tipo.Incluso si cambia el elemento raíz en la definición de flujo de trabajo a algún otro tipo, no cambien un tipo en la que dependen de las instancias de flujo de trabajo existentes.De hecho, una vez creado un flujo de trabajo desde el XOML, que XOML podría no hará referencia a nuevo por el tiempo de ejecución durante la vida útil de esa instancia.

Mediante flujos de trabajo en función de XOML significa que no tiene a la versión los flujos de trabajo ya no va a definir tipos.Porque no tienen establecimiento inflexible de tipos de nombre y versión de los flujos de trabajo, también no tiene establecimiento inflexible de tipos asignar un nombre y versión de la otra tipos, tales como las interfaces de comunicación local y las entidades empresariales.Es mucho más fácil realizar cambios de no separación, es decir, como agregar miembros o métodos a tipos, sin cantidad de trabajo de la aplicación.

Trabajar con los flujos de trabajo XOML la desventaja es que se poco para no tener acceso a código, distinto de lo que se encapsula en sus actividades, por lo que terminan escribir actividades más.Pero puesto que las actividades son simplemente las clases, no es un bloqueador de elementos principal y permite capturar métodos que pueden utilizarse para proporcionar lógica o la condición comprobación de las actividades de un flujo de trabajo XOML de control de eventos.

Además, dado que la clase SequentialWorkflowActivity no tiene las propiedades de uso para su caso empresarial definido en él, no podrá pasar parámetros al método CreateWorkflow.Afortunadamente, puede crear su propio tipo actividad raíz, derivar de uno de los tipos de flujo de trabajo incluidos y agregar sus propiedades requeridas existe o empezar el flujo de trabajo por una actividad de recepción o actividad personalizada para puede enviar en datos iniciales justo después de iniciar el flujo de trabajo.

Por último, flujos de trabajo totalmente declarativos basados en XAML deseando, son la opción de modelos principal que provienen de WF 4.0.Se realizan muchas mejoras en las capacidades, incluyendo reemplazar eventos por lo que actualmente se denominan un ActivityAction.Básicamente, estos proporcionará con una forma de delegados mediante las actividades de modelos y tienen la actividad ejecute dichas actividades en lugar de invoca un delegado.

Control de versiones de actividad

Los flujos de trabajo son las actividades, por lo que se deduce que muchos de los problemas tratados hasta ahora con el flujo de trabajo tipos aplican a tipos de actividad, así.De hecho, así como un tipo de flujo de trabajo provoca problemas si se agregan las actividades, si agrega propiedades para una actividad escribir y realizar no versión dicho ensamblado de actividad, obtendrá las excepciones en la deserialización del flujo de trabajo.Desgraciadamente, las actividades necesario que las clases y deben ser compilados tipos, por lo que no solución XOML sencilla como con flujos de trabajo.

La respuesta corta para actividades es que debe versión les mediante técnicas de control de versiones de .NET cuando se cambia la interfaz de la actividad de alguna manera.Esto permite que los flujos de trabajo existentes y flujos de trabajo nuevos para hacer referencia a la versión correcta y ejecute correctamente.Tenga en cuenta, sin embargo, que si se corregir un defecto en un método dentro de la actividad que no cambia la interfaz, se puede realizar la corrección e implementar el ensamblado con el mismo número de versión.Cuando esa actividad se carga y ejecutar flujos de trabajo nuevos o existentes, se ejecutará el código correcto.

La respuesta larga implica un conocimiento profundo de la mecánica de serialización en .NET Framework, que está fuera del alcance de este artículo.Sin embargo se hay dos cosas de claves pueden compartir que puede proporcionar las máximas ventajas con la menor cantidad de inversión.

En primer lugar, si va a agregar propiedades o campos a la actividad, puede marcar los campos con el atributo NonSerialized para evitar la excepción de índice fuera de intervalo tras la deserialización de flujos de trabajo integrado con la versión anterior de la actividad.

En segundo lugar, se puede reemplazar el método OnActivityExecutionContextLoad para inicializar cualquier estado que no se ha deserializado automáticamente.Obtiene llama a este método cuando la actividad se vuelve a crear desde el estado almacenado o cuando se crea un nuevo contexto de ejecución.De estas técnicas juntas pueden ayudarle a realizar cambios en las actividades sin requerir que establecimiento inflexible de tipos los nombres y cambiar los números de versión.

Servicios de flujo de trabajo de control de versiones

Servicios de flujo de trabajo proporcionan desafíos similares para las comunicaciones locales, así como oportunidades adicionales para separe los mensajes de los flujos de trabajo.Gracias a que un servicio de flujo de trabajo está integrado con un contrato de servicio, cualquier control de versiones del servicio o datos contratos significa que el flujo de trabajo será necesario volver a generar con las nuevas versiones de los contratos.Cuando un mensaje llega a un extremo de servicio, se recibirá por un servicio mediante un contrato que tiene una versión concreta.Si el flujo de trabajo que se destina el mensaje se creó con la misma versión del contrato, a continuación, las cosas funcionan bien.Sin embargo, si se ha creado con la versión anterior del contrato y, a continuación, se conserva el flujo de trabajo, a continuación, el mensaje no puede enviarse.Para admitir dos versiones de los contratos, deberá implementar dos versiones del servicio.

Si bien es una pena que no puede aprovechar las capacidades de control de versiones inherentes en Windows Communication Foundation (WCF) que permitiera a una nueva versión del servicio para procesar los mensajes de los clientes integrados con la versión anterior de, WCF proporcionan un mecanismo para administrar este escenario.En el nivel de WCF, los clientes y servicios simplemente intercambian los mensajes y tipos de .NET no cruzan la red.Los problemas de control de versiones que estoy hablando sobre son únicamente en el nivel de .NET y pueden quedar oculta ante los clientes mediante un enrutador de mensajería.

La ventaja con los servicios de flujo de trabajo es que es posible publicar dos servicios, uno al lado del otro, con direcciones de extremo diferentes, aunque publicar una fachada que hace que ambos servicios accesible en la misma dirección.Con este método, cuando se implementa versión 1.0 de su servicio, puede implementarlo tras un enrutador paso a través de WCF que simplemente toma en los mensajes y pasa al servicio.Cuando esté listo para implementar la versión 1.1 del servicio, puede actualizar la información de enrutamiento de modo que obtener envíen mensajes al servicio de la versión 1.0 o el servicio versión 1.1, función en el mensaje o el contexto en el que se recibió.la figura 5 muestra este concepto de enrutador con las dos versiones de un servicio detrás de un enrutador y un cliente de interactuar con ellos.

fig06.gif

La figura 5 con un enrutador para servicios de control de versiones

La clave para garantizar que una solución con un enrutador funcionará es para implementarlo con la versión 1.0 de su servicio.Entonces cuando se mueve a la siguiente versión, el enrutador no es algo nuevo está agregando a la implementación y proceso de pruebas.El SDK de .NET Framework 3.5 proporciona un enrutador de ejemplo, y también puede seguir unartículo práctica sobre cómo utilizar las reglas WF para realizar decisiones de enrutamiento.

Actualización dinámica

Después de todos los deliberar sobre cómo administrar mejor al cambiar la definición de flujos de trabajo y tratar con las versiones nuevas y antiguas ejecutar de forma simultánea, a menudo hay una pregunta sobre cómo controlar los flujos de trabajo antiguos.Ha realizado un cambio en el flujo de trabajo por un motivo.Tal vez estaba corregir un defecto en lógica, o quizás haya las normas de cumplimiento que necesita para que seguir.Sea cual sea la razón, es a menudo el caso que permitir que todos los flujos de trabajo existentes para completar tal como definieron no es un resultado tenable.En estos casos, puede considerar que aprovecha una característica muy eficaz en WF: actualización dinámica.

En resumen, la actualización dinámica permite realizar cambios en una instancia de flujo de trabajo que se está ejecutando.Los cambios pueden constar de agregar o quitar las actividades de la estructura del flujo de trabajo.Que es todo que lo que se puede hacer, pero puede cambiar por completo la definición del flujo de trabajo.Por ejemplo, en una máquina de estado, tiene la capacidad de agregar todo estados, junto con los eventos que escuchar y las transiciones definido.Puede cambiar las transiciones de estado mediante la eliminación y re-adding SetState actividades.En un flujo de trabajo secuencial, puede agregar o quitar los pasos como los cambios de proceso empresarial.

Para realizar cambios en un flujo de trabajo, primero debe crear un objeto WorkflowChanges basado en el flujo de trabajo.En ese momento, el objeto de WorkflowChanges proporciona un clon de la estructura de flujo de trabajo que puede manipular a través de su propiedad TransientWorkflow.Realizar cambios en el clon agregando y quitando las actividades.Llamar cuando se completan los cambios, al ApplyChanges método de la clase WorkflowInstance, pasando el WorkflowChanges para representar los cambios que desee aplicar a la instancia real.

A continuación se muestra el flujo de ejemplo mostrado anteriormente, que contiene dos actividades WriteLine separadas por una actividad de retraso, con una actividad WriteLine adicional agrega al final de la secuencia.Este código se ejecuta cuando el flujo de trabajo deja de inactividad, o cuando el retraso comienza la ejecución.

WorkflowChanges changes = 
  new WorkflowChanges(instance.GetWorkflowDefinition());
CompositeActivity root = changes.TransientWorkflow;
WriteLineActivity wl = new WriteLineActivity {
  Name = "newWriteLine",
  OutputText = "dynamically added"
};
root.Activities.Add(wl);
instance.ApplyWorkflowChanges(changes);

En este ejemplo sencillo muestra lo que es posible, pero escenarios más avanzados pueden crearse para aplicar muchos cambios diferentes a un flujo de trabajo que se está ejecutando.Esto permite tomar un flujo de trabajo versión 1.0 que ya se ha iniciado y realizar cambios en la instancia de forma que funcione más como un flujo de trabajo version1.1.

Envíe sus preguntas y comentarios ammnet30@Microsoft.com.

Matt Milner es un miembro del personal técnico en Pluralsight, donde principalmente se dedica en tecnologías de sistemas conectados (WCF, Windows WF, BizTalk, "Dublin" y la plataforma de servicios Azure).Matt también es un consultor independiente especializado en diseño de la aplicación Microsoft .NET y el desarrollo.Matt regularmente comparte su amor de tecnología por hablando en conferencias locales, regionales y internacionales, como Tech Ed.Microsoft reconoce Matt como MVP para sus contribuciones de comunidad alrededor de tecnología de sistemas conectados.Póngase en contacto con Matt por medio de su blog enpluralsight.com/community/blogs/Matt.