Mostrando entradas con la etiqueta trabajo. Mostrar todas las entradas
Mostrando entradas con la etiqueta trabajo. Mostrar todas las entradas

martes, 2 de diciembre de 2014

Asp.Net MVC 5 actualizando modelos en la base de datos

Para mantener sincronizados los modelos que hemos creado con la base de datos, se requiere utilizar los siguientes comandos.

Primero se debe habilitar Migrations:

  Enable-Migrations -ContextTypeName EjemploModels.Models.PersonaDBContext

Y después, se debe seguir utilizando los siguientes comandos cada vez que queremos actualizar:

  Add-Migrations

Y por último, se debe actualizar:

  Update-Database



Para más detalles, dejo el siguiente link:

http://geeks.ms/blogs/rafahernandez/archive/2012/04/29/entity-framework-f-4-3-code-first-migrations.aspx

Asp.Net MVC 5: Cambiando la configuracion de conección a base de datos de Entity Framework

Por defecto, en un proyecto MVC 5 de Visual Studio 2013,  la base de datos que Entity Framework utilizada es LocalDb. Con este tip, podremos cambiar a una conección diferente de Base de Datos, por medio del archivo de configuración.

Solo debemos reemplazar la siguiente sección del archivo Web.config. (Configurado para LocalDB)

<entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>

Por este otro, que utiliza una conección diferente (por ejemplo Sql Server)

<entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="Data Source=...; Integrated Security=True; MultipleActiveResultSets=True" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>

En el parámetro "value" del atributo "parameter", se debe escribir la misma cadena de conexión que se escribiría en una conexión normal.

Por ejemplo:

  value="Data Source=NombreServidor;Initial Catalog=NombreBaseDatos;User ID=Usuario;Password=Contraseña"

lunes, 1 de abril de 2013

Credenciales y acceso en Asp.Net sobre Active Dictory


En mi último proyecto de desarrollo de mi trabajo, he podido utilizar las bondades de Active Dictory (desde ahora AD), para poder dar acceso a usuarios y grupo de usuarios específicos.  Esto es muy útil ya que si debemos  controlar qué persona  entrará a nuestra página Web, y si además nuestra empresa y sus redes están utilizando Servicios de Directorios LDAP como Active Dictory,  entonces esta herramienta de programación será lo ideal.

A continuación muestro cómo he aplicado esta funcionalidad sobre una aplicación Web Asp.net, hecha con C#. A este método se le domina: Autentificación de Formularios a través de Active Dictory, y me baso en el artículo de microsoft  http://support.microsoft.com/kb/316748/es eso si con algunas modificaciones.

En resumen, los contenidos de documento son:

1) Crear clase LdapAuthentication.cs.
2) Agregar código al archivo global.asax.
3) Agregar código al archivo Web.config.
4) Crear la página Logon.aspx.
5) Agregar código personalizado a Logon.aspx.cs
6)Habilitando el acceso a los diferentes formulario del Software.
7)  Configuraciones faltantes en mi desarrollo.


Autentificación de Formularios a través de Active Dictory

1.- Crear clase LdapAuthentication.cs

Lo primero es crear una clase, la cual se sugiere que el nombre sea 'LdapAuthentication.cs'. Esta es, por así decirlo, la clase principal, la cual contiene los métodos necesarios para poder acceder a AD. En resumen, se le entregan tres parámetros:  dominio, usuario y contraseña.  El método 'IsAuthenticated()' averigua si usuario y contraseña son correctos  y el método 'GetGroups()' obtiene el o los grupos al cual pertenece este usuario. El código es el siguiente:


using System;
using System.Text;
using System.Collections;
using System.DirectoryServices;

namespace FormsAuth
{
    public class LdapAuthentication
    {
        private String _path;
        private String _filterAttribute;
        private String _username;
        DirectoryEntry _entry;   //modi

        public LdapAuthentication(String path)
        {
            _path = path;
        }

