Mutex vs Semaphore

El otro día estaba leyendo y encontré un sitio que exponía algunas preguntas que hacía Google en su entrevista de trabajo y ví una de ellas y me pareció curiosa (sobre todo porque creía saber la respuesta) y era “¿Diferencia entre Mutex y Semaphore?” y como ahora estoy a ver si aprendo un poco de concurrencia y esas cosicas me dije, esta es fácil a ver si soy capaz de explicarla de una forma sencilla.

 

Lo primero decir es que tanto el Mutex como el Semaphore son herramientas para controlar/bloquear (el nombre correcto es sincronizar, pero vamos…) el acceso a recursos desde nuestros hilillos. Y creo que lo mejor es contar un ejemplo y no de código.

 

Imaginemos (o supongamos) que tenemos 3 cajas que queremos utilizar, cuando una persona viene a utilizar una caja, se la lleva y entonces sólo quedan 2 cajas, cuando ha terminado de utilizarla la deja y vuelven a quedar 3 cajas, si vienen 3 personas y cogen las 3 cajas, el próximo que venga tendrá que esperar a que alguna de las personas termine con la caja y la devuelva.

 

Buenos si a eso le ponemos que las cajas son recursos y las personas son hilos, eso sería, más o menos, el funcionamiento de un Semaphore con Count = 3.

 

Creo que es bastante sencilo, y bien la pregunta ¿qué es el Mutex?, pues la respuestas sencilla sería decir que un Mutex es un Semaphore con Count = 1.

 

Y listo, evidentemente esto es algo más complejo pero creo que eso sería una descripción bastante sencilla y aproximada.

 

Os dejo las direcciones de la documentación del msdn para que veáis ejemplos, aquí el Mutex y aquí el Semaphore

 

Un saludo y hasta la próxima,

 

Mario Ropero.

[FW 3.5] Obtener los miembros recursivamente de un grupo en directorio activo

Hola a todos, con el FW 3.5 hay una opción para recoger todos los miembros de un grupo en modo recursivo, así que ya se acabó de ir buscando los miembros del grupo y ver si tenía a su vez miembros y todo el rato lo mismo.

 

Es que estos chicos de .NET son muuuuuy listos. Os pongo un ejemplillo pero es sumamente sencillo.

El espacio de nombres a usar es System.DirectoryServices.AccountManagement

 

string nombreGrupo = "grupo";
string nombreDominio = "dominio";

using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, nombreDominio))
{
GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, nombreGrupo);

if (grp != null)
{

foreach (Principal p in grp.GetMembers(true))
{
Console.WriteLine(p.Name);
}
grp.Dispose();
}
}

 

Y ya está, la gracia está en el GetMembers(true). Una cosa a tener en cuenta es que si el usuario que ejecuta este código no tiene permisos para poder ver un grupo dará un error de “Member not found”, así que es necesario que tenga permisos por lo menos de visualización.

Este post es corto, y creo que va a ser una serie de post para hacer cosas sencillas, porque creo que cuando estoy mucho tiempo sin desarrollar en algo, al final las cosas más sencillas o simples son las que más buscamos, o por lo menos en mi caso que soy un rato zote.

 

Un saludo a todos.

“Ar” Mario Ropero.

System.Transactions y concurrencia

 

Hola a todos, llevo bastante tiempo desconectado y es que el verano me ha sentado mal y estoy muy perruno, pero bueno vamos a ver si podemos hacer algo para remediarlo. Hace tiempo conté un problemita que me surgió con los TransactionScope y su abuso.

 

Esta vez el problema estaba en que un proceso hacía una operación y en un momento llamaba a un hilo en background para procesar otro trabajo, pero todo tenía que estar dentro de la misma transacción o al menos que sólo se hiciese commit si todos los procesos acababan bien.

