Blog alskare

.Net y lo que surja

Archivos de la categoría ‘Helpers’

C#. Generador de Passwords aleatorios

Publicado por alskare en 13/10/2009

Estoy más que seguro que cualquiera de nosotros hemos sido usuarios en cualquier ocasión de algún tipo de herramienta similar a la que intento crear en estos momentos. De hecho, con una búsqueda bastante genérica en Google surgen multitud de rutinas en cualquier lenguaje. No obstante, como soy de aquellas personas que prefiere crear sus propias rutinas antes de hacer un “Copia y Pega” de lo que han hecho otros, me dispongo a la creación de una utilidad que me permita obtener contraseñas de una manera aleatoria.

¿Qué necesito?

En principio, sólo necesito una rutina que me permita generar un password de 8 caracteres, y que incluya, al menos, un número, un carácter no alfanumérico y algún carácter en mayúscula. Podemos apreciar enseguida que, aunque la necesidad inminente es bastante sencilla, lo mejor es poder parametrizar estos elementos a los que podemos llamar “Caracteres especiales”:

  • Números
  • Mayúsculas
  • Símbolos

Debo reconocer que, a la hora de parametrizar valores, soy un amante de los porcentajes y, en este principio, baso muchas de las rutinas creadas. Es decir, si genero una rutina que me permita crear una contraseña de 10 caracteres, prefiero decir que tenga un 20% de números, un 20% de mayúsculas y otro 20% de símbolos para que la contraseña tenga: 2 números + 2 letras mayúsculas + 2 símbolos + 4 caracteres normales en minúscula. De esta manera, si tengo que ampliar la longitud de la contraseña a 20 caracteres, automáticamente cambiará el número de caracteres especiales, manteniendo la proporción.

Otro de los puntos a tener en cuenta es que los caracteres que pueden emplearse no siempre serán válidos en todos los entornos, por tanto, aunque no me he preocupado de parametrizar este punto, sí que he tenido la precaución de “separarlo” por si alguien tiene que añadir/eliminar algún carácter no compatible, por ejemplo, con un determinado servidor de correo.

string caracteres = "abcdefghijklmnopqrstuvwxyz";
string numeros = "0123456789";
string simbolos = "%$#@+-=&";

¿Cómo enfoco el resultado?

En mi caso, con contraseñas de 8 caracteres suelo pasar. De hecho, debo reconocer que la necesidad de la creación de una rutina que cree passwords automáticamente viene dada por una aplicación Web que tengo que crear en la que, cuando un usuario pierde una contraseña, se le enviará por e-correo y, la primera vez que entre, tendrá que cambiarla, así que prima más la “estética” de la contraseña que la seguridad. Lo que pasa es que, a la gente le gusta más ver símbolos raros que cualquier nombre.

Pues eso, que la idea inicial es la de crear un constructor estándar con 8 caracteres, de los cuales tendrá un 20% de caracteres especiales. Otro constructor que permita crear una contraseña con una longitud variable y otro que permita definir todo:

public GeneradorPassword()
{ }

public GeneradorPassword(int longitudCaracteres)
{ }

public GeneradorPassword(int longitudCaracteres, 
                         int porcentajeMayusculas, 
                         int porcentajeSimbolos, 
                         int porcentajeNumeros)
{ }

En cuanto al sistema de crear la rutina, no me complico tampoco la vida:

  1. Creo una cadena con la longitud de la contraseña todo en minúscula
  2. Obtengo el número de caracteres especiales a añadir
  3. Obtengo una posición aleatoria para colocar los caracteres especiales
  4. Reemplazo los caracteres especiales en las posiciones obtenidas.

El resultado

Dejo la rutina tal cuál me ha quedado:

using System;
using System.Collections.Generic;
using System.Text;

namespace jnSoftware.Utiles
{
    /// <summary>
    /// Clase que permite la generación de una contraseña. 
    /// La contraseña contiene un número de caracteres fijos y permite especificar el porcentaje
    /// de caracteres en mayúsculas y símbolos que se quieren obtener
    /// </summary>
    public class GeneradorPassword
    {


        /// <summary>
        /// Enumeración que permite conocer el tipo de juego de carácteres a emplear
        /// para cada carácter
        /// </summary>
        private enum TipoCaracterEnum { Minuscula, Mayuscula, Simbolo, Numero }

        #region Campos

        private int porcentajeMayusculas;
        private int porcentajeSimbolos;
        private int porcentajeNumeros;
        Random semilla;

        // Caracteres que pueden emplearse en la contraseña
        string caracteres = "abcdefghijklmnopqrstuvwxyz";
        string numeros = "0123456789";
        string simbolos = "%$#@+-=&";

        // Cadena que contiene el password generado
        private StringBuilder password;

        #endregion



        #region Propiedades

        /// <summary>
        /// Obtiene o establece la longitud en carácteres de la contraseña a obtener
        /// </summary>
        public int LongitudPassword { get; set; }

        /// <summary>
        /// Obtiene o establece el porcentaje de carácteres en mayúsculas que 
        /// contendrá la contraseña
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">Se produce al intentar introducir
        /// un valor que no coincida con un porcentaje</exception>
        public int PorcentajeMayusculas
        {
            get { return porcentajeMayusculas; }
            set
            {
                if (value < 0 || value > 100)
                    throw new ArgumentOutOfRangeException("El porcentaje es un número entre 0 y 100");
                porcentajeMayusculas = value;
            }
        }


        /// <summary>
        /// Obtiene o establece el porcentaje de símbolos que contendrá la contraseña
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">Se produce al intentar introducir
        /// un valor que no coincida con un porcentaje</exception>
        public int PorcentajeSimbolos
        {
            get { return porcentajeSimbolos; }
            set
            {
                if (value < 0 || value > 100)
                    throw new ArgumentOutOfRangeException("El porcentaje es un número entre 0 y 100");
                porcentajeSimbolos = value;
            }
        }

        /// <summary>
        /// Obtiene o establece el número de caracteres numéricos que contendrá la contraseña
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">Se produce al intentar introducir
        /// un valor que no coincida con un porcentaje</exception>
        public int PorcentajeNumeros
        {
            get { return porcentajeNumeros; }
            set
            {
                if (value < 0 || value > 100)
                    throw new ArgumentOutOfRangeException("El porcentaje es un número entre 0 y 100");
                porcentajeNumeros = value;
            }
        }

        #endregion


