Los shares en el gestor de fuentes de Team Foundation Server

Como seguramente ya conoceréis Team System no dispone de la funcionalidad de “shares” que había en Visual Source Safe.


Esta funcionalidad te permitía poder  tener varios ficheros en ubicaciones diferentes pero relacionados. Se crea una relación entre los diferentes ficheros que provoca que cuando se cambie uno se cambien todos los ficheros relacionados.


Si tienes varios proyectos que ceomparten fuentes esta característica te permite que los fuentes estén incluidos en todos los proyectos y que físicamente estén los ficheros en todos los proyectos. Es decir, que si tenemos 5 proyectos y todos comparten varios ficheros, todos estos ficheros estarían en las 5 ubicaciones, pero si cambia uno de ellos se actualizan todos.


Pero…¿ Qué hago si necesto compartir ficheros entre diferentes proyectos?


La primera es fácil. Usar un add-in de Team Foundation Server  de Component  Software, TFSLinks. Esta aplicación mantiene la relación entre los ficheros y actualiza todas las referencias automáticamente cuando se hace un check-in.


Otra opción es crear un directorio común a todos los proyectos donde estén los fuentes comunes. Los fuentes no están duplicados, sólo es una única ruta. Los proyectos que necesiten usar estos fuentes deben incluirlos en el proyecto. Creais una nueva carpeta desde visual studio al proyecto y añadis los ficheros comunes usando la opción “Add As Link”. 



De esta manera los fuentes no están en múltiples ubicaciones, están todos localizados en una única ruta, pero los proyectos que los necesiten los pueden usar sin problemas. Lógicamente, si desde un proyecto se modifica el fichero todos los proyectos disponen automáticamente de los cambios, ya que sólo hay una versión del mismo.


Para los que sigáis usando el lenguage de los dioses, C++, decir que estos proyectos no disponen de la opción “Add As Link”. Cuando se añade un fichero a un proyecto sólo existe la opción “Add”, pero no os preocupéis  porque el resultado es el mismo. Lo único que hay que tener en cuenta es que cuando se cree una carpeta dentro del proyecto hay que asegurarse que la opción “SCC Files” del proyecto esté puesta a True.



Si está opción no está activada el fichero no estará gestionado por el control de código fuente de TFS y mostrará un icono como el de la imagen, con el icono “stop”.



Y como última alternativa siempre tenemos la opción de evitar la compartición de ficheros dentro de nuestros proyectos y fomentar el uso de librerías.

Secuenciar operaciones de un servicio

Un tema que me ha parecido interesante es la posibilidad de poder secuenciar operaciones dentro de un servicio WCF. Muy sencillo y muy fácil de utilizar….eso sí, tiene la pega que es que esta funcionalidad es específica de WCF y no sigue ninguna especificación WS-* estandard. Así que cuidado si tenéis un requisito de interoperabilidad entre el servicio y posibles aplicaciones clientes hechas en otras tecnologías ya que no podéis utilizar esta funcionalidad.


En un servicio WCF, sobre todo si se está usando sesión, es habitual necesitar que ciertas operaciones se realicen en un cierto orden. Imaginaros el típico carrito de compra. No se puede comprar si no se han seleccionado los elementos a comprar.


Con WCF es muy sencillo implementar esta lógica, usando dos propiedades que se establecen en el OperationBehavior; IsInitiating y IsTerminating.


Si IsInitiating está true en una operación cuando ésta se invoca se crea una nueva instancia y una nueva sesión. Si ya existe una sesión esta operación no tiene efecto. Por defecto está es valor es true.


Si IsInitiating está a false sólo se puede invocar la operación si antes se ha llamado a otra operación que ha iniciado la sesión. Esto provoca que siempre tenga que haber una operación con IsInitiating = true.


Si IsTerminating = true significa que cuando se invoque esta operación se terminará la sesión y se liberará la instancia cuando la operación se termine. El valor por defecto es false. Antes de invocar a una operación con IsTerminating=true es necesario llamar a otra operación que tenga IsInitiating = true.


Por último, es importante tener en cuenta que estas dos propiedades están relacionadas con el atributo SessionMode de ServiceContract. Si algunas operación del servicio tiene el valor IsInitiating = false o IsTerminating = true es necesario poner SessionMode.Required si no queremos que nos salga una excepción.


[ServiceContract ( SessionMode = SessionMode.Required, Namespace = “…”, Name = “…” ) ]


public interface IService