Bueno pues ahí empezaron mis problemas, porque cuando tú creas un TransactionScope por defecto el crea una transacción (ambient transaction que se llama) y la almacena en el Thread Local Storage (lo que viene siendo el TLS) del hilo en uso y esto hace que no se propague a los nuevos hilos que se generan. Y buscando por la red encontré el whitepaper de un “peaso” de crack que ya me dijeron en su tiempo, el gran Juval Lowy y expone la solución para estos problemas.

 

Os lo pongo aquí, pero realmente creo que es mejor que os bajéis el whitepaper y le echéis un vistazo que no es nada pesado y la verdad explica muy bien cómo funciona todo y el LTM y bueno, clarifica bastante…

 

En el tema de la concurrencia, os pongo un ejemplo de la clase que se ejecutaría sobre uno de los hilos generados

public class Obrero
{
public void Trabaja(DependentTransaction transaccion)
{
Thread thread = new Thread(Metodo);
thread.Start(transaccion);
}

public void Metodo(object transaccion)
{
DependentTransaction tran = transaccion as DependentTransaction;

Transaction antiguaTransaccion = Transaction.Current;

try
{
Transaction.Current = tran;

Debug.WriteLine("Esto tiene que estar dentro de una transacción... o algo similar :)");

tran.Complete();
}
finally
{
//Liberamos la transaccion que hemos pasado y volvemos a poner la transacción a la antigua
tran.Dispose();
Transaction.Current = antiguaTransaccion;
}
}
}

Aquí lo único ha observar, es que  a la clase se le pasa un objeto DepedentTransaction y es el que usa para hacer el Complete() una vez hecho el trabajo que tenga que hacer, en este caso un importantísimo Debug.WriteLine.

 

Desde el “padre” para invocar a esto sería un código similar a esto

using (TransactionScope scope = new TransactionScope())
{
//Vamos a recoger la transacción actual y generar un dependentTransaction a través
//del método DependentClone()
DependentTransaction transaccion = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);

//Aquí llamo a la clase que generar el hilo y hace otro trabajo transaccional
Obrero obrero = new Obrero();

obrero.Trabaja(transaccion);

Debug.WriteLine("El papi hace cualquiero tipo de trabajo transaccional");

//Este Complete() significa que en este instante se ejecutará el Commit de los hijos y del padre
//debido a la opción de DependentCloneOption que está a BlockCommitUntilComplete, esto quiere decir
//que no se hará ningún commit de los "hijos" hasta que el padre haga el Complete()
scope.Complete();
}

Bueno aquí las cosas importantes son el método DependentClone de la transacción actual y la opción de DependentCloneOption, lo demás no es más que pasarle a la clase que hemos creado antes, la transacción generada y que trabaje sobre ella.

 

Las distintas opciones de DependentCloneOption

Esto es un enumerado que tiene dos opciones, BlockCommitUntilComplete y RollbackIfNotComplete.

La opción BlockCommitUntilComplete, hace que no se ejecuten los commit de las transacciones dependientes hasta que la transacción “padre” haga el Complete(), esto en la practica hace que cuando en una transacción dependiente se haga un Complete(), la transacción se marca como “lista para hacer commit” pero no se ejecuta.

 

La opción RollbackIfNotComplete, hace que si el “padre” ejecuta el Complete() y existe alguna transacción dependiente que todavía no haya hecho un Complete() se generará una TransactionAbortedException, y además el hilo hijo seguirá trabajando para nada porque la transacción ya está abortada.

 

 

La verdad es que esto del System.Transactions tiene bastante miga, seguiré investigando cositas que aunque es una tecnología bastante antigua ya, todavía sigue dando mucha guerra en los proyectos porque no se utiliza correctamente, y por cierto os vuelvo a recomendar a todos leeros el whitepaper de Juval Lowy que mola…

 

Un saludo a todos.

Mario Ropero.

Compilar en tiempo de ejecución