        public bool IsAuthenticated(String domain, String username, String pwd)
        {
            string domainAndUsername = domain + @"\" + username;
            _username = username;
           // string domainAndUsername = "ADUNACH\\usuario1";
            DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
            _entry = entry;

            try
            { //Bind to the native AdsObject to force authentication.   
                Object obj = entry.NativeObject;

                DirectorySearcher search = new DirectorySearcher(entry);

                search.Filter = "(SAMAccountName=" + username + ")";
                search.PropertiesToLoad.Add("cn");
                SearchResult result = search.FindOne();

                if (null == result)
                {
                    return false;
                }

                //Update the new path to the user in the directory.
                _path = result.Path;
                _filterAttribute = (String)result.Properties["cn"][0];
            }
            catch (Exception ex)
            {
                throw new Exception("Error al autenticar usuario" + ex.Message);
            }

            return true;
        }

        public String GetGroups()
        {
            DirectorySearcher search = new DirectorySearcher(_entry);
            search.Filter = "(cn=" + _filterAttribute + ")";
            //search.Filter = "samAccountName=" + _username;
            search.PropertiesToLoad.Add("memberOf");
            StringBuilder groupNames = new StringBuilder();

            try
            {
                SearchResult result = search.FindOne();

                int propertyCount = result.Properties["memberOf"].Count;

                String dn;
                int equalsIndex, commaIndex;

                for (int propertyCounter = 0; propertyCounter < propertyCount; propertyCounter++)
                {
                    dn = (String)result.Properties["memberOf"][propertyCounter];

                    equalsIndex = dn.IndexOf("=", 1);
                    commaIndex = dn.IndexOf(",", 1);
                    if (-1 == equalsIndex)
                    {
                        return null;
                    }

                    groupNames.Append(dn.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1));
                    groupNames.Append("|");

                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error obtaining group names. " + ex.Message);
            }
            return groupNames.ToString();
        }
    }
}

2.- Agregar código al archivo global.asax

El archivo global.asax es un controlador de eventos. Interactúa con las Cookies, y junto con el archivo 'LdapAuthentication.cs' averigua la lista de grupos. El siguiente es el código, y además le he agregado un pequeño código el cual guardará en una cookie, los grupos que contiene el usuario, y el nombre del usuario será el nombre de la cookie. El siguiente método deberá reemplazar al que ya existe:

 void Application_AuthenticateRequest(Object sender, EventArgs e)
        {
            String cookieName = FormsAuthentication.FormsCookieName;
            HttpCookie authCookie = Context.Request.Cookies[cookieName];

            if (null == authCookie)
            {//There is no authentication cookie.
                return;
            }

            FormsAuthenticationTicket authTicket = null;
            try
            {
                authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            }
            catch (Exception ex)
            {
                //Write the exception to the Event Log.
                return;
            }

            if (null == authTicket)
            {//Cookie failed to decrypt.
                return;
            }

            //When the ticket was created, the UserData property was assigned a
            //pipe-delimited string of group names.
            String[] groups = authTicket.UserData.Split(new char[] { '|' });

            //Create an Identity.
            GenericIdentity id = new GenericIdentity(authTicket.Name, "LdapAuthentication");

            //This principal flows throughout the request.
            GenericPrincipal principal = new GenericPrincipal(id, groups);

            //----Modificacion Marlon-----
            //--Guardo datos: nombre usuario y grupos que tiene
            string nombreCookie = "caunach-" + id.Name;
            string valor = "";
            foreach (string a in groups)
            {
                valor = valor +a +"?";
            }

            Response.Cookies.Remove(nombreCookie);
            Response.Cookies[nombreCookie].Value = valor;
 
            //-------- Fin Modif Marlon --------------

            Context.User = principal;
           
        }

3.- Modificando el archivo Web.confg

El siguiente extracto de código debe colocarse después de , e indicará cual será la forma de autentificación, en nuestro caso por Formularios. También indica cual será la página que servirá para el ingreso de las credenciales y cual será la cookie que controla y contiene el acceso. Tanto el acceso y el control de duración de la sessión son guardadas en la cookie 'adAuthCookie'.


 
    
     
     
    
    
      
      
    

4.- Crear la página Logon.aspx

