lunes, 3 de octubre de 2011

Repetir encabezado de una tabla en Report viewer (ASP.NET y VB.NET)

Hola,

En un curso que esoty dictando de ASP.NET con VB, me hicieron una pregunta interesante, “¿Como repetir el encabezado de una tabla en cada una de las hojas del reporte?” 

Al agregar una tabla a nuestro reporte, se activa en la parte inferior de este una zona de agrupación de filas y columnas, en esta zona, en la parte superior derecha se encuentra una flecha con un menú contextual.

image 

En esa opción se selecciona “Modo avanzado” (“Avanced mode”), al hacerlo se habilitan unas opciones ocultas que hacen referencia al encabezado de la tabla, tanto en filas como en columnas:

image

 

Cuando se hace clic sobre el grupo (Static) de las filas la venta de propiedades se activa la pripiedad “RepeatOnNewPage”. Cambiamos la propiedad a “True” y listo.

 

image

El resultado:

Página 1:

image

Página 2 y siguientes:

image

jueves, 18 de agosto de 2011

Quien es el dueño de lo que yo desarrollo.

Como desarrolladores de software nos encontramos siempre con este caso: quien es el dueño de lo que hacemos?

Lo que siempre hay que tener en cuenta es bajo que norma se rigen las relaciones entre los individuos, estas normas están reglamentadas en leyes, códigos, decretos y una serie de cosas más que los abogados saben con más detalle.

En el desarrollo de software lo que se crea es una relación entre dos individuos (personas naturales o jurídicas) el desarrollador y el cliente, teniendo en cuenta este aspecto, esta relación se puede dar entre otras teniendo en cuenta los siguientes casos:

1. Caso 1: Al desarrollador lo contrataron como empleado por nómina con todas la prestaciones del caso o como freelance pagado por horas para desarrollar algo específico para la empresa por medio de una orden de prestación de servicos, para desarrollar algo con recursos de la empresa, en las instalaciones de la empresa. En este caso todas las líneas del código desarrollado, las librerías creadas, y el producto, serán propiedad del cliente. En este caso la relación está amparada bajo el código sustantivo del trabajo (contrato laboral) y el código de comercio (contrato de prestación de servicios) algo al respecto en este vínculo: http://www.gerencie.com/contrato-de-servicios.html.

En este caso el desarrollador ganó experiencia, reconocimiento.

2. Caso 2: Una empresa contrata a un desarrollador para que le haga un producto a la medida. El producto fue desarrollado por el desarrollador, en las instalaciones del desarrollador, con herramientas del desarrollador.

En este caso la relación cliente-desarrollador es regido por el código de comercio y por tanto se debe realizar un contrato entre las dos partes donde se especifique claramente quien es dueño de que, en este contrato debe de regir una cláusula de confidencialidad, para que el cliente proteja su negocio, que es lo importante para el cliente.

En este contrato también se debe especificar los derechos patrimoniales, es decir quién puede lucrarse de la comercialización de dicho producto. Sin embargo el derecho de autor o derechos morales son del desarrollador y no se pueden negociar ni ceder, al igual que pasa con las obras de arte.

En el contrato también se puede especificar quien es el dueño del código desarrollado, lo que yo hago, es que en mis contratos especifico que el producto es del cliente. Pero el código es de mi propiedad, es decir, el cliente puede coger su producto, modificarlo, ampliarlo, venderlo a su gusto, pero yo, puedo usar el código utilizado para crear dicho producto en otras aplicaciones, eso sí, sin infringir la cláusula de confidencialidad. Lo que quiere decir, que si yo hice durante el desarrollo del sistema para la empresa A, una librería que optimiza el acceso la base de datos, dicho código lo puedo utilizar en mis posteriores aplicaciones. Lo que no podría hacer, es venderle el producto que le hice parea la empresa A a la empresa B (si así se encuentra especificado en el contrato).