        #region Constructores
        /// <summary>
        /// Constructor. La contraseña tendrá 8 caracteres, incluyendo una letra mayúscula, 
        /// un número y un símbolo
        /// </summary>
        public GeneradorPassword()
            : this(8)
        { }


        /// <summary>
        /// Constructor. La contraseña tendrá un 20% de caracteres en mayúsculas y otro tanto de 
        /// símbolos
        /// </summary>
        /// <param name="longitudCaracteres">Longitud en carácteres de la contraseña a obtener</param>
        /// <exception cref="ArgumentOutOfRangeException">Se produce al intentar introducir
        /// un porcentaje de caracteres especiales mayor de 100</exception>
        public GeneradorPassword(int longitudCaracteres)
            : this(longitudCaracteres, 20, 20, 20)
        { }


        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="longitudCaracteres">Longitud en carácteres de la contraseña a obtener</param>
        /// <param name="porcentajeMayusculas">Porcentaje a aplicar de caracteres en mayúscula</param>
        /// <param name="porcentajeSimbolos">Porcenta a aplicar de símbolos</param>
        /// <param name="porcentajeNumeros">Porcentaje de caracteres numéricos</param>
        /// <exception cref="ArgumentOutOfRangeException">Se produce al intentar introducir
        /// un porcentaje de caracteres especiales mayor de 100</exception>
        public GeneradorPassword(int longitudCaracteres, int porcentajeMayusculas, int porcentajeSimbolos, int porcentajeNumeros)
        {
            LongitudPassword = longitudCaracteres;
            PorcentajeMayusculas = porcentajeMayusculas;
            PorcentajeSimbolos = porcentajeSimbolos;
            PorcentajeNumeros = porcentajeNumeros;

            if (PorcentajeMayusculas + porcentajeSimbolos + PorcentajeNumeros > 100)
                throw new ArgumentOutOfRangeException(
                "La suma de los porcentajes de caracteres especiales no puede superar el " +
                "100%, es decir, no puede ser superior a la longitud de la contraseña");
            semilla = new Random(DateTime.Now.Millisecond);
        }

        #endregion


        #region Métodos públicos

        /// <summary>
        /// Obtiene el password
        /// </summary>
        /// <returns></returns>
        public string GetNewPassword()
        {
            GeneraPassword();
            return password.ToString();
        }


        /// <summary>
        /// Permite establecer el número de caracteres especiales que se quieren obtener
        /// </summary>
        /// <param name="numeroCaracteresMayuscula">Número de caracteres en mayúscula</param>
        /// <param name="numeroCaracteresNumericos">Número de caracteres numéricos</param>
        /// <param name="numeroCaracteresSimbolos">Número de caracteres de símbolos</param>
        public void SetCaracteresEspeciales(
            int numeroCaracteresMayuscula
            , int numeroCaracteresNumericos
            , int numeroCaracteresSimbolos)
        {
            // Comprobación de errores
            if (numeroCaracteresMayuscula
                    + numeroCaracteresNumericos
                    + numeroCaracteresSimbolos > LongitudPassword)
                throw new ArgumentOutOfRangeException(
                    "El número de caracteres especiales no puede superar la longitud del password");

            PorcentajeMayusculas = numeroCaracteresMayuscula * 100 / LongitudPassword;
            PorcentajeNumeros = numeroCaracteresNumericos * 100 / LongitudPassword;
            PorcentajeSimbolos = numeroCaracteresSimbolos * 100 / LongitudPassword;
        }



        /// <summary>
        /// Constructor. La contraseña tendrá 8 caracteres, incluyendo una letra mayúscula, 
        /// un número y un símbolo
        /// </summary>
        public static string GetPassword()
        {
            // Se crea un método estático para facilitar el uso
            GeneradorPassword gp = new GeneradorPassword();
            return gp.GetNewPassword();
        }


        #endregion


        #region Métodos de cálculo

        /// <summary>
        /// Método que genera el password. Primero crea una cadena de caracteres 
        /// en minúscula y va sustituyendo los caracteres especiales
        /// </summary>
        private void GeneraPassword()
        {
            // Se genera una cadena de caracteres en minúscula con la longitud del 
            // password seleccionado
            password = new StringBuilder(LongitudPassword);
            for (int i = 0; i < LongitudPassword; i++)
            {
                password.Append(GetCaracterAleatorio(TipoCaracterEnum.Minuscula));
            }

            // Se obtiene el número de caracteres especiales (Mayúsculas y caracteres) 
            int numMayusculas = (int)(LongitudPassword * (PorcentajeMayusculas / 100d));
            int numSimbolos = (int)(LongitudPassword * (PorcentajeSimbolos / 100d));
            int numNumeros = (int)(LongitudPassword * (PorcentajeNumeros / 100d));

            // Se obtienen las posiciones en las que irán los caracteres especiales
            int[] caracteresEspeciales =
                    GetPosicionesCaracteresEspeciales(numMayusculas + numSimbolos + numNumeros);
            int posicionInicial = 0;
            int posicionFinal = 0;

            // Se reemplazan las mayúsculas
            posicionFinal += numMayusculas;
            ReemplazaCaracteresEspeciales(caracteresEspeciales,
                 posicionInicial, posicionFinal, TipoCaracterEnum.Mayuscula);

            // Se reemplazan los símbolos
            posicionInicial = posicionFinal;
            posicionFinal += numSimbolos;
            ReemplazaCaracteresEspeciales(caracteresEspeciales,
                 posicionInicial, posicionFinal, TipoCaracterEnum.Simbolo);

            // Se reemplazan los Números
            posicionInicial = posicionFinal;
            posicionFinal += numNumeros;
            ReemplazaCaracteresEspeciales(caracteresEspeciales,
                 posicionInicial, posicionFinal, TipoCaracterEnum.Numero);
        }



        /// <summary>
        /// Reemplaza un caracter especial en la cadena Password
        /// </summary>
        private void ReemplazaCaracteresEspeciales(
                                        int[] posiciones
                                        , int posicionInicial
                                        , int posicionFinal
                                        , TipoCaracterEnum tipoCaracter)
        {
            for (int i = posicionInicial; i < posicionFinal; i++)
            {
                password[posiciones[i]] = GetCaracterAleatorio(tipoCaracter);
            }
        }