Hola a todos, seguro que muchos de vosotros ya sabéis de que va todo esto, pero es que es una de las cosas que más gracia me hizo cuando descubrí cómo hacerlo. Vamos a ver cómo gracias a una librería muy maja (System.CodeDom) podemos compilar en tiempo de ejecución y gracias a la reflexión (ya sabéis que es la raíz de todo mal) podemos ejecutarlo.

 

El uso que se le puede dar a esto es prácticamente ilimitado aunque no es tan fácil de ver (al menos en mí caso), así que me encantaría que me dijeseis para qué lo habéis usado para hacerme una idea, en mí caso yo lo tuve que usar para permitir que ciertos usuarios bastante avanzados pudieran meter validaciones complejas sobre campos y se ejecutasen al momento, vamos para hacer un generador de fórmulas y cosas así está muy bien.

 

Bueno os pongo un ejemplito para que veáis lo fácil que es (la verdad es que los chicos de .NET son unos tipos muy listos).

 

La función que genera una clase en tiempo de ejecución que tiene un método que ejecuta un “Hola Mundo!”

private object CreaYCompilaHolaMundoClass()
{
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("system.dll");
cp.ReferencedAssemblies.Add("system.data.dll");
cp.ReferencedAssemblies.Add("system.xml.dll");
cp.ReferencedAssemblies.Add("system.windows.forms.dll");

cp.GenerateExecutable = false;
cp.GenerateInMemory = true;


StringBuilder code = new StringBuilder();
code.Append("using System; n");
code.Append("using System.Windows.Forms; n");
code.Append("using System.Data; n");
code.Append("using System.Xml; n");
code.Append("using System.Reflection; n");
code.Append("namespace Prueba.Compilador { n");
code.AppendFormat(" public class {0} ", "HolaMundo");
code.Append("{ ");
//Clases de apoyo
//GetValue a string
code.Append(" public void HazTuTrabajo() n");
code.Append(" {");
code.Append(" MessageBox.Show("Hola mundo");");
code.Append(" }n");

code.Append("} }");

CompilerResults cr = CodeDomProvider.CreateProvider("C#").CompileAssemblyFromSource(cp, code.ToString());
if (cr.Errors.HasErrors)
{
StringBuilder error = new StringBuilder();
error.Append("Error al compilar: ");
foreach (CompilerError err in cr.Errors)
{
error.AppendFormat("{0}n", err.ErrorText);
}
throw new Exception("Error al compilar: " + error.ToString());
}
Assembly a = cr.CompiledAssembly;
return a.CreateInstance("Prueba.Compilador.HolaMundo");
}

 

Lo primero importante es que necesita el using del System.CodeDom.Compiler. Luego cosas a destacar, ReferencedAssemblies son las dlls que queremos referenciar desde nuestro código generado (en el ejemplo he puesto varios aunque no se necesitan todos), en este caso no se genera una dll física si no que está compilada en memoria.

Después escribimos el código que queramos que tenga (hay que tener un poco de cuidado con las llaves de apertura y cierre) y la línea de CompilerResults….. es la importante. Después de eso se genera un Assembly (System.Reflection) y se devuelve una instancia…

 

Para ejecutar lo que hemos creado sería algo similar a esto

object _comp = CreaYCompilaHolaMundoClass();
MethodInfo mi = _comp.GetType().GetMethod("HazTuTrabajo");
mi.Invoke(_comp, null);

 

Y poco más… evidentemente esto se puede complicar lo que queramos, pasando parámetros y demás… como os dije antes se abren muchas, muchísimas puertas aunque hay veces que es complicado verle la utilidad.

 

Por cierto, yo no opino que usar reflexión sea malo, siempre y cuando sea usada correctamente (creo que hay muchas discusiones sobre esto pero algún día me gustaría escribir sobre ello) la reflexión mola y mola mucho.

 

Un saludo y hasta la próxima.

Mario Ropero.

[WCF] DataContractSerializer y la propiedad IsReference. .NET 3.5 SP1

 

Hola a todos, siguiendo al hilo de mi anterior post y haciendo caso a un señor que de esto sabe un rato, se puede pasar por referencia los objetillos sin necesidad de generar un behavior especial, simplemente con una propiedad del atributo DataContract.

 