Hay una práctica que yo hago, y así lo específico en mis contratos, es que yo entrego el producto con el código fuente al cliente, sin embargo, aclaro que cualquier modificación que hagan al código anula la garantía. Y créanme que siempre el cliente me ha contratado de nuevo para que le haga yo mismo las mejoras al producto, y si eventualmente el cliente modifica el código y daña la aplicación, adivinen a quien llama y adivinen cuanto cobro yo por arreglar el daño…

3. Caso 3: Yo hice un producto y el cliente me quiere comprar dicho producto, en ese caso, el producto fue desarrollado por mí, en mis instalaciones y con mis recursos. En este caso el cliente adquiere el producto que yo le estoy ofreciendo, y también está regido por el código de comercio en una operación de compra-venta en la cual también hay que hacer un contrato y en este se especifica que la propiedad es mía y que, el cliente puede utilizar dicho producto para su beneficio. Como en el caso por ejemplo de un sistema de nómina, ahí no hay procesos del cliente a proteger ni confidencialidad sobre procedimientos ni nada, pues es una tarea común a muchos clientes, el producto se puede vender sin ninguna restricción de confidencialidad.

4. Caso 4: Ahora aprovechando las nuevas tecnologías, como Windows azure, surge una nueva posibilidad, el software como servicio, en este caso, el cliente compra el acceso al sistema por un tiempo especificado, por una cantidad de transacciones especificadas, etc, etc, etc, más o menos como un alquiler, en este caso también se debe realizar un contrato y es regido por el código de comercio, pero es más parecido a un contrato de arrendamiento, en el cual el cliente hace uso del producto bajo unas condiciones especificadas. Es contrato es lo que normalmente uno chequea como “Acepto” en algunos sitios sin ni siquiera leer lo que allí dice.

En conclusión hay que tener muy claro lo que se especifica en el contrato, pues en caso de un pleito jurídico es el primer documento que se tiene en cuenta para el desempate (es decir definir quién tiene la razón, si el cliente o el desarrollador), y por consiguiente sugiero que se valgan de un abogado para que les ayude a crear una buena minuta contractual que se encargará de regir la relación con sus clientes.

domingo, 13 de febrero de 2011

Mi primera experiencia con Windows Azure

Bueno, pues acabo de enterarme que me gané un XBOX 360 con Kinect  por participar en el primer concurso de Cloud XBOX realizado por Microsoft.

Antes que nada, agradezco a Microsoft Colombia por brindarme la oportunidad de participar en el concurso, lo que me ha permitido además de de ganarme el premio, indagar sobre una tecnología que estoy seguro me va a abrir nuevas posibilidades de negocios.

Bueno, el concurso consistía en realizar un prototipo de una aplicación para Windows Azure, publicarla (para esto utilicé una cuenta de prueba), realizar un video explicando el prototipo y participar de la carrera de Windows Azure en el programa MVA . Este fue el video con el cual participé:

 

Acerca de Celuturno

El sistema fue una idea pensada para mejorar el servicio que prestan los restaurantes, al tomar el celular del cliente al tomar el pedido para enviarle un mensaje de texto avisando que su pedido se encuentra listo.

Con esta aplicación se pretende eliminar la espera que tiene que hacer el cliente frente a un tablero o esperando ser llamado desde la zona de entrega de pedidos, o en el mejor de los casos cargar un dispositivo grande e incómodo que avisará al cliente cuando el pedido se encuentre listo.

Mi primera experiencia con Windows Azure

Este prototipo fue mi primer acercamiento al desarrollo para Windows Azure. Y en esta experiencia he notado que no no difiere mucho de lo que ya venia haciendo como desarrollador de aplicaciones ASP .NET, lo cual me facilitó la creación del prototipo.

Sin embargo para implementar la aplicación es necesario tener un conocimiento adicional sobre el almacenamiento de información, el manejo de sesiones y otras cosas mas que pude dominar gracias a:

1. Curso de capacitación realizado por la comunidad BogotaDotNet

2. El Windows Azure Plataform Training Kit

3. La carrera de Cloud Computing de MVA 

4. El blog de Walter Novoa, en el cual encontré detalles claves para que mi aplicación funcionara correctamente.

un punto adicional: La aplicación es perfecta para ser montada en Windows Azure, teniendo en cuenta que el procesamiento de esta es mayor a ciertas horas (hora de almuerzo) y en otras horas la aplicación puede estar detenida (horas de la noche), lo que disminuye el costo de la aplicación en un ambiente de alta disponibilidad.

Detalle de la aplicación

La aplicación es una aplicación web forms de ASP.NET, la cual la implemeté sobre un web role.

Consta de un formulario ASPX que tiene la interfaz de digitación de celulares y el envío de mensajes a los clientes y otro formulario que permite la iniciación a cero del contador de turnos.

Teniendo en cuenta que la aplicación no necesita un complejo modelo de base de datos el almacenamiento se hizo utilizando el Azure Storage, alimentando los datos mediante tables

El manejo de tables me permite almacenar los telefonos con los turnos y una manipulación simple de estos datos a través de linq.

Por ultimo, la aplicación tiene una clase que permite enviar el mensaje de texto a el celular del cliente, utilizando las api que los proveedores de telefonía celular tienen para tal fin.

martes, 4 de enero de 2011

OBTENIENDO EL LOG DE LINQ to SQL UTILIZANDO EL DATACONTEXT

 

Hola…

Me he encontrado en una situación en la que requiero registrar el log de todas las operaciones realizadas en una aplicación

Para dar solución a dicho requerimiento lo que hice fue registrar todas las operaciones SQL realizadas sobre la base de datos.

Teniendo en cuenta que la aplicación se encuentra en ASP.NET y la capa de datos la estoy trabajando con LINQ to SQL opté por obetener las transacciones realizadas a través del DataContext.

A continuación explico como realicé dicho proceso:

1. Requerimiento:

Registrar el log de todas las transacciones realizadas en la aplicación

2. Escenario:

Aplicación en ASP.NET utilizando LINQ to SQL como capa de datos.

A través del editor del LinqToSQL cree el diagrama y lo llamé bdRemisiones.dbml

image 

3. Solución:

Teniento en cuenta que a través del diseñador se crean automáticamente las clases que me permiten abstraer el modelo de la base de datos y entre ellas una llamada bdRemisionesDataContext que se encarga de conectar a la base de datos realizar las respectivas actualizaciones (para ver como se hace recomiendo: tutorial-de-linq-to-sql)

La clase creada por el diseñador es una clase parcial, lo que me permite adicionar métodos y propiedades desde otro archivo (OJO: es importante que sea en otro archivo, por que si se hace una modificación al modelo, los cambios se pueden perder)

Ahora, simplemente lo que hice fue crear en un archivo nuevo de clase, crear la clase parcial que me permite obtener el log de las transacciones SQL realizadas por el bdRemisionesDataContext asi:

Partial Public Class bdRemisionesDataContext
Inherits System.Data.Linq.DataContext

End Class



Luego definí un strinWriter para almacenar el contenido del log:

Dim writer As New System.IO.StringWriter()





 


despues, con el fin de que al crear un nuevo bdRemisionesdatacontext automaticamente se incie el registro del log creé el método onCreated() en el cual asigno el log del datacontext (ver  Datacontex.Log)


 

 Private Sub OnCreated()
MyBase.Log = writer
End Sub



Luego creo un método que me retorna un string con el log de las opreaciones realizadas por dicho datacontext:


 

    Public Function GetLogStr() As String
Dim lg As String
MyBase.Log = writer
lg = writer.ToString()
Return lg
End Function

el código completo se ve asi:

Partial Public Class bdRemisionesDataContext
Inherits System.Data.Linq.DataContext