Esta contiene los TextBox necesarios para ingresar tanto usuario como contraseña. Además contiene el código necesario para interactuar con las clases y métodos ya creados, y ver si puede continuar y acceder a otras partes del programa. Si el ingreso de las credenciales son erroneos, esta pantalla (logon.aspx), no permitirá el acceso a otra página. Cito un texto de la documentación de Microsoft:

'La página Logon.aspx es una página que recopila la información de los métodos de usuario y la llamada en la clase LdapAuthentication . Después el código autentica al usuario y obtiene una lista de grupos, el código crea un objeto FormsAuthenticationTicket , cifra el vale, agrega el vale cifrado a una cookie, agrega la cookie a la colección HttpResponse.Cookies y, a continuación, redirige la solicitud a la dirección URL que se solicitó originalmente.'

El código es el siguiente, notar que es solo de Body hacia abajo lo que yo pongo:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Logon.aspx.cs" Inherits="CargaDocenteMantencion.Logon" %>


<%@ Import Namespace="FormsAuth" %>


  
 
    
      
  
     
     
Confirmación de contraseña
Usuario:
Constraseña:
<%-- asp:CheckBox ID=chkPersist Runat=server Text="Persist Cookie" /> --%>

5.- Agrego código personalizado al archivo Logon.aspx.cs

Debo escribir algunas lineas de código en este archivo, para obtener el valor de DOMINIO. Me explico, al comienzo explicamos que la clase principal LdapAuthentication.cs, y por tanto toda estas herramientas, trabajan con tres parametros ingresados: Usuario, contraseña y dominio. Entonces sabemos que tanto 'Usuario' como 'Contraseña' son elementos que ingresaran y constantemente y no necesariamente serán siempre los mismos, pero no pasa así con 'Dominio'. El dominio, prácticamente no cambiará, ya que generalmente habrá un solo dominio para una institución (ej iis.com, APPCEE, origin.com, etc). En nuestro caso  hay uno solo, y no lo escribo en código, sino lo guardo cómo un valor en Base de Datos. Agrego entonces el código que me permite extraer este Dominio.

 ---------------

protected void Page_Load(object sender, EventArgs e)
        {
            dominio = obtenerConfiguracion("DOM");
            //traigo el usuario de autoservicio
            if (IsPostBack != true)
            {
                txtUsername.Text = Request.QueryString["usr"];
            }
        }
Notar que obtenerConfiguracion("DOM") es mi método que permite extraer el dominio de una tabla en base de datos. Por ejemplo, un dominio puede ser 'inacap.com', 'itt.org' etc.


6.- Habilitando el acceso a los diferentes formulario del software


Este código está basado en la documentación de Microsoft, dirección mencionada arriba, pero los que pongo en este documento ya están alterados y han sufridos algunas modificaciones, para el buen funcionamiento de mi aplicación.

Ahora que tenemos todo esto funcionando quiero mostrar cómo se va a dar  acceso o denegar acceso (programáticamente) el ingreso a los formularios, una vez que tenemos el resultado de la autentificación.
Este resultado se almacena en una variable global llamada 'Context'. En mi aplicación yo obtengo el nombre de usuario que se ha logueado y autorizado correctamente a través de 'Context.User.identity.Name'. Y también debo obtener el  o los grupos de AD a los cuales este usuario pertenece. Pero, aunque la variable Context tiene esta información, esta es privada, por lo que no puedo extraerla. Así que la recupero de una Cookie que hice en el archivo Global.asax.cs (visto más arriba). Entonces, el código para obtener el usuario y los grupos de este usuario, y además darle acceso al usuario ya autenticado es el siguiente, y puede ir en cualquier Forms que exista, dentro del método Page_load()


   //Primero de todo veo si el usuario está logeado
            //y ademas pertenece al grupo de "FACULTAD"
            int encontrado = 0;
            string usuario = Context.User.Identity.Name;
            string grupos = "";
            string aa = Context.User.Identity.AuthenticationType[0].ToString();
            if (Request.Cookies["caunach-" + usuario] != null)
            {
                grupos = Server.HtmlEncode(Request.Cookies["caunach-" + usuario].Value);
                string[] grup = grupos.Split('?');
                foreach (string g in grup)
                {
                    if (g.Trim().Equals("facultad"))
                    {
                        encontrado = 1;
                    }
                }
            }
            if (encontrado == 0)
            {
                Response.Redirect("../AccesoNoAutorizado.aspx");
            }
   