        /// <summary>
        /// Obtiene un array con las posiciones en las que deberán colocarse los caracteres
        /// especiales (Mayúsculas o Símbolos). Es importante que no se repitan los números
        /// de posición para poder mantener el porcentaje de dichos carácteres
        /// </summary>
        /// <param name="numeroPosiciones">Valor que representa el número de posiciones
        /// que deberán crearse sin repetir</param>
        private int[] GetPosicionesCaracteresEspeciales(int numeroPosiciones)
        {
            List<int> lista = new List<int>();
            while (lista.Count < numeroPosiciones)
            {
                int posicion = semilla.Next(0, LongitudPassword);
                if (!lista.Contains(posicion))
                {
                    lista.Add(posicion);
                }
            }
            return lista.ToArray();
        }


        /// <summary>
        /// Obtiene un carácter aleatorio en base a la "matriz" del tipo de caracteres
        /// </summary>
        private char GetCaracterAleatorio(TipoCaracterEnum tipoCaracter)
        {
            string juegoCaracteres;
            switch (tipoCaracter)
            {
                case TipoCaracterEnum.Mayuscula:
                    juegoCaracteres = caracteres.ToUpper();
                    break;
                case TipoCaracterEnum.Minuscula:
                    juegoCaracteres = caracteres.ToLower();
                    break;
                case TipoCaracterEnum.Numero:
                    juegoCaracteres = numeros;
                    break;
                default:
                    juegoCaracteres = simbolos;
                    break;
            }

            // índice máximo de la matriz char de caracteres
            int longitudJuegoCaracteres = juegoCaracteres.Length;

            // Obtención de un número aletorio para obtener la posición del carácter
            int numeroAleatorio = semilla.Next(0, longitudJuegoCaracteres);

            // Se devuelve una posición obtenida aleatoriamente
            return juegoCaracteres[numeroAleatorio];
        }

        #endregion

    }
}

 

La rutina puede probarse gracias a los amigos de velasco.biz: Probar rutina

Publicado en C#, Helpers, NetFramework | 3 Comentarios »

Validar Número de IVA VIES

Publicado por alskare en 07/09/2009

El otro día, hablando con la contable de la empresa, me comentó la posibilidad de añadir en las aplicaciones la validación de unos “NIF” un poco especiales. Digo un poco especiales porque en principio no se trata de un número de identificación sino más bien es un registro de aquellas empresas “legalizadas” para poder trabajar con IVAs a nivel intracomunitario. Digo legalizada entre comillas puesto que desconozco totalmente si el medio para entrar en esa base de datos se realiza automáticamente al trabajar con empresas intracomunitarias o hace falta algún tipo de registro especial.

Bueno, el caso es que mala validación podemos crear si el origen es una base de datos, así que no me queda más remedio que empezar a buscar y encuentro lo que andaba buscando en lo que creo que es la AEAT Europea: http://ec.europa.eu/taxation_customs/vies/lang.do?fromWhichPage=vieshome&selectedLanguage=ES.

Dentro de los servicios informáticos con los que he trabajado, quizás éste sea uno de los más originales. De hecho, no existe una base de datos centralizada. Se trata de bases de datos con un ámbito del país local que va “replicando” con el resto de países (igual me he pasado al escribir “replicando”). Por otro lado, resulta que no todos los países atienden las 24 horas del día (igual los ordenadores se van a tomar un café): http://ec.europa.eu/taxation_customs/vies/viesspec.do

Al fin y al cabo, somos programadores y nuestros profes siempre nos han enseñado que debemos desglosar un problema gordo en problemas más pequeños para poder afrontarlos con mayor destreza, así que eso voy a hacer en estos momentos. Imagino que al final pasará como ha ocurrido con otra entrada en el blog (Validar NIF, NIE, CIF ), que empezó con una pequeña validación y se ha ido ampliando y mejorando con el tiempo. Así, el objetivo inicial será el de comprobar si el NIF introducido es correcto o no, siempre según el servicio de Fiscalidad y Unión Aduanera.

La primera me la doy en la frente. Resulta que para solicitar la validez de un Número de IVA, necesitamos el código del país y… ¿cómo no?, no encuentro ningún servicio que devuelva los países aceptados, así que hay que hacer una lectura del código HTML de la página para poder tenerlos todos. Para poder trabajar con los países y poder ponerlos como origen de datos de los controles se me ocurre hacer lo más sencillo, una clase List<T>.

Paises

using System;
using System.Collections.Generic;

namespace ValidacionVies
{
    class Pais : IComparable 
    {
        public string CodigoPais { get; set; }
        public string NombrePais { get; set; }

        public Pais(string codigoPais, string pais)
        {
            this.CodigoPais = codigoPais;
            this.NombrePais  = pais;
        }


        // Se implementa la interfaz IComparable para poder ordenar por el país 
        public int CompareTo(object obj)
        {
            return this.NombrePais.CompareTo(((Pais)obj).NombrePais);
        }
    }


    class Paises : List<Pais>
    {
        public Paises()
        {
            this.Add(new Pais("AT", "Austria"));
            this.Add(new Pais("BE", "Bélgica"));
            this.Add(new Pais("BG", "Bulgaria"));
            this.Add(new Pais("CY", "Chipre"));
            this.Add(new Pais("CZ", "Chequia"));
            this.Add(new Pais("DE", "Alemania"));
            this.Add(new Pais("DK", "Dinamarca"));
            this.Add(new Pais("EE", "Estonia"));
            this.Add(new Pais("EL", "Grecia"));
            this.Add(new Pais("ES", "España"));
            this.Add(new Pais("FI", "Finlandia"));
            this.Add(new Pais("FR", "Francia"));
            this.Add(new Pais("GB", "Reino Unido"));
            this.Add(new Pais("HU", "Hungría"));
            this.Add(new Pais("IE", "Irlanda"));
            this.Add(new Pais("IT", "Italia"));
            this.Add(new Pais("LT", "Lituania"));
            this.Add(new Pais("LU", "Luxemburgo"));
            this.Add(new Pais("LV", "Letonia"));
            this.Add(new Pais("MT", "Malta"));
            this.Add(new Pais("NL", "Países Bajos"));
            this.Add(new Pais("PL", "Polonia"));
            this.Add(new Pais("PT", "Portugal"));
            this.Add(new Pais("RO", "Rumania"));
            this.Add(new Pais("SE", "Suecia"));
            this.Add(new Pais("SI", "Eslovenia"));
            this.Add(new Pais("SK", "Eslovaquia"));

            this.Sort();
        }
    }

}

 

El problema lo encontraré el día que haya que hacer alguna modificación, así que tomo nota de la mejora que podría hacerse creando un XML o un simple TXT para poder almacenar los países.