Dim writer As New System.IO.StringWriter()

Private Sub OnCreated()
MyBase.Log = writer
End Sub

Public Function GetLogStr() As String
Dim lg As String
MyBase.Log = writer
lg = writer.ToString()
Return lg
End Function

End Class

Ahora para utilizar el log creado simplemente creo un objeto el bdRemisionesdatacontext, realizo las operaciones necesarias y por ultimo utilizo el log generado por ejemplo para incluirlo en una tabla de auditoria. Ej:

      'instanciar el objeto bd utilizando la clase bdRemisionesDataContext
Using bd As New bdRemisionesDataContext()
Dim fecha As Date = CDate(sender.text)

'Utilizar linq para obtener un objeto con los datos de mi base de datos
Dim r = From x In bd.Web_Remisiones
Select x
Where x.IdRemision = idremision

Dim remision As New Web_Remisione()
remision = r.First
'Modificar el valor de una propiedad de mi objeto remisiones

remision.FechaEntrega = fecha

'Al utilizar submitchanges el datacontext genera la sentencia update y actuliza el registro en la base de datos
bd.SubmitChanges()

'Utilizo mi claye de ayuda Helper para registrar el log de la transaccion
'Notese que con el obejeto bd puedo utilizar el método creado GetLogStr para
'obtener la cadena con el log de la transacción.

Using h As New Helper
h.InsertarAuditoria(bd.GetLogStr)
End Using

End Using



La cadena retornada por el método en este caso sería algo asi:

SELECT TOP (1) [t0].[IdRemision], [t0].[Consecutivo], [t0].[FechaRemision], [t0].[HoraRemision], [t0].[Id_Cliente], [t0].[Contacto], [t0].[RemitirA], [t0].[UltimaModificacion], [t0].[IdUsuario], [t0].[FechaCreacion], [t0].[Observaciones], [t0].[FechaEntrega]
FROM [dbo].[Web_Remisiones] AS [t0]
WHERE [t0].[IdRemision] = @p0
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [2]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 4.0.30319.1

UPDATE [dbo].[Web_Remisiones]
SET [FechaEntrega] = @p10
WHERE ([IdRemision] = @p0) AND ([Consecutivo] = @p1) AND ([FechaRemision] = @p2) AND ([HoraRemision] = @p3) AND ([Id_Cliente] = @p4) AND ([Contacto] = @p5) AND ([RemitirA] = @p6) AND ([UltimaModificacion] = @p7) AND ([IdUsuario] = @p8) AND ([FechaCreacion] = @p9) AND ([Observaciones] IS NULL) AND ([FechaEntrega] IS NULL)
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [2]
-- @p1: Input Int (Size = -1; Prec = 0; Scale = 0) [2]
-- @p2: Input SmallDateTime (Size = -1; Prec = 0; Scale = 0) [20/12/2010 12:00:00 a.m.]
-- @p3: Input VarChar (Size = 8000; Prec = 0; Scale = 0) [ ]
-- @p4: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [M27]
-- @p5: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [ANGELA RODRIGUEZ]
-- @p6: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [ANGELA RODRIGUEZ CRA 5 CON CLL 25]
-- @p7: Input SmallDateTime (Size = -1; Prec = 0; Scale = 0) [20/12/2010 12:00:00 a.m.]
-- @p8: Input Int (Size = -1; Prec = 0; Scale = 0) [1]
-- @p9: Input SmallDateTime (Size = -1; Prec = 0; Scale = 0) [20/12/2010 09:56:00 p.m.]
-- @p10: Input SmallDateTime (Size = -1; Prec = 0; Scale = 0) [31/12/2010 12:00:00 a.m.]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 4.0.30319.1


Espero les sirva de algo este post y si tienen comentarios y  sugerencias, bienvenidos sean.
Róbinson Moscoso
Bogotá - Colombia