{


…………………..



 

¿ Problemas registrando un listener HTTP con un usuario no administrador ?

Siempre que desarrollamos una aplicación tenemos que tener en cuenta que nuestra aplicación sólo debe disponer de los mínimos privilegios necesarios. Tener en cuenta esta situación provoca que sea un poco más complicado la configuración de nuestra aplicación.


Cuando tiene privilegios de administrador todo va muy bien, pero cuando se cambia habitualmente surgen problemas que no siempre son fáciles de diagnosticar.


Uno de los puntos importantes a tener en cuenta cuando desarrollamos un servicio WCF es que, por defecto, para poder registrar un listener HTTP  es necesario disponer de privilegios de administrador.


Si estamos desarrollando un servicio que está hosteado en un servicio windows es recomendable que el servicio windows corra como NetworkService en lugar de usar los privilegios de LocalSystem. Si usamos NetworkService y exponemos algún endpoint HTTP, aunque sean los metadatos del servicio, tendremos un problema de permisos y el host no podrá arrancar correctamente dando una excepción de acceso denegado ( AddressAccessDeniedException ) indicando que no puede registrar la URL http.


La solución es fácil; hay que dar permisos al usuario NetworkService para que puede registrar la URL. Ahora veremos cómo.



En Windows XP y Windows 2003 se necesita disponer de la utilidad httpcfg. Es necesario instalar las Windows Supports Tools para poder disponer de él. Lo podeis descargar de aquí.


Mediante esta utilidad se puede establecer los permisos de acceso a una determinada URL. El acceso se da usando una lista ACL, donde se indica el usuario ( Sid ) y los permisos que tiene ( lectura, ejecución…)



httpcfg set urlacl /u http://+:8080/services/example /a D:(A;;GA;;;NS)



La sintaxis completa de httpcfg la podéis ver aquí.


Si el sistema operativo que usáis es Vista, la utilidad que debéis emplear es netsh.



add urlacl url=http://+:8080/services/example user=NetworkService


Una vez que hayáis hecho esto el host podrá registrar correctamente el listener http y arrancar sin problemas.

¿ Un bug estableciendo las seguridad en las colas MSMQ ?

 Pues al menos tiene toda la pinta. Os cuento….


En un proyecto en el que estoy involucrado tengo un servicio WCF que está hosteado en un servicio Windows.El servicio windows corre con el usuario NetworkService ( con LocalSystem todo iba perfecto 🙂 ) y necesita acceder a unas colas MSMQ que previamente había creado.


Al instalar el servicio tenía un método para dar permisos al usuario NetworkService para acceder a las colas: 



        private void SetPermissionToQueue(string queuePath)
        {
            //Creamos la lista de acceso
            AccessControlList accessControlList = new AccessControlList();


            //Creamos una entrada para la lista
            AccessControlEntry entry = new AccessControlEntry();
            entry.Trustee = new Trustee(<nombre del usuario al que hay que dar permisos>);
            entry.StandardAccessRights = StandardAccessRights.All;
            entry.GenericAccessRights = GenericAccessRights.All;
            entry.EntryType = AccessControlEntryType.Allow;


            //Agregamos la entrada a la lista
            accessControlList.Add(entry);


            //Asignamos la lista de acceso a la cola
            MessageQueue queue = new MessageQueue(queuePath);
            queue.SetPermissions(accessControlList);
        }



Parece sencillo, no ? Lanzado este código todo parecía que estaba bien. Reviso la seguridad de las colas en las herramientas administrativas y todo perfecto; el usuario NetworkService estaba incluido en la lista de usuarios con permisos y con todos los permisos que yo le había dado…


Pero no funciona. Arranco el servicio y éste no puede acceder a las colas; acceso denegado. Y Aquí empieza lo raro.


Si desde las herramientas administrativas de MSMQ accedo a la pestaña de seguridad y simplemente desmarco y marco cualquier opción, dejando todo igual…es decir, sin tocar nada, todo empieza a funcionar!!!!


Perfecto, ya tengo la solución. Cada vez que instale mi aplicacíón sólo tengo que ir ahí y desmarcar-marcar 🙂


La solución? Pues usando otra sobrecarga de “SetPermissions” conseguí echarlo a funcionar.