Una vez tenemos los países, conociendo los resultados que nos devuelve el WebService, es cuestión de empezar a preparar un entorno de interacción con el usuario:

- <element name="checkVatResponse">
- <complexType>
- <sequence>
  <element name="countryCode" type="xsd:string" /> 
  <element name="vatNumber" type="xsd:string" /> 
  <element name="requestDate" type="xsd:date" /> 
  <element name="valid" type="xsd:boolean" /> 
  <element name="name" type="xsd:string" /> 
  <element name="address" type="xsd:string" /> 
  </sequence>
  </complexType>
  </element>

Como que me hace gracia jugar un poco con las llamadas asíncronas al Web Service, opto por crear una aplicación WinForms que me permita realizar las primeras pruebas, así, me sale algo así como lo siguiente (ya dice mi jefe que lo mío no es el diseño):

image

 

De hecho, en el formulario no hay nada raro, un combo en el que se cargan los países (cboPaises), un textBox en el que deberá teclearse el número a validar (txtVatNumber) y los textBox de resultado (rstXXXX).

Al lío:

Código del formulario

using System;
using System.Windows.Forms;
using ValidacionVies.eu.europa.ec;


namespace ValidacionVies
{
    public partial class Form1 : Form
    {
        checkVatService cvs;

        public Form1()
        {
            InitializeComponent();

            // Asignación de eventos
            this.Load += new EventHandler(Form1_Load);
            this.cmdValida.Click += new EventHandler(cmdValida_Click);
        }

        void Form1_Load(object sender, EventArgs e)
        {
            lblProgreso.Text = string.Empty;

            // Carga de paises y asignación al combo
            Paises paises = new Paises();
            cboPaises.DataSource = paises;
            cboPaises.DisplayMember = "NombrePais";
            cboPaises.ValueMember = "CodigoPais";
            cboPaises.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
            cboPaises.AutoCompleteSource = AutoCompleteSource.ListItems;

            // Asignación del evento IndexChanged para el combo.
            cboPaises.SelectedIndexChanged += new EventHandler(cboPaises_SelectedIndexChanged);
            txtCountryCode.Text = cboPaises.SelectedValue.ToString();
        }


        void cboPaises_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox cbo = (ComboBox)sender;
            txtCountryCode.Text = cbo.SelectedValue.ToString();
        }


        void cmdValida_Click(object sender, EventArgs e)
        {
            lblProgreso.Text = "Consultando";

            // Llamada asíncrona al WebService
            cvs = new checkVatService();
            cvs.checkVatCompleted += new checkVatCompletedEventHandler(cvs_checkVatCompleted);
            cvs.checkVatAsync(txtCountryCode.Text, txtVatNumber.Text);
        }


        void cvs_checkVatCompleted(object sender, checkVatCompletedEventArgs e)
        {
            // Respuesta de la llamada asíncrona al WebService
            try
            {
                if (!e.Cancelled)
                {
                    lblProgreso.Text = string.Empty;
                    rstAddress.Text = e.address;
                    rstCountryCode.Text = e.countryCode;
                    rstName.Text = e.name;
                    rstResult.Text = e.Result.ToShortDateString();
                    rstCorrecto.Text = e.valid ? "Sí" : "No";
                }
                else
                {
                    lblProgreso.Text = string.Empty;
                    rstAddress.Text = string.Empty;
                    rstCountryCode.Text = string.Empty;
                    rstName.Text = string.Empty;
                    rstResult.Text = string.Empty;
                    rstCorrecto.Text = string.Empty;
                }
            }
            catch (System.Reflection.TargetInvocationException ex)
            {
                lblProgreso.Text = ex.Message;
            }
            catch (Exception ex)
            {
                lblProgreso.Text = "Se ha producido un error " + ex.GetType().ToString();

            }
        }
    }
}

Ya está. ¡Qué bonitas se ven las cosas cuando están acabadas!

Por cierto, se si alguien tiene interés, puede descargar el proyecto en VisualStudio2008: Descargar

Publicado en C#, Helpers, WebServices, WinForms | 3 Comentarios »

Escribir texto en una fotografía

Publicado por alskare en 26/08/2009

En más de una ocasión he tenido la necesidad de añadir algún texto dentro de una fotografía, bien sea como marca de agua para subir las fotos a un servidor o, sencillamente, para incluir algún tipo de información en la misma fotografía.

Siempre había realizado esta acción en VisualBasic, pero en esta ocasión he tenido que hacerlo en C# así que, siguiendo la costumbre, dejo aquí el trabajo. Tal como está la clase en estos momentos, reconozco que está muy verde, puesto que, sin problemas, pueden añadirse multitud de servicios que la harían mucho más funcional, pero deja bien asentadas las bases de la escritura de un texto dentro de la foto.

 

using System.Drawing;

namespace jnSoftware.Utiles.Fotos
{

    public class Foto
    {
        #region Campos 
        private Bitmap _foto = null;
        private int _posicion_izquierda = 2;
        private int _posicion_arriba = 2;
        private Brush _pincel = Brushes.White;
        private int _tamanoFuente = 100;
        private string _nombreFuente = "Tahoma";
        #endregion 


        #region Propiedades

        /// <summary>
        /// Obtiene o establece el pincel (color del texto)
        /// </summary>
        public Brush Pincel
        {
            get { return _pincel; }
            set { _pincel = value; }
        }
    

        /// <summary>
        /// Obtiene o establece el tamaño de letra
        /// </summary>
        public int Tamano
        {
            get { return _tamanoFuente; }
            set { _tamanoFuente = value; }
        }


        /// <summary>
        /// Obtiene o establece la distancia existente entre el borde izquierdo de la 
        /// foto y el principio del texto
        /// </summary>
        public int PosicionIzquierda
        {
            get { return _posicion_izquierda; }
            set { _posicion_izquierda = value; }
        }


        /// <summary>
        /// Obtiene o establece la distancia existente entre el borde superior de la 
        /// foto y el principio del texto
        /// </summary>
        public int PosicionArriba
        {
            get { return _posicion_arriba; }
            set { _posicion_arriba = value; }
        }

        #endregion


        #region Constructores
        /// <summary>
        /// Constructor - Instancia la clase con una nueva fotografía
        /// </summary>
        /// <param name="foto">Fotografía a retocar</param>
        public Foto(Bitmap foto)
        {
            _foto = foto;
        }