Sigo pensando exactamente lo mismo que antes, que esto, aunque solucione muchos problemas es posible que enmascare un desconocimiento de fondo por parte de los desarrolladores del proyecto, y que las cosas dejen de funcionar correctamente porque esto está o no aplicado.

 

Pero bueno al lío, que esto es rápido y sencillo.

 

Clase que NO se pasa por referencia

[DataContract]
public class Persona
{
[DataMember]
public string Nombre {get;set;}

[DataMember]
public string Apellidos {get;set;}
}

Esto es un DataContract normal y corriente.

 

Clase que SI se pasa por referencia

[DataContract(IsReference = true)]
public class Persona
{
[DataMember]
public string Nombre {get;set;}

[DataMember]
public string Apellidos {get;set;}
}

 

Como podéis observar es mucho más sencillo ahora. Lo único es que es necesario tener instalado el SP1 del framework 3.5.

 

Muchas gracias a Unai por indicarnos el camino….

 

Hasta la próxima.

 

Mario Ropero.

[WCF] Vuelta a la realidad,… y jugando con el DataContractSerializer

Hola a todos!!!!, han pasado muchas semanas sin que haya actualizado el blog, de hecho ni me he acercado a él. Necesitaba desconectar y vaya que si lo he hecho… :). Pero todo se acaba, así que aquí vuelvo a soltar rollazos a troche y moche (tampoco muchos, que esto de escribir cansa…).

 

Uno de mis mayores problemas que he encontrado cuando se trabaja con un patrón proxy (como Remoting, WCF,…) es que mucha gente no tiene claro dónde van sus objetos y cómo se pasan los valores por referencia, por valor, etc… Y se escucha mucho eso de…”He pasado mi clase loquesea y cuando actualizo en el servidor su valor, no me lo devuelve cambiado…”

 

Debo deciros que a mí también me costó lo suyo (uno que es lento…), pero bueno es bastante normal que esto ocurra, y también es normal que haya formas de evitar esto, por ejemplo en Remoting había que poner explícitamente el “ref” en la variable y el se encargaba de mantener el cambio y devolverlo.

 

Pues estuve buscando algo similar para utilizar en WCF, y encontré que si usamos el DataContractSerializer (el serializador que se usa por defecto en WCF), tenemos una opción parecida aunque un poco más compleja de elaborar, se hace a través de OperationBehavior y decoradores de métodos.

 

Generamos un DataContractSerializerOperationBehavior

Creamos una clase que herede de “DataContractSerializarOperationBehavior”, este es el behavior que luego aplicaremos a través del decorador.

public class SerializadorConReferencias : DataContractSerializerOperationBehavior
{
public SerializadorConReferencias(OperationDescription operationDescription)
: base(operationDescription)
{ }

public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return CreateDataContractSerializer(type, name, ns, knownTypes);
}

private static XmlObjectSerializer CreateDataContractSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return CreateDataContractSerializer(type, name, ns, knownTypes);
}

public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes,
2147483647 /* En plan bruto... */,
this.IgnoreExtensionDataObject,
true /*Aquí esta el cambio*/,
this.DataContractSurrogate);
}
}

 

El caso está en el último CreateSerializer al que ponemos a true la propiedad de “PreserveReferences”. Usando este serializador en vez del de por defecto ya lo tendríamos, pero queda más elegante si usamos un decorador de métodos y así decidimos los métodos que queremos que lo usen y los que no.

 

Generamos un decorador que extienda IOperationBehavior

Para crear un decorador debemos heredar de Attribute y además en este caso debemos implementar el interfaz IOperationBehavior para poder aplicar este behavior en la operación (Método) que deseemos.

public class ConReferenciasDec : Attribute, IOperationBehavior
{
#region IOperationBehavior Members
public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}