En resumen, obtengo usuario de 'Context', con esto entonces (ya que mi cookie de grupos tiene el nombre del usuario), averiguo los grupos de la cookie. Pregunto si este usuario pertenece a un grupo llamado 'facultad', y si es así, puedo continuar cargando este formulario normalmente, si no (no pertenece a grupo 'facultad'), lo redirecciono inmediatamente a una página de donde se le menciona que no tiene autorización para ver este contenido.


7.- Configuraciónes faltantes en mi desarrollo


Me he saltado algunas configuraciones, debido a que no ha sido necesario o ya estaban pre-establecidos en mis herramientas de desarrollo. Por ejemplo la opción de configuración del archivo Web.config:   (del apartado 'Modificar el archivo Web.config' del tutorial de Microsoft) no la he habilitado. Así también el apartado 'Configurar IIS para la autenticación anónima', ya estaba configurada en mi servidor IIS.

jueves, 19 de abril de 2012

Creación de logos


Muestro un par de logos que he realizado en mis proyectos laborales. El primero está hecho con Photoshop, y lo he diseñado completamente desde cero. El segundo está creado 3ds Max, y renderizado con Brazil Render. El diseño de este último está basado en el logo oficial de mi querida Universidad Adventista de Chile.

viernes, 9 de diciembre de 2011

Pinturas con mi iPad



Estas dos pinturas la realicé con mi iPad, especificamente con el software Procreate. La imagen del Moai corresponde al ícono oficial del programa que realicé para la Universidad Adventista de Chile (visto en mi blog también). Y el planeta, lo hize con el anhelo de aplicar algunas técnicas de pintura digital para algunos efectos bien bonitos, como por ejemplo la translucencia de un oceano esférico iluminado directamente por una luz (con colores de aguas tropicales), o la sombras de las nubes pegando sobre la superficie del planeta, y el efecto glow que se persibe en el horizonte del planeta debido al brillo reflejado del sol. Con esto aprendí alcunas cosas muy interesantes del programa "Procreate", y me gustaría pintar algunas otras cosas, eso sí, si el tiempo me alcanza.

lunes, 29 de agosto de 2011

Mi software para capturas de fotos y administración de tarjeta TUI



Versión 0.8 UNACH CAPTURE

Bueno, pongo acá nuevas screenshots de la aplicación UNACH CAPTURE, que servirá para la toma de fotografía rápida de la Universidad Adventista de Chile. Han pasado 7 meses desde que presenté las primeras imágenes de esta aplicación (11 de Enero, 2011) y se han modificado y eliminados ciertas cosas, cómo la mantención de fotos via Web, pero a la vez he agregado otro módulo que permitirá la mantención a través de una nueva ventana (de escritorio), la cual administrará y almacenará tanto las fotos de los alumnos como también, las diferentes salidas y compilaciónes de estas para la solicitudes de la Credencial Universitaria TUI Unach.
Muestro a continuación la nuevas características de UNACH CAPTURE version 0.8.

Captura de una Persona

La ventana encargada de la captura, trabaja directamente con una Web Cam HD Microsoft, la cual la detecta inmediatamente iniciada la aplicación. Esta es la pantalla.


La captura realizada es automáticamente formateada a una proporción 4:3, para después ser asociada a un rut (automaticamente validado) y un número identificador de la institución para este alumno, que en el caso de la UNACH es el número de alumno (código matrícula).

Ahora, si ya se tiene el archivo de la imagen (jpg), entonces se puede cargar la imagen a travez del boton verde "Cargar Foto", el cual permitirá elegir y buscar una foto del disco. Esta foto ya debe estar en un formato 4:3 y de un tamaño aprox 255 x 340.

Hay muchas opciones más en esta pantalla, como por ejemplo: hacer un flip a la imagen, desactivar la opción de validación de rut, encontrar el rut de un alumno antiguo por medio de su numero de matrícula, o incluso poder sacar dos fotos por alumnos (de frente y de lado).

Confirmación de la Foto