        /// <summary>
        /// Constructor - Instancia la clase con un fichero 
        /// </summary>
        /// <param name="foto">Ruta completa del fichero gráfico a retocar</param>
        public Foto(string foto)
        {
            _foto = new Bitmap(foto);
        }
        #endregion 




        /// <summary>
        /// Obtiene la foto con las modificaciones 
        /// </summary>
        /// <returns></returns>
        public Bitmap GetFoto()
        {
            return _foto ;
        }



        /// <summary>
        /// Escritura de la cadena de texto sobre la foto.
        /// </summary>
        /// <param name="cadena"></param>
        public void EscribeTexto(string cadena)
        {
            // La clase Graphics encapsula una superficie de dibujo de GDI+. 
            Graphics g = Graphics.FromImage(_foto);
            // Se crea un PointF para posicionar el texto
            PointF posicion = new PointF( _posicion_izquierda, _posicion_arriba);
            // Fuente
            Font fuente = new Font(_nombreFuente, _tamanoFuente);
            // Se escribe la cadena de texto en la fotografía
            g.DrawString(cadena, fuente, _pincel, posicion);
        }


    }
}

Publicado en C#, Helpers, NetFramework | Comentarios desactivados

Exportar datos a formato dbf

Publicado por alskare en 22/07/2009

Hoy me encuentro con un problema. Una aplicación que tengo corriendo bajo Sql Server 2005 tiene que exportar datos a un formato .DBF con la finalidad de poder traspasar los datos a un programa de contabilidad. Esta es una de aquellas cosas que , por lo menos para mí, son desagradables de crear, puesto que, comúnmente están mal valoradas. En la interfaz del cliente tan sólo se ve un formulario en el que se solicita un fichero o carpeta de salida y un botón que suele decir Exportar. El resto de horas de trabajo, sencillamente, no se aprecian.

Como siempre, empezando con una busca genérica, poco se ve del tema, así que mucho me temo que va a ser uno de aquellos días de prueba-error hasta que consiga obtener un apaño que hago algo similar a lo que se quiere inicialmente.

Por algún sitio habrá que empezar, así que inicio escribiendo la firma de los métodos estáticos que quiero crear:

 

using System;
using System.Data.Common;


namespace jnSoftware.Traspasos
{
    public static class Databases
    {

        /// <summary>
        /// Exporta una expresión Sql a formato Dbf (dBase III)
        /// </summary>
        /// <param name="cadenaConexion">Cadena de conexión con el servidor SQL</param>
        /// <param name="sql">Secuencia Select SQL para exportar</param>
        /// <param name="ficheroSalida">Nombre completo del fichero que se creará</param>
        /// <returns>true si la exportación es correcta</returns>
        public static bool Sql2Dbf(string cadenaConexion, string sql, string ficheroSalida)
        {
            DbProviderFactory factoria = DbProviderFactories.GetFactory("System.Data.SqlClient");
            return Databases.Db2Dbf(factoria, cadenaConexion, sql, ficheroSalida);
        }


        /// <summary>
        /// Exporta una expresión Sql a formato Dbf (dBase III)
        /// </summary>
        /// <param name="factoria">Factoría de System.Data.Common en el que se encuentra el formato de origen</param>
        /// <param name="cadenaConexion">Cadena de conexión con la base de datos de origen</param>
        /// <param name="sql">Secuencia Select SQL para exportar</param>
        /// <param name="ficheroSalida">Nombre completo del fichero que se creará</param>
        /// <returns>true si la exportación es correcta</returns>
        public static bool Db2Dbf(DbProviderFactory factoria, string cadenaConexion, string sql, string ficheroSalida)
        {
            // TODO 
            return false;
        }

    }
}

 

Es genial esto de Internet: una búsqueda un poco más detallada, me da una gran idea, gracias a uno de los “grandes de las news”, el Maestro Enrique Martinez ( Exportar de SQL a DBF ), así que intento hacer una adaptación que me permita tener un módulo más o menos útil.

Bueno, debo reconocer que no he sido capaz de hacer un volcado directo de una secuencia desde SQL a DBF. Me daba todo tipo de errores, sobre todo, por las cadenas de conexión, es decir, he podido hacer conexiones tanto a SQL como a DBF, pero no me he sido capaz de montar una buena consulta tal como comentaba Enrique en el foro. Por tanto, opto por otra opción.

Vueltas por aquí y por allí me hacen pensar en si se podría crear una tabla con la instrucción CREATE TABLE de Sql y… Bingo!. Me crea el fichero correctamente e incluso hasta me deja insertar datos. Al fin y al cabo, como se trata de crear un fichero “temporal” cuyo objetivo será el de traspasar datos, tampoco me voy a poner puntilloso con el tema de las restricciones de tablas, así que, después de crear las pruebas que incluyo a continuación, ya empiezo a pensar en una lectura de la estructura de la tabla de SQL Server que sirva también para la creación de la tabla de salida. ¡Veremos qué hacemos!. De momento, dejo las pruebas de creación de la base:

private static void CrearTabla()
{
    string ruta = @"C:\";
    string strConnDbase = @"Provider = Microsoft.Jet.OLEDB.4.0" +
                           ";Data Source = " + ruta +
                           ";Extended Properties = dBASE IV" +
                           ";User ID=Admin;Password=;";

    // Se borra el fichero en caso de que exista
    File.Delete(ruta + "\\salida.DBF");

    using (OleDbConnection cn = new OleDbConnection(strConnDbase))
    {
        // Pruebo a crear una tabla directamente
        string sql = "CREATE TABLE salida ( Campo1 Varchar(10), Campo2 Varchar(5) )";
        using (OleDbCommand cmd = new OleDbCommand(sql, cn))
        {
            cn.Open();
            cmd.ExecuteNonQuery();
            cn.Close();
        }

        // Realizo un par de pruebas de inserción de datos en la tabla.
        string sqlCommand = "Insert into salida(Campo1,Campo2) VALUES(@campo1,campo2);";
        OleDbCommand cmdInsertar = new OleDbCommand(sqlCommand, cn);
        cmdInsertar.Parameters.Add("@campo1", OleDbType.VarChar, 10);
        cmdInsertar.Parameters.Add("@campo2", OleDbType.VarChar,5);

        cn.Open();
        for (int i = 1; i <= 10; i++)
        {
            cmdInsertar.Parameters["@campo1"].Value = "h" + i;
            cmdInsertar.Parameters["@campo2"].Value = "i" + i;
            cmdInsertar.ExecuteNonQuery();
        }
        cn.Close();

    }
}

 

Resultado final.