public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
IOperationBehavior innerBehavior = new SerializadorConReferencias(description);
innerBehavior.ApplyClientBehavior(description, proxy);
}

public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
{
IOperationBehavior innerBehavior = new SerializadorConReferencias(description);
innerBehavior.ApplyDispatchBehavior(description, dispatch);
}

public void Validate(OperationDescription description)
{
}

#endregion

}

Aquí lo único a destacar es que tenemos que aplicar el behavior en el cliente y en el servidor. Ahora sólo nos quedaría utilizarlo.

public interface IService
{

[OperationContract]
[ConReferenciaDec]
void DoSomething(ComplexType algo);
}

 

Conclusiones

WCF mola mucho y se pueden hacer muchísimas cosas de una forma más o menos sencilla. En este caso en particular yo no estoy muy de acuerdo en utilizar este tipo de cosas, intento explicarme, tengo claro que la forma habitual de trabajar en .NET es que si pasas un tipo complejo a un método este siempre lo pasa por referencia, esto es cierto siempre y cuando ocupen el mismo espacio de memoria, que en el caso que nos ocupa NUNCA ocurre, porque para eso estamos a través de un proxy. Es preferible que tú método devuelva el mismo tipo y te lo pase cambiado y que los desarrolladores tengan muy clara la diferencia.

Aunque bueno para gustos los colores así que cada uno tendrá su opinión.

 

Hasta la próxima…

Mario Ropero…a medio gas…

CERRADO POR VACACIONES!!!!!

 

El armario se cierra por vacaciones, qué ilusión que me hace poder decir esto. Voy a pasar las siguientes 6 (seis!!!!!!!) semanacas descansando, intentaré aprovechar para leer algo y culturizarme un poco, pero no creo que tenga mucho tiempo para escribir, así que dejaremos la actividad por un tiempo.

 

Un saludo y disfrutad los que podáis.

 

Mario Ropero.

AYUDA : Validaciones vs Excepciones

Hola a todos, estamos en pleno periodo vacacional para algunos, otros no (nos queda poco, poco) y me ha surgido un problema, que espero que podáis ayudarme a resolver. Se refiere al tema de trabajar con validaciones o trabajar con excepciones y su rendimiento.

 

A la hora de desarrollar un método cuando este recibe parámetros lo “ideal” es comprobar que los parámetros que nos llegan son válidos para utilizarlos en nuestra lógica posterior, así que según dicho esto lo que yo creo como ideal, es que la primera parte de un método sería validar la entrada de los parámetros y si está todo ok, seguir adelante.

 

Bueno, en mi caso, la realidad es bastante diferente, en mi caso particular y “chapucero” (estoy intentando cambiar…), yo soy más de los de “try…catch” y listo y sí, debo admitir que algún catch vacío existe por mi código, aunque cada vez que lo veo digo “aghhhhhhh, mis ojos, mis ojos….”

 

Esto es MALO, porque cuando te llegan varios parámetros o parámetros complejos y te da un error en el catch, no tienes la certeza de saber en qué punto te ha dado, lo normal es el típico error de “Object reference not set…” y listo, ahora tienes que averiguar en qué punto se te ha ido la pinza…

 

En este caso está claro que lo mejor es validar la entrada y después hacer lo que tengas que hacer, pero mi problema está en el rendimiento, y pensaba que era mucho más eficiente validar que trabajar con la excepción, que costaría mucho más trabajar con una excepción que con validaciones, así que me generé un código sencillo para poder verlo.

static void Main(string[] args)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
for (int aux = 0; aux < 10; aux++)
{
DoSomething(null);
}
Console.WriteLine("Tiempo total Exception " + sw.Elapsed.TotalSeconds.ToString());
sw.Stop();
sw.Start();
for (int aux = 0; aux < 10; aux++)
{
DoSomethingHasValue(null);
}
Console.WriteLine("Tiempo total HasValue " + sw.Elapsed.TotalSeconds.ToString());
Console.ReadLine();
}

