Archive for abril 2011
Me caí del mundo y no sé por dónde se entra...
Lo que me pasa es que no consigo andar por el mundo tirando cosas y cambiándolas por el modelo siguiente sólo porque a alguien se le ocurre agregarle una función o achicarlo un poco.
No hace tanto, con mi mujer, lavábamos los pañales de los críos, los colgábamos en la cuerda junto a otra ropita, los planchábamos, los doblábamos y los preparábamos para que los volvieran a ensuciar.
Y ellos, nuestros nenes, apenas crecieron y tuvieron sus propios hijos se encargaron de tirar todo por la borda, incluyendo los pañales.
¡Se entregaron inescrupulosamente a los desechables! Si, ya lo sé. A nuestra generación siempre le costó botar. ¡Ni los desechos nos resultaron muy desechables! Y así anduvimos por las calles guardando los mocos en el pañuelo de tela del bolsillo.
¡¡¡Nooo!!! Yo no digo que eso era mejor. Lo que digo es que en algún momento me distraje, me caí del mundo y ahora no sé por dónde se entra. Lo más probable es que lo de ahora esté bien, eso no lo discuto. Lo que pasa es que no consigo cambiar el equipo de música una vez por año, el celular cada tres meses o el monitor de la computadora todas las navidades.
¡Guardo los vasos desechables!
¡Lavo los guantes de látex que eran para usar una sola vez!
¡Los cubiertos de plástico conviven con los de acero inoxidable en el cajón de los cubiertos!
Es que vengo de un tiempo en el que las cosas se compraban para toda la vida!
¡Es más!
¡Se compraban para la vida de los que venían después!
La gente heredaba relojes de pared, juegos de copas, vajillas y hasta palanganas de loza.
Y resulta que en nuestro no tan largo matrimonio, hemos tenido más cocinas que las que había en todo el barrio en mi infancia y hemos cambiado de refrigerador tres veces.
¡¡Nos están fastidiando! ! ¡¡Yo los descubrí!! ¡¡Lo hacen adrede!! Todo se rompe, se gasta, se oxida, se quiebra o se consume al poco tiempo para que tengamos que cambiarlo. Nada se repara. Lo obsoleto es de fábrica.
¿Dónde están los zapateros arreglando las media-suelas de los tenis Nike?
¿Alguien ha visto a algún colchonero escardando colchones casa por casa?
¿Quién arregla los cuchillos eléctricos? ¿El afilador o el electricista?
¿Habrá teflón para los hojalateros o asientos de aviones para los talabarteros?
Todo se tira, todo se desecha y, mientras tanto, producimos más y más y más basura.
El otro día leí que se produjo más basura en los últimos 40 años que en toda la historia de la humanidad.
El que tenga menos de 30 años no va a creer esto: ¡¡Cuando yo era niño por mi casa no pasaba el que recogía la basura!!
¡¡Lo juro!! ¡Y tengo menos de.... años!
Todos los desechos eran orgánicos e iban a parar al gallinero, a los patos o a los conejos (y no estoy hablando del siglo XVII)
No existía el plástico ni el nylon. La goma sólo la veíamos en las ruedas de los autos y las que no estaban rodando las quemábamos en la Fiesta de San Juan.
Los pocos desechos que no se comían los animales, servían de abono o se quemaban. De 'por ahí' vengo yo. Y no es que haya sido mejor.. Es que no es fácil para un pobre tipo al que lo educaron con el 'guarde y guarde que alguna vez puede servir para algo', pasarse al 'compre y bote que ya se viene el modelo nuevo'.Hay que cambiar el auto cada 3 años como máximo, porque si no, eres un arruinado. Así el coche que tenés esté en buen estado . Y hay que vivir endeudado eternamente para pagar el nuevo!!!! Pero por Dios.
Mi cabeza no resiste tanto.
Ahora mis parientes y los hijos de mis amigos no sólo cambian de celular una vez por semana, sino que, además, cambian el número, la dirección electrónica y hasta la dirección real.
Y a mí me prepararon para vivir con el mismo número, la misma mujer, la misma casa y el mismo nombre (y vaya si era un nombre como para cambiarlo) Me educaron para guardar todo. ¡¡¡Toooodo!!! Lo que servía y lo que no. Porque algún día las cosas podían volver a servir. Le dábamos crédito a todo.
Si, ya lo sé, tuvimos un gran problema: nunca nos explicaron qué cosas nos podían servir y qué cosas no. Y en el afán de guardar (porque éramos de hacer caso) guardamos hasta el ombligo de nuestro primer hijo, el diente del segundo, las carpetas del jardín de infantes y no sé cómo no guardamos la primera caquita. ¿Cómo quieren que entienda a esa gente que se desprende de su celular a los pocos meses de comprarlo?
¿Será que cuando las cosas se consiguen fácilmente, no se valoran y se vuelven desechables con la misma facilidad con la que se consiguieron?
En casa teníamos un mueble con cuatro cajones. El primer cajón era para los manteles y los repasadores, el segundo para los cubiertos y el tercero y el cuarto para todo lo que no fuera mantel ni cubierto. Y guardábamos.. . ¡¡Cómo guardábamos!! ¡¡Tooooodo lo guardábamos!! ¡¡Guardábamos las tapas de los refrescos!! ¡¿Cómo para qué?! Hacíamos limpia-calzados para poner delante de la puerta para quitarnos el barro. Dobladas y enganchadas a una piola se convertían en cortinas para los bares. Al terminar las clases le sacábamos el corcho, las martillábamos y las clavábamos en una tablita para hacer los instrumentos para la fiesta de fin de año de la escuela. ¡Tooodo guardábamos!
Cuando el mundo se exprimía el cerebro para inventar encendedores que se tiraban al terminar su ciclo, inventábamos la recarga de los encendedores descartables. Y las Gillette -hasta partidas a la mitad- se convertían en sacapuntas por todo el ciclo escolar. Y nuestros cajones guardaban las llavecitas de las latas de sardinas o del corned-beef, por las dudas que alguna lata viniera sin su llave. ¡Y las pilas! Las pilas de las primeras Spica pasaban del congelador al techo de la casa. Porque no sabíamos bien si había que darles calor o frío para que vivieran un poco más. No nos resignábamos a que se terminara su vida útil, no podíamos creer que algo viviera menos que un jazmín.
Las cosas no eran desechables.. Eran guardables. ¡¡¡Los diarios!!! Servían para todo: para hacer plantillas para las botas de goma, para pone r en el piso los días de lluvia y por sobre todas las cosas para envolver. ¡¡¡Las veces que nos enterábamos de algún resultado leyendo el diario pegado al trozo de carne!!!
Y guardábamos el papel plateado de los chocolates y de los cigarros para hacer guías de pinitos de navidad y las páginas del almanaque para hacer cuadros y los goteros de las medicinas por si algún medicamento no traía el cuentagotas y los fósforos usados porque podíamos prender una hornalla de la Volcán desde la otra que estaba prendida y las cajas de zapatos que se convirtieron en los primeros álbumes de fotos y los mazos de naipes se reutilizaban aunque faltara alguna, con la inscripción a mano en una sota de espada que decía 'éste es un 4 de bastos'.
Los cajones guardaban pedazos izquierdos de pinzas de ropa y el ganchito de metal. Al tiempo albergaban sólo pedazos derechos que esperaban a su otra mitad para convertirse otra vez en una pinza completa.
Yo sé lo que nos pasaba: nos costaba mucho declarar la muerte de nuestros objetos. Así como hoy las nuevas generaciones deciden 'matarlos' apenas aparentan dejar de servir, aquellos tiempos eran de no declarar muerto a nada: ¡¡¡ni a Walt Disney!!!
Y cuando nos vendieron helados en copitas cuya tapa se convertía en base y nos dijeron: 'Cómase el helado y después tire la copita', nosotros dijimos que sí, pero, ¡¡¡minga que la íbamos a tirar!!! Las pusimos a vivir en el estante de los vasos y de las copas. Las latas de arvejas y de duraznos se volvieron macetas y hasta teléfonos. Las primeras botellas de plástico se transformaron en adornos de dudosa belleza. Las hueveras se convirtieron en depósitos de acuarelas, las tapas de botellones en ceniceros, las primeras latas de cerveza en portalápices y los corchos esperaron encontrarse con una botella.
Y me muerdo para no hacer un paralelo entre los valores que se desechan y los que preservábamos. ¡¡¡Ah!!! ¡¡¡No lo voy a hacer!!! Me muero por decir que hoy no sólo los electrodomésticos son desechables; que también el matrimonio y hasta la amistad son descartables.
Pero no cometeré la imprudencia de comparar objetos con personas. Me muerdo para no hablar de la identidad que se va perdiendo, de la memoria colectiva que se va tirando, del pasado efímero.. No lo voy a hacer. No voy a mezclar los temas, no voy a decir que a lo perenne lo han vuelto caduco y a lo caduco lo hicieron perenne. No voy a decir que a los ancianos se les declara la muerte apenas empiezan a fallar en sus funciones, que los cónyuges se cambian por modelos más nuevos, que a las personas que les falta alguna función se les discrimina o que valoran más a los lindos, con brillo,pegatina en el cabello y glamour.
Esto sólo es una crónica que habla de pañales y de celulares. De lo contrario, si mezcláramos las cosas, tendría que plantearme seriamente entregar a la 'bruja' como parte de pago de una señora con menos kilómetros y alguna función nueva. Pero yo soy lento para transitar este mundo de la reposición y corro el riesgo de que la 'bruja' me gane de mano y sea yo el entregado.
Eduardo Galeano, periodista y escritor Uruguayo
Personalizar el FCKEditor
Este componente ofrece un control de entrada de texto HTML, requiero que no se muestren las opciones de formato de fuente.
En la carpeta donde esta alojado el sitio web, buscar y editar:
..\FCKeditor\fckconfig.js
Por defecto esta de esta manera:
FCKConfig.ToolbarSets["Default"] = [
['Source','DocProps','-','Templates'],
['Cut','Copy','Paste','PasteText','PasteWord','-','SpellCheck'],
['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
['Bold','Italic','Underline','StrikeThrough'],['Subscript','Superscript'],
['OrderedList','UnorderedList','-','Outdent','Indent'],
['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
['Link','Unlink','Anchor'],
['Image','Flash','Table','Rule','Smiley','SpecialChar','PageBreak'],
['Style'],['FontFormat'],['FontName'],['FontSize'],
['TextColor','BGColor'],
['FitWindow']
] ;
Y para este caso debe quedar así:
FCKConfig.ToolbarSets["Default"] = [
['Source','DocProps','-','Templates'],
['Cut','Copy','Paste','PasteText','PasteWord','-','SpellCheck'],
['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
['Bold','Italic','Underline','StrikeThrough'],['Subscript','Superscript'],
['OrderedList','UnorderedList','-','Outdent','Indent'],
['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
['Link','Unlink','Anchor'],
['Image','Flash','Table','Rule','Smiley','SpecialChar','PageBreak'],
['TextColor','BGColor'],
['FitWindow']
] ;
Se graba y los cambios se reflejan al momento, si esto no sucede es porque el javascript se ha cacheado, simplemente CTRL-F5 en IE o su equivalente en otros navegadores.
En la carpeta donde esta alojado el sitio web, buscar y editar:
..\FCKeditor\fckconfig.js
Por defecto esta de esta manera:
FCKConfig.ToolbarSets["Default"] = [
['Source','DocProps','-','Templates'],
['Cut','Copy','Paste','PasteText','PasteWord','-','SpellCheck'],
['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
['Bold','Italic','Underline','StrikeThrough'],['Subscript','Superscript'],
['OrderedList','UnorderedList','-','Outdent','Indent'],
['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
['Link','Unlink','Anchor'],
['Image','Flash','Table','Rule','Smiley','SpecialChar','PageBreak'],
['Style'],['FontFormat'],['FontName'],['FontSize'],
['TextColor','BGColor'],
['FitWindow']
] ;
Y para este caso debe quedar así:
FCKConfig.ToolbarSets["Default"] = [
['Source','DocProps','-','Templates'],
['Cut','Copy','Paste','PasteText','PasteWord','-','SpellCheck'],
['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
['Bold','Italic','Underline','StrikeThrough'],['Subscript','Superscript'],
['OrderedList','UnorderedList','-','Outdent','Indent'],
['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
['Link','Unlink','Anchor'],
['Image','Flash','Table','Rule','Smiley','SpecialChar','PageBreak'],
['TextColor','BGColor'],
['FitWindow']
] ;
Se graba y los cambios se reflejan al momento, si esto no sucede es porque el javascript se ha cacheado, simplemente CTRL-F5 en IE o su equivalente en otros navegadores.
Ideas básicas de desarrollo con WWF
A modo de resumen, ideas básicas que tenemos que tener presente cuando desarrollamos WWF.
Existen tres tipos de flujos de trabajo:
Workflow Secuencial, útil para operaciones repetitivas y predecibles que siempre son iguales (ParallelActivity, EventHandlingScopeActivity, ConditionedActivityGroup, ListenActivity, IfElseActivity, WhileActivity, ReplicatorActivity).
Workflow State Machine, compuesto por un conjunto de estados controlados por eventos (EventDrivenActivity, SetStateActivity, StateActivity, StateInitializationActivity, StateFinalizationActivity)
Workflow controlado por datos, depende de los datos para determinar si se ejecutan o no ciertas actividades basadas en un estado de datos local.
Existe tres modalidades de contemplar WF y la lógica de negocio:
Sólo código. Éste es el modo de creación predeterminado para Windows Workflow Foundation
Separación de código
Sin código
Un RuleSet está compuesto de una o más condiciones de regla y sus acciones resultantes. Son como reglas de instrucción IF-THEN-ELSE, con la condición que corresponde a IF, y las acciones que definen el comportamiento de las cláusulas THEN y ELSE. El mecanismo de evaluación puede describirse conceptualmente como:
Comience con la lista de reglas activas.
Busque la regla de prioridad máxima.
Evalúe la regla y ejecute sus acciones Then/Else, según corresponda.
Si las acciones de una regla actualizan un campo o propiedad utilizada por la condición de una o más reglas anteriores de la lista (las que tienen mayor prioridad), vuelva a evaluar esas reglas anteriores.
Windows Workflow Foundation proporciona compatibilidad para la recuperación de errores de transacción mediante la actividad TransactionScopeActivity para encapsular transacciones System.Transactions.NET Framework, que automáticamente deshacen sus acciones si se produce un error.
Su flujo de trabajo guarda periódicamente su estado en un almacenamiento persistente durante determinados puntos de control llamados puntos de persistencia. Si algo va mal en su flujo de trabajo, podría ser necesario que el motor de tiempo de ejecución recupere la información conservada para volver a un estado estable. Si dos o más componentes se están comunicando, es a menudo útil coordinar la persistencia para que los estados de los componentes sean coherentes. Los lotes de trabajo los usan los servicios externos al flujo de trabajo para conservar información de estado. Estos servicios procesan por lotes sus elementos de trabajo y comparten la misma transacción que la del flujo de trabajo. Si el flujo de trabajo no está llevando a cabo una transacción, algunos elementos de trabajo aún pueden ser procesados por lotes por los servicios durante los puntos de persistencia.
Windows Workflow Foundation proporciona IWorkBatch y IPendingWork para ayudar a los servicios y las instancias de flujo de trabajo a conservar información de estado.
El control de errores en Windows Workflow Foundation hace referencia al control de excepciones de una manera asincrónica. Esto significa que el motor de tiempo de ejecución de flujo de trabajo detecta las excepciones producidas en una actividad (explícita o implícitamente) y, a continuación, se programan en una cola para ser administradas más tarde. Esto difiere del control de excepciones normal en que si se produce una excepción en un bloque try, el bloque catch exception adecuado lo detecta o se devuelve inmediatamente al usuario.
El modelo de compensación de Windows Workflow Foundation para transacciones completadas es el proceso de administrar cualquier excepción de negocio que se produce en un flujo de trabajo y deshacer lógicamente las transacciones completadas. La compensación de Windows Workflow Foundation puede ser:
Implícita de forma predeterminada, cuando no se especifica el controlador de excepciones o no se administra una excepción concreta.
Explícita, cuando se utiliza la actividad CompensateActivity. Para obtener más información, consulte Uso de la actividad CompensateActivity.
Los servicios de comunicación de Windows Workflow Foundation admiten el intercambio de datos entre un flujo de trabajo y su entorno host. Los servicios de comunicación de Windows Workflow Foundation le permiten a un flujo de trabajo intercambiar datos con un host local mediante las clases HandleExternalEventActivity y CallExternalMethodActivity junto con las interfaces que admiten el atributo ExternalDataExchangeAttribute.
Windows Workflow Foundation proporciona a los diseñadores y programadores una manera declarativa de crear flujos de trabajo mediante el lenguaje de marcado de aplicaciones eXtensible (XAML) para crear archivos de origen de marcado. Estos archivos de marcado se pueden compilar en un tipo de flujo de trabajo, cargarse directamente en el motor de tiempo de ejecución en el flujo de trabajo en tiempo de ejecución, o se pueden compilar en un tipo de flujo de trabajo con archivos de código subyacente implementados en C# o Visual Basic. Esto significa que los archivos de marcado de flujo de trabajo pueden compilarse o no, según las razones comerciales y si se requiere lógica de implementación adicional. El uso de marcado del flujo de trabajo con archivos lógicos de código subyacente es similar a cómo ASP.NET separa los archivos de presentación de los archivos lógicos.
Windows Workflow Foundation contiene un conjunto predeterminado de actividades que proporcionan la funcionalidad para el flujo de control, las condiciones, el control de eventos, la administración de estados, y la comunicación con aplicaciones y servicios. Al diseñar flujos de trabajo, puede utilizar las actividades proporcionadas por Windows Workflow Foundation y crear sus propias actividades personalizadas.
Las actividades son las unidades de creación fundamentales de los flujos de trabajo. Un flujo de trabajo es un conjunto de actividades organizadas jerárquicamente en una estructura de árbol. Una actividad representa una acción en un flujo de trabajo. Puede ser una acción simple, como un retraso, o una actividad compuesta que se compone de varias actividades secundarias. Una actividad, como un flujo de trabajo, puede ser secuencial, lo que significa el orden de sus acciones se especifica en el tiempo de diseño. O, la actividad puede estar orientada a eventos, lo que significa que el orden de sus acciones se determina en el tiempo de ejecución en respuesta a eventos externos. Cada actividad tiene un contexto de ejecución que representa el entorno de ejecución de la actividad. Puede utilizar las API de Windows Workflow Foundation para crear actividades personalizadas. Desarrolle una actividad personalizada mediante la definición de una clase de actividad personalizada que derive directamente de Activity, o de una actividad predeterminada que deriva de Activity. Tiene la opción de personalizar varios aspectos de su actividad personalizada, por ejemplo, la serialización, la validación, el diseño y la lógica predeterminada, utilizando un conjunto de clases relacionadas que encapsulan esas partes de funcionalidad concretas. Los atributos de actividad se utilizan para hacer referencia a estas clases personalizadas de modo que se utilice la lógica personalizada en lugar de la lógica predeterminada que usan los atributos.
Windows Workflow Foundation proporciona numerosos servicios que su aplicación puede utilizar para procesar por lotes el trabajo mediante transacciones, administrar el subprocesamiento de instancias de flujo de trabajo, conservar instancias de flujo de trabajo en medios de almacenamiento para posterior recuperación y realizar el seguimiento de la ejecución de instancias de flujo de trabajo.
El motor de tiempo de ejecución de Windows Workflow Foundation es responsable de crear y mantener en ejecución las instancias de flujo de trabajo. Para conseguirlo, el motor de tiempo de ejecución necesita un proceso host que incluya aplicaciones de consola, aplicaciones basadas en Windows Forms, sitios web de ASP.NET y servicios web. Además, las aplicaciones habilitadas por flujos de trabajo que hospedan el motor de tiempo de ejecución de Windows Workflow Foundation pueden refinar más el comportamiento del motor de tiempo de ejecución del flujo de trabajo utilizando los servicios. Los servicios base en Windows Workflow Foundation se pueden configurar para que admitan transacciones, persistencia, seguimiento, subprocesamiento y programación. Para la funcionalidad específica de aplicación, su aplicación puede definir también servicios personalizados que se pueden agregar al motor de tiempo de ejecución.
Windows Workflow Foundation admite servicios de comunicación local en el entorno host del flujo de trabajo y las comunicaciones de servicio web.
Los servicios de comunicación de Windows Workflow Foundation permiten a un flujo de trabajo interactuar con un sistema externo a través de mensajería con métodos y eventos. Los eventos se usan para enviar datos a un flujo de trabajo, mientras que los flujos de trabajo utilizan métodos para enviar datos a la aplicación host. La capacidad de comunicarse con los flujos de trabajo a través de eventos proporciona una manera asincrónica de enviar datos a un flujo de trabajo.
Existen tres tipos de flujos de trabajo:
Workflow Secuencial, útil para operaciones repetitivas y predecibles que siempre son iguales (ParallelActivity, EventHandlingScopeActivity, ConditionedActivityGroup, ListenActivity, IfElseActivity, WhileActivity, ReplicatorActivity).
Workflow State Machine, compuesto por un conjunto de estados controlados por eventos (EventDrivenActivity, SetStateActivity, StateActivity, StateInitializationActivity, StateFinalizationActivity)
Workflow controlado por datos, depende de los datos para determinar si se ejecutan o no ciertas actividades basadas en un estado de datos local.
Existe tres modalidades de contemplar WF y la lógica de negocio:
Sólo código. Éste es el modo de creación predeterminado para Windows Workflow Foundation
Separación de código
Sin código
Un RuleSet está compuesto de una o más condiciones de regla y sus acciones resultantes. Son como reglas de instrucción IF-THEN-ELSE, con la condición que corresponde a IF, y las acciones que definen el comportamiento de las cláusulas THEN y ELSE. El mecanismo de evaluación puede describirse conceptualmente como:
Comience con la lista de reglas activas.
Busque la regla de prioridad máxima.
Evalúe la regla y ejecute sus acciones Then/Else, según corresponda.
Si las acciones de una regla actualizan un campo o propiedad utilizada por la condición de una o más reglas anteriores de la lista (las que tienen mayor prioridad), vuelva a evaluar esas reglas anteriores.
Windows Workflow Foundation proporciona compatibilidad para la recuperación de errores de transacción mediante la actividad TransactionScopeActivity para encapsular transacciones System.Transactions.NET Framework, que automáticamente deshacen sus acciones si se produce un error.
Su flujo de trabajo guarda periódicamente su estado en un almacenamiento persistente durante determinados puntos de control llamados puntos de persistencia. Si algo va mal en su flujo de trabajo, podría ser necesario que el motor de tiempo de ejecución recupere la información conservada para volver a un estado estable. Si dos o más componentes se están comunicando, es a menudo útil coordinar la persistencia para que los estados de los componentes sean coherentes. Los lotes de trabajo los usan los servicios externos al flujo de trabajo para conservar información de estado. Estos servicios procesan por lotes sus elementos de trabajo y comparten la misma transacción que la del flujo de trabajo. Si el flujo de trabajo no está llevando a cabo una transacción, algunos elementos de trabajo aún pueden ser procesados por lotes por los servicios durante los puntos de persistencia.
Windows Workflow Foundation proporciona IWorkBatch y IPendingWork para ayudar a los servicios y las instancias de flujo de trabajo a conservar información de estado.
El control de errores en Windows Workflow Foundation hace referencia al control de excepciones de una manera asincrónica. Esto significa que el motor de tiempo de ejecución de flujo de trabajo detecta las excepciones producidas en una actividad (explícita o implícitamente) y, a continuación, se programan en una cola para ser administradas más tarde. Esto difiere del control de excepciones normal en que si se produce una excepción en un bloque try, el bloque catch exception adecuado lo detecta o se devuelve inmediatamente al usuario.
El modelo de compensación de Windows Workflow Foundation para transacciones completadas es el proceso de administrar cualquier excepción de negocio que se produce en un flujo de trabajo y deshacer lógicamente las transacciones completadas. La compensación de Windows Workflow Foundation puede ser:
Implícita de forma predeterminada, cuando no se especifica el controlador de excepciones o no se administra una excepción concreta.
Explícita, cuando se utiliza la actividad CompensateActivity. Para obtener más información, consulte Uso de la actividad CompensateActivity.
Los servicios de comunicación de Windows Workflow Foundation admiten el intercambio de datos entre un flujo de trabajo y su entorno host. Los servicios de comunicación de Windows Workflow Foundation le permiten a un flujo de trabajo intercambiar datos con un host local mediante las clases HandleExternalEventActivity y CallExternalMethodActivity junto con las interfaces que admiten el atributo ExternalDataExchangeAttribute.
Windows Workflow Foundation proporciona a los diseñadores y programadores una manera declarativa de crear flujos de trabajo mediante el lenguaje de marcado de aplicaciones eXtensible (XAML) para crear archivos de origen de marcado. Estos archivos de marcado se pueden compilar en un tipo de flujo de trabajo, cargarse directamente en el motor de tiempo de ejecución en el flujo de trabajo en tiempo de ejecución, o se pueden compilar en un tipo de flujo de trabajo con archivos de código subyacente implementados en C# o Visual Basic. Esto significa que los archivos de marcado de flujo de trabajo pueden compilarse o no, según las razones comerciales y si se requiere lógica de implementación adicional. El uso de marcado del flujo de trabajo con archivos lógicos de código subyacente es similar a cómo ASP.NET separa los archivos de presentación de los archivos lógicos.
Windows Workflow Foundation contiene un conjunto predeterminado de actividades que proporcionan la funcionalidad para el flujo de control, las condiciones, el control de eventos, la administración de estados, y la comunicación con aplicaciones y servicios. Al diseñar flujos de trabajo, puede utilizar las actividades proporcionadas por Windows Workflow Foundation y crear sus propias actividades personalizadas.
Las actividades son las unidades de creación fundamentales de los flujos de trabajo. Un flujo de trabajo es un conjunto de actividades organizadas jerárquicamente en una estructura de árbol. Una actividad representa una acción en un flujo de trabajo. Puede ser una acción simple, como un retraso, o una actividad compuesta que se compone de varias actividades secundarias. Una actividad, como un flujo de trabajo, puede ser secuencial, lo que significa el orden de sus acciones se especifica en el tiempo de diseño. O, la actividad puede estar orientada a eventos, lo que significa que el orden de sus acciones se determina en el tiempo de ejecución en respuesta a eventos externos. Cada actividad tiene un contexto de ejecución que representa el entorno de ejecución de la actividad. Puede utilizar las API de Windows Workflow Foundation para crear actividades personalizadas. Desarrolle una actividad personalizada mediante la definición de una clase de actividad personalizada que derive directamente de Activity, o de una actividad predeterminada que deriva de Activity. Tiene la opción de personalizar varios aspectos de su actividad personalizada, por ejemplo, la serialización, la validación, el diseño y la lógica predeterminada, utilizando un conjunto de clases relacionadas que encapsulan esas partes de funcionalidad concretas. Los atributos de actividad se utilizan para hacer referencia a estas clases personalizadas de modo que se utilice la lógica personalizada en lugar de la lógica predeterminada que usan los atributos.
Windows Workflow Foundation proporciona numerosos servicios que su aplicación puede utilizar para procesar por lotes el trabajo mediante transacciones, administrar el subprocesamiento de instancias de flujo de trabajo, conservar instancias de flujo de trabajo en medios de almacenamiento para posterior recuperación y realizar el seguimiento de la ejecución de instancias de flujo de trabajo.
El motor de tiempo de ejecución de Windows Workflow Foundation es responsable de crear y mantener en ejecución las instancias de flujo de trabajo. Para conseguirlo, el motor de tiempo de ejecución necesita un proceso host que incluya aplicaciones de consola, aplicaciones basadas en Windows Forms, sitios web de ASP.NET y servicios web. Además, las aplicaciones habilitadas por flujos de trabajo que hospedan el motor de tiempo de ejecución de Windows Workflow Foundation pueden refinar más el comportamiento del motor de tiempo de ejecución del flujo de trabajo utilizando los servicios. Los servicios base en Windows Workflow Foundation se pueden configurar para que admitan transacciones, persistencia, seguimiento, subprocesamiento y programación. Para la funcionalidad específica de aplicación, su aplicación puede definir también servicios personalizados que se pueden agregar al motor de tiempo de ejecución.
Windows Workflow Foundation admite servicios de comunicación local en el entorno host del flujo de trabajo y las comunicaciones de servicio web.
Los servicios de comunicación de Windows Workflow Foundation permiten a un flujo de trabajo interactuar con un sistema externo a través de mensajería con métodos y eventos. Los eventos se usan para enviar datos a un flujo de trabajo, mientras que los flujos de trabajo utilizan métodos para enviar datos a la aplicación host. La capacidad de comunicarse con los flujos de trabajo a través de eventos proporciona una manera asincrónica de enviar datos a un flujo de trabajo.
Building an MVC 3 App with Code First and Entity Framework 4.1
Watch a video of this content
.png)
Download the code for this article:
- C# version (VS2010)
- VB version (VS2010)
Microsoft’s ADO.NET Entity Framework (EF) simplifies data access by allowing you to avoid working directly with the database in your code. Instead you can retrieve data by writing queries against strongly typed classes letting the Entity Framework handle the database interaction on your behalf. EF can also persist changes back to the database for you. In addition to this benefit, you will also benefit from the EF’s comprehension of relationships. This means you will not be required to write extra code to specify joins between entities when expressing queries or simply working with your objects in memory.
EF provides you with three ways to describe the model of your entities. You can begin with a legacy database to create a model. You can design a model in a designer. Or you can simply define classes and let EF work with those. This last tactic is referred to as code first, because the first thing you do is write code to describe your entities.
In this whitepaper, I will walk you through creating a simple MVC 3 application using Entity Framework’s code first technology to describe your classes and manage all of your data access.
Overview
In this walkthrough you will build pieces of a blogging application. The walkthrough will not result in a fully functional blogging application, but instead it will use the blog classes to demonstrate code first’s features. You will:- Define a set of classes to represent the entities for a blog — Blog, Post and Comment.
- Reference the Entity Framework code first assembly.
- Create a DbContext to manage the Blog classes and data access.
- Build a simple ASP.NET MVC 3 application that will let you view, add, edit and delete blogs.
Creating the MVC Application
For this demo, all of the code will live inside of an MVC 3 project so the first step will be to create that project. You’ll use a template that will set up much of the structure for the application.If you have not installed MVC 3 you can find the download and instructions at http://www.asp.net/mvc/mvc3.
- In Visual Studio 2010, add a new project by selecting the File menu, then New and then Project.
- In the Search Installed Templates text box (top right), type MVC 3 to filter down the list of project templates.
- Select ASP.NET MVC 3 Web Application using your language of choice. This walkthrough will use C# code, but you can find both C# and Visual Basic versions in the sample solutions download.
- Name the project MVC3AppCodeFirst and then click OK.
- In the New ASP.NET MVC 3 Project wizard, choose Internet Application.
- Leave the default values of the other options and click OK.
.png)
Figure 1: Creating a new MVC 3 Project
Visual Studio will create a full project structure for you including folders that contain pre-built controller classes, models and views. In fact you can run the application already to see it’s default content which is simply a message welcoming you to MVC.
Creating the Model Classes for the Blogging Application
The M in MVC stands for Model and represents your domain classes. Each class is thought of as a model. You’ll store your model classes — Blog, Post and Comment — in the Models folder. To keep things simple for your first look at code first, we’ll build all three classes in a single code file.- In Solution Explorer, right click the Models folder.
- Select Add from the menu and then from the bottom of its context menu choose Class.
- In the Add New Item dialog, change the new class name to BlogClasses.
- A new file, BlogClasses will be created.
- Remove the BlogClasses class from within the file and replace it with the three classes listed below.
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string BloggerName { get; set;}
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public ICollection<Comment> Comments { get; set; }
}
public class Comment
{
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public string Content { get; set; }
public int PostId { get; set; }
public Post Post { get; set; }
}
Creating an Entity Framework Context to Manage the Classes and Database Interaction
Now that you have classes, you’ll need to bring in the Entity Framework to manage those classes while it provides data access and change tracking for their object instances. Entity Framework’s DbContext class performs this job. We’ll create a class that inherits from DbContext and knows how to serve up and manage the Blog, Post and Comment objects. The Entity Framework will take care of bridging the classes and a database.Before you can use the DbContext, you’ll need to create a reference to the Entity Framework 4.1 API. When you installed MVC 3, it added a new feature to Visual Studio 2010 called Nuget. Nuget allows you to easily find and install reference assemblies from the internet.
- Select the MVC3AppCodeFirst project in Solution Explorer.
- From the Tools Menu, choose Library Package Manager which has a sub-menu.
- From the sub-menu choose Package Manager Console.
- At the console’s PM prompt type install-package EntityFramework then hit enter.
.png)
Figure 2: Installing the Entity Framework 4.1 package reference
Also there will be a new reference listed in the project references called EntityFramework. This is the assembly that contains the Code First runtime.
- Add a new class to the Models folder and name it BlogContext.
- Modify the class to match the following code:
using System.Data.Entity;
namespace MVC3AppCodeFirst.Models
{
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
}
}
But where is this database? Code first depends on a default presumption about the location of a database. If you don’t specify otherwise, EF will look for the database in the default location and if it doesn’t exist, it will create it for you. Also by default, this database will be a SQL Express database with the name derived from the strongly typed name of the context and its file will be in the SQL Express default data folder. For example:
C:\Program Files\Microsoft SQL Server\MSSQL10.SQLEXPRESS\MSSQL\ DATA\MVC3AppCodeFirst.Models.BlogContext.mdfWe’ll rely on this default behavior for this walkthrough.
Creating the Controller Logic for the Blog Class
The “C” in MVC stands for controller. A controller gathers up data and sends it to a view and responds to requests from the view. We’ll create a controller that uses the BlogContext to retrieve data for us. In a more advanced application, you should separate logic further and would not be working with the BlogContext directly from the controller.For the Blog class, we’ll be creating one view that displays a list of available Blogs and another that lets users create new Blogs. Therefore the controller will need one method to gather up a list of blogs to present in the first view, another method to provide a view to enter information for a new blog and finally a method to handle saving that new blog back to a database.
The project template created a controller called Home with a set of views and another controller called Account with its own set of views. We’ll ignore those and create our own controllers and views, starting with a controller for the Blog class.
- Build the project by choosing Build from the Visual Studio menu and then Build MVC3AppCodeFirst from its drop-down menu.
- In the Solution Explorer, right click the Controllers folder.
- Click Add from its context menu and then Controller.
- In the Add Controller window, change the Controller Name to BlogController and check the Add action methods checkbox.
- Click the Add button.
The job of the Index method will be to return a list of Blogs to be displayed in a view. The default code returns an empty View. Change the Index method code to the following:
public ActionResult Index()
{
using (var db = new BlogContext())
{
return View(db.Blogs.ToList());
}
}
Since you don’t yet have a database, code first will create it the first time you run this application and execute the Index method. After that, code first will automatically use the database that is created. As stated earlier, we’ll rely on the default behavior and won’t need to be concerned any more about the database.
Creating the Index View to Display the Blog List
We’ll add an Index view so that you can see what happens to the results of the Index method.- Right click anywhere in the Index method declaration (public ActionResult Index()).
- In the context menu that opens click the Add View option.
.png)
Figure 3: Adding a view to a controller ActionResult
- The AddView dialog will open with the View name already set to Index.
- Check the Create a strongly typed view checkbox.
- Drop down the Model class option and select Blog.
- From the Scaffold template options select List.
- Click Add to complete the view creation.
.png)
Figure 4: Creating a new view to display a list of Blog types
Visual Studio will create a Blog folder inside of the Views folder and add the new Index view to that folder as shown in Figure 5.
.png)
Figure 5: The new Blog Index View is added to the Views/Blog folder
Since the very first call to this method will create a new database, the list of blogs will be empty and you’ll have to begin by creating new blogs. This is where the two Create methods come into play. Let’s add in the Create logic and View before running the app. Note that you’ll need to make a change to the global.asax file before running the app anyway. You’ll do this shortly.
Adding Controller Logic to Create New Blogs
The first Create method does not need to return anything along with the View. Its View will be used to enter details for a new blog, so those details will start out empty. You don’t need to make any changes to this method.public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(FormCollection collection)
Modify the Create method overload (the second Create method) to match the following code:
[HttpPost]
public ActionResult Create(Blog newBlog)
{
try
{
using (var db = new BlogContext())
{
db.Blogs.Add(newBlog);
db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Adding a View for the Create Action
Next, create a view for the Create ActionResult as you did for Index. You can right click either of the Create methods but you only need to build one Create view. Figure 6 shows the settings for the Create view. Notice that the scaffold template is Create. That will result in a very different looking web page than the List you chose for the Index view..png)
Figure 6: Creating a new view to allow users to add a new Blog.
The new view will be added to the Views/Blog folder along with the Index view you created.
Running the Application
When you first created the MVC application with the template defaults, Visual Studio created a global.asax file that has in it an instruction, called a routing, that tells the application to start with the Index view of the Home controller. You’ll need to change that to start with the Index View of the Blog controller instead.- Open the global.asax file from Solution Explorer.
- Modify the MapRoute call to change the value of controller from “Home” to “Blog”.
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Blog", action = "Index", id = UrlParameter.Optional }
.png)
Figure 7: Blog List (empty)
Not much to see here except that when you return a View from the BlogController Index method, MVC will find the Blog Index view and display that along with whatever was passed in, which in this case was an empty list.
Clicking the Create New link will call the Create method which returns the Create view. After entering some information, such as that shown in Figure 8 and clicking the Create button, control is passed back to the Controller, this time calling the Create post back method.
.png)
Figure 8: Creating a new blog
The view pushed a blog instance back to the Create method, which then uses the BlogContext to push that data into the database. The Create method then redirects to the Index method which re-queries the database and returns the Index View along with the list of Blogs. This time the list has a single item in it and is displayed as shown in Figure 9.
.png)
Figure 9: Blog list after adding new blog
Implementing Edit and Delete
Thus far you have queried for data and added new data. Now you’ll see how Code First lets you edit and delete data just as easily.To demonstrate this you’ll use the BlogController’s Edit and Delete methods. This means you’ll need the corresponding Views.
- Create an Edit View from the BlogController Edit method. Be sure to select a strongly typed view for the Blog class and the Edit scaffolding type.
- Create a Delete View from the Blog Controller Edit method. Again, you must select a strongly typed view for the Blog class and this time, the Delete scaffolding type.
- Modify the Edit method to match the following code;
public ActionResult Edit(int id)
{
using (var db = new BlogContext())
{
return View(db.Blogs.Find(id));
}
}
Your project will need a reference to the System.Data.Entity namespace in order to change the State. The first few steps that follow show you how to do that.
- Right click the References folder in Solution Explorer.
- Choose Add Reference… from the References context menu.
- Select the .NET tab in the Add Reference dialog.
- Locate the System.Data.Entity component, select it and then click OK.
- Modify the Edit HttpPost method to make the context aware of the Blog and then save it back to the database as follows:
[HttpPost]
public ActionResult Edit(int id, Blog blog)
{
try
{
context.Entry(blog).State = System.Data.EntityState.Modified;
context.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
By default, the Edit view presents all of the properties except the key, BlogID.
.png)
Figure 10: Editing the blog information
After the changes are saved in the Edit postback method, MVC redirects back to the Index method. A fresh query is executed to retrieve the Blogs, including the newly updated Blog, which are then displayed in the Index view.
.png)
Figure 11: After editing blog information
Deleting a Blog will work in much the same way.
Modify the Delete methods to match the following examples:
public ActionResult Delete(int id)
{
using (var context = new BlogContext())
{
return View(context.Blogs.Find(b));
}
}
[HttpPost]
public ActionResult Delete(int id, Blog blog)
{
try
{
using (var context = new BlogContext())
{
context.Entry(blog).State = System.Data.EntityState.Deleted;
context.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
The Delete view presents a confirmation screen to the user.
.png)
Figure 12: Delete Confirmation Screen
When the user clicks the Delete button, the Delete postback method will be executed and the user will be returned to the Index view.
Summary
Entity Framework’s Code First enables the simplest path from your logic to your persisted data. At its simplest, you need no more than a reference to the special API and a class that derives from DbContext that has knowledge of your domain classes. Code First will even create the data store for you, by default, a SQL Express database with no effort on your part.The Evolution of a Programmer
The Evolution of a Programmer
High School/Jr.High
10 PRINT "HELLO WORLD" 20 END
First year in College
program Hello(input, output) begin writeln('Hello World') end.
Senior year in College
(defun hello (print (cons 'Hello (list 'World))))
New professional
#include <stdio.h> void main(void) { char *message[] = {"Hello ", "World"}; int i; for(i = 0; i < 2; ++i) printf("%s", message[i]); printf("\n"); }
Seasoned professional
#include <iostream.h> #include <string.h> class string { private: int size; char *ptr; string() : size(0), ptr(new char[1]) { ptr[0] = 0; } string(const string &s) : size(s.size) { ptr = new char[size + 1]; strcpy(ptr, s.ptr); } ~string() { delete [] ptr; } friend ostream &operator <<(ostream &, const string &); string &operator=(const char *); }; ostream &operator<<(ostream &stream, const string &s) { return(stream << s.ptr); } string &string::operator=(const char *chrs) { if (this != &chrs) { delete [] ptr; size = strlen(chrs); ptr = new char[size + 1]; strcpy(ptr, chrs); } return(*this); } int main() { string str; str = "Hello World"; cout << str << endl; return(0); }
Master Programmer
[ uuid(2573F8F4-CFEE-101A-9A9F-00AA00342820) ] library LHello { // bring in the master library importlib("actimp.tlb"); importlib("actexp.tlb"); // bring in my interfaces #include "pshlo.idl" [ uuid(2573F8F5-CFEE-101A-9A9F-00AA00342820) ] cotype THello { interface IHello; interface IPersistFile; }; }; [ exe, uuid(2573F890-CFEE-101A-9A9F-00AA00342820) ] module CHelloLib { // some code related header files importheader(<windows.h>); importheader(<ole2.h>); importheader(<except.hxx>); importheader("pshlo.h"); importheader("shlo.hxx"); importheader("mycls.hxx"); // needed typelibs importlib("actimp.tlb"); importlib("actexp.tlb"); importlib("thlo.tlb"); [ uuid(2573F891-CFEE-101A-9A9F-00AA00342820), aggregatable ] coclass CHello { cotype THello; }; }; #include "ipfix.hxx" extern HANDLE hEvent; class CHello : public CHelloBase { public: IPFIX(CLSID_CHello); CHello(IUnknown *pUnk); ~CHello(); HRESULT __stdcall PrintSz(LPWSTR pwszString); private: static int cObjRef; }; #include <windows.h> #include <ole2.h> #include <stdio.h> #include <stdlib.h> #include "thlo.h" #include "pshlo.h" #include "shlo.hxx" #include "mycls.hxx" int CHello::cObjRef = 0; CHello::CHello(IUnknown *pUnk) : CHelloBase(pUnk) { cObjRef++; return; } HRESULT __stdcall CHello::PrintSz(LPWSTR pwszString) { printf("%ws ", pwszString); return(ResultFromScode(S_OK)); } CHello::~CHello(void) { // when the object count goes to zero, stop the server cObjRef--; if( cObjRef == 0 ) PulseEvent(hEvent); return; } #include <windows.h> #include <ole2.h> #include "pshlo.h" #include "shlo.hxx" #include "mycls.hxx" HANDLE hEvent; int _cdecl main( int argc, char * argv[] ) { ULONG ulRef; DWORD dwRegistration; CHelloCF *pCF = new CHelloCF(); hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // Initialize the OLE libraries CoInitializeEx(NULL, COINIT_MULTITHREADED); CoRegisterClassObject(CLSID_CHello, pCF, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegistration); // wait on an event to stop WaitForSingleObject(hEvent, INFINITE); // revoke and release the class object CoRevokeClassObject(dwRegistration); ulRef = pCF->Release(); // Tell OLE we are going away. CoUninitialize(); return(0); } extern CLSID CLSID_CHello; extern UUID LIBID_CHelloLib; CLSID CLSID_CHello = { /* 2573F891-CFEE-101A-9A9F-00AA00342820 */ 0x2573F891, 0xCFEE, 0x101A, { 0x9A, 0x9F, 0x00, 0xAA, 0x00, 0x34, 0x28, 0x20 } }; UUID LIBID_CHelloLib = { /* 2573F890-CFEE-101A-9A9F-00AA00342820 */ 0x2573F890, 0xCFEE, 0x101A, { 0x9A, 0x9F, 0x00, 0xAA, 0x00, 0x34, 0x28, 0x20 } }; #include <windows.h> #include <ole2.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include "pshlo.h" #include "shlo.hxx" #include "clsid.h" int _cdecl main( int argc, char * argv[] ) { HRESULT hRslt; IHello *pHello; ULONG ulCnt; IMoniker * pmk; WCHAR wcsT[_MAX_PATH]; WCHAR wcsPath[2 * _MAX_PATH]; // get object path wcsPath[0] = '\0'; wcsT[0] = '\0'; if( argc > 1) { mbstowcs(wcsPath, argv[1], strlen(argv[1]) + 1); wcsupr(wcsPath); } else { fprintf(stderr, "Object path must be specified\n"); return(1); } // get print string if(argc > 2) mbstowcs(wcsT, argv[2], strlen(argv[2]) + 1); else wcscpy(wcsT, L"Hello World"); printf("Linking to object %ws\n", wcsPath); printf("Text String %ws\n", wcsT); // Initialize the OLE libraries hRslt = CoInitializeEx(NULL, COINIT_MULTITHREADED); if(SUCCEEDED(hRslt)) { hRslt = CreateFileMoniker(wcsPath, &pmk); if(SUCCEEDED(hRslt)) hRslt = BindMoniker(pmk, 0, IID_IHello, (void **)&pHello); if(SUCCEEDED(hRslt)) { // print a string out pHello->PrintSz(wcsT); Sleep(2000); ulCnt = pHello->Release(); } else printf("Failure to connect, status: %lx", hRslt); // Tell OLE we are going away. CoUninitialize(); } return(0); }
Apprentice Hacker
#!/usr/local/bin/perl $msg="Hello, world.\n"; if ($#ARGV >= 0) { while(defined($arg=shift(@ARGV))) { $outfilename = $arg; open(FILE, ">" . $outfilename) || die "Can't write $arg: $!\n"; print (FILE $msg); close(FILE) || die "Can't close $arg: $!\n"; } } else { print ($msg); } 1;
Experienced Hacker
#include <stdio.h> #define S "Hello, World\n" main(){exit(printf(S) == strlen(S) ? 0 : 1);}
Seasoned Hacker
% cc -o a.out ~/src/misc/hw/hw.c % a.out
Guru Hacker
% echo "Hello, world."
New Manager
10 PRINT "HELLO WORLD" 20 END
Middle Manager
mail -s "Hello, world." bob@b12 Bob, could you please write me a program that prints "Hello, world."? I need it by tomorrow. ^D
Senior Manager
% zmail jim I need a "Hello, world." program by this afternoon.
Chief Executive
% letter letter: Command not found. % mail To: ^X ^F ^C % help mail help: Command not found. % damn! !: Event unrecognized % logout