Bueno, al final ha salido una versión que, de momento, hace lo que quería. Para la creación he seguido la el esquema que me había propuesto:

  1. Método estático que permite acceder desde otros proyectos. De hecho, esta parte casi la tenía creada con anterioridad
  2. Clase DatabaseToDbf, que se encarga de realizar todos los pasos:
    1. Lectura de la estructura en la base de datos de origen. Por comodidad he creado una clase auxiliar Campo, que permite trabajar de manera más cómoda con los campos de la “tabla” de origen.
    2. Creación de la base de dBase. Aunque inicialmente tenía la intención de hacer este método también con el namespace System.Data.Common, he desistido por comodidad. Si un día de estos tuviese tiempo, igual lo intento. De esta manera, con algún arreglo, podría ser un método que, con suerte, permite hacer un traslado de datos con un abanico más amplio de posibilidades.
    3. Recorrido por los datos de origen, realizando una inserción en la tabla dbf de destino.

 

Clase: Database

using System.Data.Common;

/*
 * Databases.cs
 * Servicios de traspaso de información entre bases de datos
 * 
 * alskare, Jul/09
 */

namespace jnSoftware.Traspasos
{
    public static class Databases
    {

        /// <summary>
        /// Exporta una expresión Sql a formato Dbf (dBase III)
        /// </summary>
        /// <param name="cadenaConexion">Cadena de conexión con el servidor SQL</param>
        /// <param name="sql">Secuencia Select SQL para exportar</param>
        /// <param name="ficheroSalida">Nombre completo del fichero que se creará</param>
        /// <returns>true si la exportación es correcta</returns>
        public static bool Sql2Dbf(string cadenaConexion, string sql, string ficheroSalida)
        {
            DbProviderFactory factoria = DbProviderFactories.GetFactory("System.Data.SqlClient");
            return Databases.Db2Dbf(factoria, cadenaConexion, sql, ficheroSalida);
        }


        /// <summary>
        /// Exporta una expresión Sql a formato Dbf (dBase III)
        /// </summary>
        /// <param name="factoria">Factoría de System.Data.Common en el que se encuentra el formato de origen</param>
        /// <param name="cadenaConexion">Cadena de conexión con la base de datos de origen</param>
        /// <param name="sql">Secuencia Select SQL para exportar</param>
        /// <param name="ficheroSalida">Nombre completo del fichero que se creará</param>
        /// <returns>true si la exportación es correcta</returns>
        public static bool Db2Dbf(DbProviderFactory factoria, string cadenaConexion, string sql, string ficheroSalida)
        {
            bool retval;
            DatabaseToDbf export = new DatabaseToDbf(factoria, cadenaConexion, sql, ficheroSalida);
            retval = export.Exporta();
            return retval;
        }


    }
}

Clase: DatabaseToDbf 

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.OleDb;
using System.IO;
using System.Text.RegularExpressions;

/*
 * DatabaseToDbf.cs
 * Servicios que permiten el traspaso de información de una base de datos a un fichero .dbf
 * 
 * alskare, Jul/09
 */


namespace jnSoftware.Traspasos
{

    /// <summary>
    /// Servicios que nos permiten realizar un traspaso de una base de datos 
    /// a un formato dbf
    /// </summary>
    internal class DatabaseToDbf
    {

        private DbProviderFactory factoria;
        private string cadenaConexion;
        private string sql;
        private string pathSalida;
        private string ficheroSalida;
        private string nombreTabla;

        private List<string> campos = new List<string>();
        private List<string> parametros = new List<string>();
        private List<string> nombreCampos = new List<string>();

        private string strConnDbf;



        /// <summary>
        /// Constructor de la clase
        /// </summary>
        /// <param name="factoria">Factoría del origen de los datos</param>
        /// <param name="cadenaConexion">Cadena de conexión a la base de datos de origen</param>
        /// <param name="sql">Instrucción Select SQL para exportar a dbf</param>
        /// <param name="ficheroSalida">Nombre completo del fichero de salida</param>
        public DatabaseToDbf(DbProviderFactory factoria, string cadenaConexion, string sql, string ficheroSalida)
        {
            this.factoria = factoria;
            this.cadenaConexion = cadenaConexion;
            this.sql = sql;

            // En base al fichero, se desglosa la información para usarla más tarde.
            FileInfo f = new FileInfo(ficheroSalida);
            pathSalida = f.DirectoryName;
            this.ficheroSalida = f.FullName;
            nombreTabla = new Regex(f.Extension + "$").Replace(f.Name, "");

            // Creación de la cadena de conexión al fichero .dbf
            strConnDbf = @"Provider = Microsoft.Jet.OLEDB.4.0" +
                                   ";Data Source = " + pathSalida +
                                   ";Extended Properties = dBASE IV" +
                                   ";User ID=Admin;Password=;";
        }





        /// <summary>
        /// Realiza la exportación de la base de datos de origen a un fichero con formato .dbf.
        /// </summary>
        /// <returns>True si el traspaso ha sido correcto</returns>
        public bool Exporta()
        {
            bool retVal = false;
            try
            {
                LeeEstructura();
                CreaTabla();
                InsertaDatos();

                // Se ha llegado hasta aquí, se supone que está todo bien
                retVal = true;
            }
            catch
            {
                retVal = false;
            }
            return retVal;
        }




        /// <summary>
        /// Lectura de la estructura de la tabla de origen
        /// </summary>
        private void LeeEstructura()
        {
            using (DbConnection cn = factoria.CreateConnection())
            {
                cn.ConnectionString = cadenaConexion;
                using (DbCommand cmd = cn.CreateCommand())
                {
                    cmd.Connection = cn;
                    cmd.CommandType = CommandType.Text;
                    cmd.CommandText = sql;

                    DbDataAdapter da = factoria.CreateDataAdapter();
                    da.SelectCommand = cmd;

                    DataTable dt = new DataTable();
                    da.FillSchema(dt, SchemaType.Mapped);

                    foreach (DataColumn columna in dt.Columns)
                    {
                        Campo c = new Campo(columna);
                        // Se crea la lista de parámetros
                        campos.Add(c.Tabla());
                        parametros.Add(c.Parametro());
                        nombreCampos.Add(c.Nombre());

                        c = null;
                    }
                }
            }
        }