Cuando ya se ha confirmado que esta foto es la que queremos, pasamos a una nueva ventana llamada "Ventana de Confirmación Final", la cual permitirá asociar a la foto el tipo de persona: "Alumno Pre-grado", "Alumno Post-grado", "Docente" o "Miembro de Personal". También si al momento de esta captura, el alumno "Tiene el Carnet" "No lo tiene" o bien "Carnet extraviado". (Esto datos son necesarios para la creación de la tarjeta universitaria TUI). Y por último, se elige en que momento se ha capturado esta foto: "En la matrícula principal", o en alguna de los otras matrículas (1ª Covocatoria, 2ª, 3ª, matricula intermedia, etc.).


También hay otras opciones, como el de mostrar las fotos en tamaño más grande, para que la persona pueda observarla bién. Y además de la opción para ingresar datos personales desglosados, por si la persona es un "Miembro del Personal". Entre otras cosas más.

Una vez confirmado todo, se presiona "Guardar", la cual enviará la Foto (o las dos fotos) a la base de datos MySql que está en el Servidor, junto con todos los datos ingresados por la persona que capturó la foto.

Nuevo Módulo para Administrar Fotos y Lotes de Fotos.

Este es el nuevo módulo que estará a cargo de todo lo que es la administración de Fotos y la salida de fotos, según las necesidades de la institución.


Durante la creación de este Software, me topé con el problema de que aunque se tuviera una ventana para ver y administrar las fotos, la UNACH (y en realidad, cualquier institución) se podría necesitar que, en algún momento dado, haya que compartir o entregar fotos a ciertos departamentos para algún proceso o proyecto. Me explico mejor, por ejemplo la UNACH realiza cada cierto tiempo una revista llamada "Anuario", la cual compila todas las fotos de los alumnos de un año, por lo que es necesario enviárles todas las fotos que ellos necesiten entre un rango de fechas (semestres, años, etc.). El mismo caso de las tarjetas TUI, se necesita enviar cada cierto tiempo a Santiago los alumnos que necesitan nuevas credenciales.

Entonces se me ocurrio la idea de que el Software trabajara no solo administrando FOTOS, sino también administrado LOTES. Este módulo permite entonces crear lotes y a cada lotes agregarles las fotos que uno quiera. Por último estos lotes son guardados y procesados según se requiera. En estos momentos la version 0.8, solo posee la opción para generar un Lote para Pedidos de Credenciales TUI. Espero en la próxima versión, agregarles opción para "Generar Lote para Anuario".

jueves, 2 de octubre de 2008

Por fin termino el programa de inventario

Listo, por fin, he terminado el programita para el inventario de la biblioteca. Casi dos meses y unas 4000 lineas de código java han hecho que mis ojos adquieran la forma de la pantalla de mi notebook. Pero por otro lado estoy felíz porque he aprendido muchas cosas nuevas relacionada con este lenguaje tan particular. He conocido el grandioso y elegante swing worked, (el hilo para los swing), los diccionarios hashTables, la manipulación de expresiones regulares mediante las clases Matcher y Pattern, la clase RandomAccessFile para accesar directamento los archivos de textos, los controles de barras para mostrar el avance de los procesos, etc., etc., etc.

Esta es la ventana principal de la aplicación:


Para variar, ha sucedido lo que me pasa la mayoría de las veces que hago un proyecto más o menos grande; suelen cambiar algunas cosas y algunos puntos que fijo al momento de empezar la elaboración del mismo. Las funciones y procesos que descarté fueron:
  1. Los resultados serán guardados en archivos de textos independientes y no en un solo documento excel como tenía planeado.
  2. Eliminé, algunos botones y checkbox, que aunque eran importantes no era obligatorio ni necesarios para que la aplicación realice el proceso principal. Los descarto por motivos de tiempo.
  3. La aplicación es ahora un contenedor de varias aplicaciones. Me explico, bajo este mismo programa se engloban varios programas o subprogramas y no solo uno. Hasta este momento hay dos subprogramas, el primero es el "Inventario", (proceso que tenía pensado desde un principio) , y el segundo es "Comparación de secciones". Se podrán ir agregando nuevas aplicaciones según las necesidades de la biblioteca.