        private void SetPermissionToQueue(string queuePath)
        {
               MessageQueue queue = new MessageQueue(queuePath);


              queue.SetPermissions(<nombre del usuario al que hay que dar permisos>, MessageQueueAccessRights.FullControl, AccessControlEntryType.Allow);         


        } 


Con esto más sencillo y sobre todo, funciona 🙂


 

Ven a llorar con nosotros….

“Ven a llorar con nosotros…..sobre Arquitectura” es el nombre del siguiente evento del grupo de usuario del Pais Vasco Artalde.NET.


¿Quién no ha tenido una duda sobre cómo diseñar una arquitectura o quién no ha estado involugrado en discusiones sobre qué opción es mejor…….¿Cuántas capas pongo en mi aplicación?¿Devuelvo datasets a la capa de presentación o uso colecciones?¿Uso enterprise library?¿ Debo usar procedimientos almacenados o sentencias SQL? 


Pues ha llegado el momento de exponer todas las dudas y/o problemas que nos hemos tenido y entre todos los asistentes intentar dar una solución.  Con este evento buscamos involucrar a todos los asistentes, invitándoles a la participación y por qué no…A llorar con nosotros!!!


Fecha evento: Miércoles 23 de Mayo 2007


Hora: 19:00 h – 21:00 h 


Sitio. El de siempre….En el edificio ESIDE de la universidad Deusto. 


Toda la información completa y registro aquí. 


Web del grupo de usuarios: www.artalde.net

Siguiendo con las instancias del servicio WCF

Como comenté anteriormente la propiedad InstanceContextMode determina el ciclo de vida de las instancias del servicio. Esta propiedad se establece de forma global una sola vez para toda la clase.


Pero ¿ qué pasa si queremos cambiar esto?¿ Podemos hacer que una determinada operación haga que el servicio se comporte de manera diferente? La respuesta es sí.


En el OperationBehavior del método podemos establecer la propiedad ReleaseInstanceMode, que viene a completar la funcionalidad ofrecida por InstanceContextMode.


[OperationBehavior ( ReleaseInstanceMode =  <valor> ) ]


public bool Operation()


{


Los valores que puede adoptar este atributo son:


ReleaseInstanceMode.AfterCall. Cuando finaliza la operación la instancia del servicio libera la instancia. Si el cliente invoca otra operación se creará otra instancia.


ReleaseInstanceMode.BeforeCall. Si existe ya una instancia cuando el cliente lo llama, éste se destruirá y se creará una nueva.


ReleaseInstanceMode.BeforeAndAfterCall. Como es de suponer es una combinación de las dos anteriores.


ReleaseInstanceMode.None. Es el valor por defecto. Se hace caso al valor de InstanceContextMode.


Conocer esta propiedad, las propiedades InstanceContextMode y Concurrency y los parámetros de Throtting es algo básico para poder diseñar tu servicio WCF.


 

¿Cómo quiero que se comporten las instancias de mi servicio WCF?


Para poder realizar un buen diseño de un servicio WCF me parece crítico conocer en profudidad las propiedades InstanceContextMode y ConcurrencyMode, y establecer los valores adecuados en el ServiceBehavior en una fase temprana si no queremos llevarnos sorpresas posteriormente.


Elegir uno u otro valor puede afectar a factores como la escabilidad o incluir necesidades de sincronización en el acceso a la información.


InstanceContextMode permite delimitar el número de instancias que se crean en el servidor y cómo se comportan éstas, mientras que ConcurrencyMode permite controlar los hilos que pueden levantarse.


InstanceMode.PerSession


Se crea una instancia nueva cuando una aplicación cliente invoca por primera vez a una operación del servidor y permanece activa hasta que el cliente cierra la conexión, permaneciendo activa hasta entonces para atender otras peticiones del mismo cliente. Al período desde que se crea hasta que se destruye la instancia es a lo que se llama sesión. ( diferentes sesiones no pueden compartir información entre ellas)


Por defecto sólo procesará una petición a la vez, por lo que si hay una petición en curso y llega otra, la segunda tendrá que esperar a que termine la primera. ( o dar un time-out ).


Este funcionamiento se puede cambiar usando la propiedad ConcurrencyMode, pasando de ConcurrencyMode.Single a Multiple, permitiendo de esta manera que pueda haber múltiples hilos atendiendo peticiones.


En este caso de tener múltiples hilos usando la misma sesión será responsabilidad del desarrollador encargarse de que el código sea thread-safe.


[ServiceBehavior(InstanceContextMode = InstanceMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]


public class Service : IService


{


……


InstanceMode.PerCall


Crea una instancia del servicio cada vez que el cliente invoca una operación. La instancia se destruye cuando se completa la operación.


De cara a la escalabilidad este modo ofrece mejor rendimiento que el anterior, ya que libera recursos entre llamada y llamada. Por ejemplo, si suponemos 100 clientes usando PerSession, el servidor tendrá que tener 100 instancias. Si sólo uno está activo y los otros 999 están tomándose un café, el servidor seguirá teniendo 100 instancias aunque sólo una se esté usando. Si se estuviese usando PerCall, el servidor sólo tendría una instancia.


Lógicamente, la desventaja de usar PerCall es que si necesitamos guardar estado entre sesión y sesión la cosa se complica y toca buscar alternativas más costosas de implementar.


InstanceMode.Single


Crea una instancia la primera vez que el cliente invoca una operación del servidor y permanece viva para atender todas las peticiones del mismo cliente y lo que es más importante, también todas las peticiones de otros clientes que se conecten al mismo servicio. La instancia se destruye cuando la aplicación que hace de host se detiene.


La principal ventaja, a parte de un menor consumo de recursos, es que todos los usuarios pueden compartir de una forma muy sencilla información ya que usan la misma instancia. Esta también se puede considerar su principal problema o desventaja…


Si utilizas este modo es importante establece ConcurrencyMode.Multiple, porque sino todas las peticiones de todos los clientes se estarán haciendo una detrás de otras y podrá haber muchas peticiones que den time-out.


Adicionalmente a estas propiedades es importante no olvidarse de configurar los parámetros de service throttling que ya comentaba anteriormente Oskar Alvarez.

Lo primero lo primero..

Y lo primero es presentarme.


Me llamo Ibon Landa y gracias a la oportunidad que me ha dado Rodrigo Corral abriendome este blog intentaré aportar mi granito de arena sobre diversos temas relacionados con tecnologías de .NET, especialmente sobre WCF, ASP.NET Ajax o Team System, tecnologías y herramientas con las que trabajo actualmente.


Tampoco me olvidaré de la gestión de proyectos e intentaré ofrecer mi visión de la misma, a partir de la experiencia que tengo en el trabajo que desempeño en este momento.