        /// <summary>
        /// Creación del fichero DBF.
        /// </summary>
        private void CreaTabla()
        {
            // Se borra el fichero en el caso de que exista
            File.Delete(ficheroSalida);

            using (OleDbConnection cn = new OleDbConnection(strConnDbf))
            {
                using (OleDbCommand cmd = new OleDbCommand())
                {
                    cmd.Connection = cn;
                    cmd.CommandType = CommandType.Text;
                    cmd.CommandText = GetSql_Create();

                    cn.Open();
                    cmd.ExecuteNonQuery();
                    cn.Close();
                }
            }
        }





        /// <summary>
        /// Realiza el traspaso de datos de la base de datos de origen al fichero dbf.
        /// </summary>
        private void InsertaDatos()
        {
            // Preparación del comando de inserción
            OleDbConnection cnDestino = new OleDbConnection(strConnDbf);

            OleDbCommand cmdInserta = new OleDbCommand();
            cmdInserta.CommandType = CommandType.Text;
            cmdInserta.CommandText = GetSql_Insert();
            cmdInserta.Connection = cnDestino;

            // Parámetros 
            for (int i = 0; i < parametros.Count; i++)
            {
                // Añado los parámetros con un valor nulo. Luego se cambiará. 
                cmdInserta.Parameters.Add(new OleDbParameter(parametros[i], DBNull.Value));
            }

            // Se hace un recorrido por los datos de origen
            using (DbConnection cnOrigen = factoria.CreateConnection())
            {
                cnOrigen.ConnectionString = cadenaConexion;
                using (DbCommand cmd = cnOrigen.CreateCommand())
                {
                    cmd.Connection = cnOrigen;
                    cmd.CommandType = CommandType.Text;
                    cmd.CommandText = sql;

                    cnOrigen.Open();
                    DbDataReader dr = cmd.ExecuteReader();
                    cnDestino.Open();

                    while (dr.Read())
                    {
                        for (int i = 0; i < nombreCampos.Count; i++)
                        {
                            // Se establece el valor del parámetro
                            cmdInserta.Parameters[i].Value = dr[i];
                        }

                        // Ejecución de la inserción en dbf
                        cmdInserta.ExecuteNonQuery();
                    }
                    dr.Close();
                    cnDestino.Close();
                    cnOrigen.Close();
                }
            }
        }





        /// <summary>
        /// Devuelve la instrucción SQL que permitirá la inserción de los datos
        /// </summary>
        private string GetSql_Insert()
        {
            return "INSERT INTO " + nombreTabla +
                    string.Concat("(", string.Join(",", nombreCampos.ToArray()), ")")
                    + " VALUES " + string.Concat("(", string.Join(",", parametros.ToArray()), ")")
                    ;
        }



        /// <summary>
        /// Obtiene la instrucción SQL que permitirá la creación de la tabla
        /// </summary>
        private string GetSql_Create()
        {
            return "CREATE TABLE " + nombreTabla +
                string.Concat("(", string.Join(", ", campos.ToArray()), ")");

        }


    }
}

 

Clase auxiliar: Campo

using System;
using System.Data;

namespace jnSoftware.Traspasos
{



    /// <summary>
    /// Clase que representa un campo de la tabla de origen.
    /// </summary>
    /// <remarks>
    /// Como la estructura de la tabla de destino tendrá la misma estructura que la sentencia
    /// de entrada, es importante obtener todos los datos posibles de dicha estructura.
    /// </remarks>
    internal class Campo
    {

        /// <summary>
        /// Tipos de datos que puede tener la tabla de origen. 
        /// </summary>
        /// <remarks>Como que la lectura de la base de datos de origen se hace mediante clases genéricas
        /// de acceso a datos, pueden surgir tipos no conocidos aquí</remarks>
        private enum TiposCampoEnum { Varchar, Int, Double, Bit, DateTime }

        private string nombre;
        private TiposCampoEnum tipo; 
        private int tamano;


        /// <summary>
        /// Constructor. 
        /// </summary>
        public Campo(System.Data.DataColumn columna)
        {
            
            nombre = columna.ColumnName ;
            tipo = TipoCampo(columna) ;
            tamano = columna.MaxLength;
            // Se omiten intencionadamente los campos Memo
            if (tamano > 254)
                tamano = 254;
        }



        /// <summary>
        /// Adaptación del tipo de campo de origen a un formato simple dbf
        /// </summary>
        /// <remarks>Es posible que si se usan otras bases de datos haya que modificar este
        /// procedimiento</remarks>
        private TiposCampoEnum TipoCampo(DataColumn columna)
        {
            TiposCampoEnum s = TiposCampoEnum.Varchar;

            switch (columna.DataType.FullName)
            {
                case  "System.String" :
                    s = TiposCampoEnum.Varchar;
                    break;
            
                case "System.Int":
                case "System.Int16":
                case "System.Int32":
                case "System.Int64":
                    s = TiposCampoEnum.Int;
                    break;

                case "System.Double":
                case "System.Decimal":
                    s = TiposCampoEnum.Double;
                    break;


                case "System.Boolean":
                    s = TiposCampoEnum.Bit;
                    break;

                case "System.DateTime":
                    s = TiposCampoEnum.DateTime;
                    break;

                default :
                    throw new ArgumentOutOfRangeException("El tipo " + columna.DataType.FullName + 
                        " no está contemplado en el procedimiento Campo.TipoCampo");
            }
            return s;
        }



        /// <summary>
        /// Obtiene el campo en formato de parámetro
        /// </summary>
        /// <returns></returns>
        public string Parametro()
        {
            return  "@" + nombre; 
        }


        /// <summary>
        /// Obtiene el nombre del campo
        /// </summary>
        /// <returns></returns>
        public string Nombre()
        {
            return nombre;
        }


        /// <summary>
        /// Obtiene la estructura necesaria que se empleará en la creación de la tabla.
        /// </summary>
        /// <returns></returns>
        public string Tabla()
        {
            return "[" + nombre + "]" + " " + tipo + (tipo != TiposCampoEnum.Varchar ? "" : "(" + tamano + ")");
        }

    }
}

 

En las búsquedas que anduve haciendo sólo vi aplicaciones similares de pago, así que, con unos pocos cambios, es probable que tenga su utilidad.

Publicado en C#, Helpers, NetFramework | 3 Comentarios »

Validar número de cuenta bancaria española

Publicado por alskare en 20/07/2009

Ya hacía tiempo que no posteaba nada, así que ya va siendo hora que contribuya con alguna cosa. En esta ocasión, le toca el turno a una función que he tenido que realizar para validar una cuenta bancaria. Por la vagancia que nos suele caracterizar, había encontrado alguna cosa por Internet, pero debo decir que tuve problemas a la hora de aplicar en serio la función, sobre todo, por desbordamientos.