private static void DoSomething(int? i)
{
try
{
int local = i.Value;
}
catch (Exception)
{
Console.WriteLine("Valor de i nulo");
}
}

private static void DoSomethingHasValue(int? i)
{
if (i.HasValue)
{
int local = i.Value;
}
}

 

Pues la salida de ese ejemplo es que las excepciones son un poco más rápidas que el “HasValue”, da igual que ponga 10, 100, 1000 o 10000, que compile en Debug o en Release, que ejecute dentro del Visual Studio o fuera.

 

Lo único que vi, es que con las excepciones en el windbg (herramienta molona) genera un montón de ruido, por otra parte normal.

 

Tengo varias cosas bastante claras, una es que se mucho mejor validar la entrada antes que dejar el control en un try…catch global, aunque no se por rendimiento, el mantenimiento posterior será mucho más sencillo. Otra cosa es que seguro que el código que he puesto está mal pero no consigo encontrar dónde y la verdad, me sorprendió mucho que sea más rápido capturar una excepción que hacer una validación.

 

Espero que podáis dedicar un tiempo y echarme una mano.

 

Muchas gracias a todos.

Mario Ropero.

 

EDITO: Gracias a un compi que ha visto el error del código que he puesto, he llegado a dos conclusiones, una soy un rato inútil por no haberlo visto antes y dos, realmente es mucho más eficiente validar antes que lanzar excepciones. Os dejo el código arreglado que lo comprueba:

static void Main(string[] args)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
for (int aux = 0; aux < 10; aux++)
{
DoSomething(null);
}
Console.WriteLine("Tiempo total Exception " + sw.Elapsed.TotalSeconds.ToString());
sw.Stop();
sw = new System.Diagnostics.Stopwatch();
sw.Start();
for (int aux = 0; aux < 10; aux++)
{
DoSomethingHasValue(null);
}
Console.WriteLine("Tiempo total HasValue " + sw.Elapsed.TotalSeconds.ToString());
Console.ReadLine();
}

private static void DoSomething(int? i)
{
try
{
int local = i.Value;
}
catch (Exception)
{
Console.WriteLine("Valor de i nulo");
}
}

private static void DoSomethingHasValue(int? i)
{
if (i.HasValue)
{
int local = i.Value;
}
}

Gracias por vuestro tiempo.

Un saludico.

Mario.

Ejecutar un servicio de Windows en 32-bit en un Windows de 64-bit

Hola a todos, llevo un tiempo apartado de los maravillosos mundos de internés, porque estamos en fase de puesta en producción en mi proyecto actual, y ya sabéis como es eso. Muchos nervios por parte de la jefatura, se ven algún que otro látigo de siete colas, alguna que otra frase graciosa del tipo “¿Dormir? Para que necesitas dormir… a trabajar…” y cosas similares. Bueno, pues unos de los diversos cambios que se hizo fue en la plataforma y pasamos de un bonito Windows Server 2003 32 bit a su esplendido predecesor el Windows 2008 Server 64-bit. Y después de unas pruebas de concepto con la aplicación vimos que todo funcionaba incluso un poco mejor, pero…¿todo?, NO todo no funcionaba a la perfección. Teníamos un pequeño servicio de Windows que se encargaba de ejecutar unos procesillos asíncronamente que decidió dejar de funcionar.

 

La situación fue un poco caótica, un procesillo del que nadie se había acordado, paso a ser la prioridad número uno, vamos que se caía el mundo si eso no funcionaba. Y allí estaba yo, con un montón de jefes revoloteando a mi lado, mirando la pantalla de mi ordenador y sus smartphones viendo que el mundo se caía, y haciendo los típicos comentarios que imagino que todos hemos escuchado alguna vez “¿Ya está?”, “¿Seguro que eso es por (poned aquí cualquier cosa que paso el día anterior que no tenga nada que ver con esto)?”, “Esto tiene que estar ya”. Y yo ahí aguantando el chaparrón y el servicio sólo me decía “No encuentro la xxx.dll”, y yo… “Joé, que la dll está aquí, ¿dónde quieres que te la deje corazón?”.

 

Lo único que había cambiado era la plataforma, así que me dije, voy a ejecutarlo en 32-bit y a probar, y… más problemillas no tenía acceso al código para compilarlo para la plataforma x86, que sería la solución ideal, y busqué por internet y encontré una pequeña maravilla que se esconde en el Windows 2008 SDK (esta herramienta es más antigua, pero para el 2008 se encuentra ahí), la herramienta ‘CorFlags.exe’.

 

Esta herramienta se encuentra en “C:Program FilesMicrosoft SDKsWindowsv6.0Binx64CorFlags.exe “, y sirve para activar el modo 32BIT a un ejecutable, en mí caso el servicio.

Para ejecutarla, es muy sencillo, si queremos poner el modo 32BIT:

CoreFlags.exe Ejecutable.exe /32BIT+

Si queremos quitar el modo 32BIT:

CoreFlags.exe Ejecutable.exe /32BIT-

Y con eso todo empezó a funcionar. Y el pequeño proceso dejó de ser la prioridad uno, y todo el mundo respiró más tranquilo. Luego estuve investigando un poco más, y el problema no era el proceso en sí que puede ejecutarse en 32 o 64, era la dll que referenciaba (un proveedor de base de datos) que no estaba instalado en modo 64bit porque no existía.

 

Hasta la próxima.

Una de TransactionScope por favor!!!!

Buenos días a todos, no tenía pensado en escribir nada de este maravilloso elemento, pero estamos haciendo una pequeña refactorización de código porque algún DBA nos dijo que en nuestra aplicación teníamos un poco de contención con las transacciones y yo pensé “Transacciones?? Si prácticamente no las usamos”, infeliz de mí, luego hice una búsqueda sencilla por el código y aquí estoy quitando código y escribiendo sobre esto.

 

Lo que me he encontrado hasta la saciedad es esto

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
//Acción sobre base de datos
DoSomething.....
scope.Complete();
}

Dónde el DoSomething es un Insert, un Update, un Delete o un Select (sí, sí… se ven cosas que dan mucho miedito), a ver…

¿PARA QUÉ NECESITAS UNA TRANSACCIÓN?, es que parece que si un insert está dentro de una transacción mola más o debe ser algo parecido, pero lo único que hace es NADA, o dar un poco por saco en todo caso.

 

Otro caso gracioso es poner una transacción para una sentencia de selección, joe… esa es buenísima y la he visto demasiadas veces por desgracia, ahora imaginaos una select entre varias tablas de vuestra base de datos que sea pesada y que tenga un transactionscope con IsolationLevel a Serializable (uuuuuuuuuuuuhhh escalofríos me entran sólo de pensarlo).

 

Otro tema son los transactionscopes encadenados, para hacer justamente eso, una acción, esto encima tiene delito porque pones a trabajar al DTC en una transacción distribuida, os pongo un ejemplito de código que me he encotrado, para que veáis:

private void Metodo1()
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{ //Acción sobre base de datos
Metodo2();
scope.Complete()
}
}

private void Metodo2()
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{ //Acción sobre base de datos
DoSomething...
scope.Complete()
}
}

 

Conclusión

Los TransactionScope están para lo que están, no para abusar de ellos porque nos pueden poner en situación bastante perjudiciales para el rendimiento de nuestra máquina, y nos pueden a llevar a bloqueos en base de datos sin quererlo. Así que se tienen que usar con cabeza y vuelvo a repetir, UNA ÚNICA OPERACIÓN EN BASE DE DATOS NO NECESITA UN TRANSACTIONSCOPE.

 

Perdonad por el tono del post, es que estoy muy cabreado con esto, que estoy aquí pico y pala quitando transactionscopes que me salen por las orejillas, intentaré escribir algún post con algún ejemplo más tangible.

 

Saludicos.