En la elaboración de la misma me he ido encontrando con algún que otro tropiezo, puesto que me ha dado la cabezonería de meterme en C# y, claro, después de tanto tiempo con mi querido VB, hay ocasiones en las que me quedo en blanco. No sé, una vez que está todo hecho, lo veo la mar de fácil, pero he tenido ciertos problemas con las costumbres del namespace Microsoft.VisualBasic (Os prometo que he estado un rato para hacer una función IsNumeric).

Bueno, el caso es que ya está hecho y aquí lo dejo por si hay alguien que pueda usarlo. He optado por la creación de una clase estática que incluye tres métodos públicos (Bendita sobrecarga) para intentar evitar las conversiones típicas:

// Cuenta bancaria completa. 20 dígitos
bool c1 = CuentasBancarias.ValidaCuentaBancaria("01230123010123456789");

// Separación de Banco, Oficina, Dc y cuenta en formato string
bool c2 = CuentasBancarias.ValidaCuentaBancaria("0123", "0123", "01", "0123456789");

// Separación de Banco, Oficina, Dc y cuenta en formato UInt64
bool c3 =  CuentasBancarias.ValidaCuentaBancaria(123, 123, 1, 12345);

Bueno, pues dejo el código. Si alguien encuentra algún error o algún modo de mejorarlo, no tiene más que decirlo.

using System;
using System.Text.RegularExpressions;

namespace jnSoftware.Validaciones
{

    /// <summary>
    /// Servicios de validación de las cuentas bancarias españolas
    /// </summary>
    public static class CuentasBancarias
    {

        /// <summary>
        /// Validación de una cuenta bancaria española
        /// </summary>
        /// <param name="banco">Código del banco en formato "0000"</param>
        /// <param name="oficina">Código de la sucursal en formato "0000"</param>
        /// <param name="dc">Dígito de control en formato "00"</param>
        /// <param name="cuenta">Número de cuenta en formato "0000000000"</param>
        /// <returns>true si el número de cuenta es correcto</returns>
        public static bool ValidaCuentaBancaria(string banco, string oficina, string dc, string cuenta)
        {
            // Se comprueba que realmente sean números los datos pasados como parámetros y que las longitudes
            // sean correctas
            if (!IsNumeric(banco) || banco.Length != 4)
                throw new ArgumentException("El banco no tiene un formato adecuado");

            if (!IsNumeric(oficina) || oficina.Length != 4)
                throw new ArgumentException("La oficina no tiene un formato adecuado");

            if (!IsNumeric(dc) || dc.Length != 2)
                throw new ArgumentException("El dígito de control no tiene un formato adecuado");

            if (!IsNumeric(cuenta) || cuenta.Length != 10)
                throw new ArgumentException("El número de cuenta no tiene un formato adecuado");

            return CompruebaCuenta(banco, oficina, dc, cuenta);
        }

        /// <summary>
        /// Validación de una cuenta bancaria española
        /// </summary>
        /// <param name="cuentaCompleta">Número de cuenta completa con carácteres numéricos y 20 dígitos</param>
        /// <returns>true si el número de cuenta es correcto</returns>
        public static bool ValidaCuentaBancaria(string cuentaCompleta)
        {
            // Comprobaciones de la cadena
            if (cuentaCompleta.Length != 20)
                throw new ArgumentException("El número de cuenta no el formato adecuado");

            string banco = cuentaCompleta.Substring(0, 4);
            string oficina = cuentaCompleta.Substring(4, 4);
            string dc = cuentaCompleta.Substring(8, 2);
            string cuenta = cuentaCompleta.Substring(10, 10);

            return ValidaCuentaBancaria(banco,oficina,dc,cuenta);

        }

        /// <summary>
        /// Validación de una cuenta bancaria española
        /// </summary>
        /// <param name="banco">Código del banco</param>
        /// <param name="oficina">Código de la oficina</param>
        /// <param name="dc">Dígito de control</param>
        /// <param name="cuenta">Número de cuenta</param>
        /// <returns>true si el número de cuenta es correcto</returns>
        public static bool ValidaCuentaBancaria(UInt64 banco, UInt64 oficina, UInt64 dc, UInt64 cuenta)
        {
            return ValidaCuentaBancaria(
                                banco.ToString("0000")
                                , oficina.ToString("0000")
                                , dc.ToString("00")
                                , cuenta.ToString("0000000000")
                                );
        }

        /// <summary>
        /// Comprueba que la cadena sólo incluya números
        /// </summary>
        /// <param name="numero">Cadena de texto en formato número</param>
        /// <returns>true si <paramref name="numero"/> contiene sólo números</returns>
        /// <remarks>No se contemplan decimales</remarks>
        private static bool IsNumeric(string numero)
        {
            Regex regex = new Regex("[0-9]");
            return regex.Match(numero).Success;
        }

        /// <summary>
        /// Una cuenta bancaria está validada si los dígitos de control calculados coinciden con los
        /// que se han pasado en los argumentos
        /// </summary>
        private static bool CompruebaCuenta(string banco, string oficina, string dc, string cuenta)
        {
            return GetDigitoControl("00" + banco + oficina) + GetDigitoControl(cuenta) == dc;
        }

        /// <summary>
        /// Obtiene el dígito de control de una cuenta bancaria. La función sólo devuelve un número
        /// que corresponderá a una de las dos opciones.
        ///     - Codigo + CódigoOficina
        ///     - CuentaBancaria
        /// </summary>
        private static string GetDigitoControl(string CadenaNumerica)
        {
            int[] pesos = { 1, 2, 4, 8, 5, 10, 9, 7, 3, 6 };
            UInt32 suma = 0;
            UInt32 resto;

            for (int i = 0  ; i < pesos.Length; i++)
            {
                suma += (UInt32)pesos[i] * UInt32.Parse(CadenaNumerica.Substring(i, 1));
            }
            resto = 11 - (suma % 11);

            if (resto == 10) resto = 1;
            if (resto == 11) resto = 0;

            return resto.ToString("0");
        }

    }
}

Los amigos de velasco.biz han creado una página en la que puede validarse una cuenta bancaria in-situ. Dicho de otra manera, puede probarse todo este código en la dirección http://www.velasco.biz/html/desarrollo/Validaciones.aspx

Publicado en C#, Helpers, NetFramework | 2 Comentarios »

 
Seguir

Get every new post delivered to your Inbox.