twitter

La comunidad Netaweb 2.0, como parte de su restructuración tiene como planes realizar una serie de proyectos “Open-Source” alojados en CodePlex para el uso y aprendizaje de las nuevas tecnologías que nos ofrece Microsoft.

En esta ocacion le toca el turno a NetTwit, siendo este no más un cliente rico, amigable y flexible para Twitter, usando las API que ofrece el servicio e integrando otros servicios que se integran con Twitter.

NetTwit estaba basado en Windows Communication Foundation (WCF) (tomando como base el desarrollo que hicieron los chicos de Vertigo Software y haciendole a la vez algunas mejoras) y Windows Presentation Foundation (WPF), siendo WCF la plataforma base para la implementación de las API de Twitter y WPF como la capa de presentación del cliente, el proyecto tiene como propósito aprender y entender la arquitectura de Windows Communication Foundation (WCF), no solamente a los miembros de la Comunidad NetaWeb 2.0 sino a cualquier entusiasta interesado en colaborar y aprender.

¿Qué es NetaWeb 2.0?

NetaWeb 2.0 es la más grande comunidad de desarrolladores profesionales de República Dominicana y el Caribe, teniendo en su cartera más de 1800 miembros registrados, la comunidad está enfocada en todo lo concerniente al desarrollo de software usando la tecnología .NET.

¿Qué es Twitter?

Tal como dice Wikipedia, Twitter es un servicio gratuito de microblogging, que hace las veces de red social y que permite a sus usuarios enviar micro-entradas (también denominadas "tweets") basadas en texto, con una longitud máxima de 140 caracteres, donde se responde a la pregunta ¿Qué estás haciendo?. El envío de estos mensajes se puede realizar tanto por la web de Twitter, como vía SMS (Short Message Service) desde un teléfono móvil, desde programas de mensajería instantánea, o incluso desde cualquier aplicación de terceros.

Pueden ver más información del proyecto en los links:

http://www.codeplex.com/NetTwit
http://www.twitter.com/estebanx

Problema

Desde hace varios meses cada domingo envió más de 250 SMS vía Orange a distintos celulares de diferentes compañías telefónicas,  Orange tienen una aplicación web que me permite agregar contactos y a la vez con estos agregarlo a listas de contactos para poder enviarle lo mensajes, sucede que los números que no pertenecen a Orange no se pueden enviar y a la vez se quedan en los estados  “Numero Invalido”, “Pendiente”, “Expirado” y “Fallido”, hasta aquí vamos bien, la aplicación web me provee una opción para ver el histórico de mensajes enviado, el problema consiste en que el histórico no me provee una opción para filtrar los números que están en los estados “Numero Invalido”, “Pendiente”, “Expirado” y “Fallido”.

Solución   

Dada esta problemática decidí por mi cuenta poder hacer consultas al html que genera la aplicación

Aplicacion


Tome solamente del código html el table donde están los campos que necesito para poder hacerle más adelante consulta con Linq y lo guarde en el disco C: con el nombre geeksPhones.html


Entendiendo el esquema del archivo guardado

El archivo guardado tiene el siguiente esquema para la primera fila:

 esquemafirstrow

Esta primera fila realmente no nos interesa la que si nos va a interesar es a partir de la segunda fila en adelante que tendrá el mismo código repetitivo de los 1546 mensajes enviados:

secondrow

Diseño de nuestra aplicacion

Como todos sabemos HTML se deriva del GML (Standard Generalized Markup Language - Lenguaje de Marcación Estándar Generalizada), que tambien xml se deriva del GML, entonces  decidi convertir el HTML en XML y esto se hizo posible usando el componente htmlagilitypack y la vez parsiando ese html con mi Extension Methods ToXMLDocument();

  public static XDocument ToXMLDocument(this HtmlDocument doc)
        {
            using (StringWriter strWriter = new StringWriter())
            {
                doc.OptionOutputAsXml = true;
                doc.Save(strWriter);
                return XDocument.Parse(strWriter.GetStringBuilder().ToString());
            }
        }

Tenemos tambien la clase Phone:

public class Phones
    {
        public string SendDate { get; set; }
        public string Phone { get; set; }
        public string EndDate { get; set; }
        public Status Status { get; set; }
    }

Y finalmente el Enum Status:

public enum Status
    {
        None = 0, //Siempre uso este como valor Default
        Recibido = 1,
        Pendiente = 2,
        NumeroInvalido = 3,
        Fallido = 4,
        Expirado = 5
    }

 

Definido ya estos elementos entonces use el siguiente Linq Query para poder leer el html y convertirlo en una Lista genérica de tipo Phone:

HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            
            doc.Load(@"C:\geeksphones.html");
            XDocument xmlDoc = doc.ToXMLDocument();
            List<Phones> query = (from d in xmlDoc.Descendants("table")
                         let tbody = d.Element("tbody")
                         let tr = tbody.Element("tr")
                         select new
                         {

                             SendDate = (from s in tbody.Descendants("td")
                                         select s
                                             into tempsenddate
                                             where tempsenddate.Attribute("width").Value == "5%" && 
tempsenddate.HasElements ==
false
&& tempsenddate.Value.Length > 18
select tempsenddate.Value ).ToArray(), Status = (from status in tbody.Descendants("td") select status into tempstatus where tempstatus.Attribute("width").Value == "3%" && tempstatus.HasElements == false
&& tempstatus.Value.Length > 3 && tempstatus.Value.Length <= 15 select tempstatus.Value).ToArray(), PhoneNumber = (from p in tbody.Descendants("td") select p into tempPhoneNumber where tempPhoneNumber.Attribute("width").Value == "5%" &&
tempPhoneNumber.HasElements ==
false && tempPhoneNumber.Value.Length == 10 select tempPhoneNumber.Value).ToArray(), ReceiveDate = (from r in tbody.Descendants("td") select r into tempReceive where tempReceive.Attribute("width").Value == "3%" &&
tempReceive.HasElements ==
false && tempReceive.Value.Length == 19
|| tempReceive.Value.Length == 3
select tempReceive.Value).ToArray() } into tempPhone from i in Enumerable.Range(0, tempPhone.PhoneNumber.Count()) select new Phones() { Phone = tempPhone.PhoneNumber[i], EndDate = tempPhone.ReceiveDate[i], SendDate = tempPhone.SendDate[i], Status = (Status)Enum.Parse(typeof(Status), tempPhone.Status[i].Replace(" ", "")) } ).ToList();

Explicación del Query

Básicamente lo que queremos de nuestro HTML es saber la fecha de envió, el número de teléfono, el estatus del mensaje y la fecha de recepción, entonces para obtenerlo correctamente tenemos que:

SendDate: solamente se llenara cuando el elemento (td) tenga el atributo width en 5%, no tenga más elementos hijos y la longitud del valor del elemento sea igual a 19 caracteres.

Status: para que pueda tener los datos correctos se debe cumplir la condición de que el elemento (td) tenga el atributo width = 3%, el elemento no tenga más elementos hijos y la longitud del valor del elemento este en un rango de 3 hasta 15 caracteres.

PhoneNumber: para obtener los números correctamente se debe cumplir las condiciones de que el elemento (td) tenga el atributo width = 5%, el elemento no tenga más elementos hijos y la longitud del valor del elemento sea igual a 10 caracteres debido a que los números en mi país tiene un total de 10 caracteres.

ReceiveDate: para obtener la fecha de recibido correctamente se debe cumplir las condiciones de que el elemento (td) tenga el atributo width=3%, el elemento no tenga más elemento hijos y la longitud del elemento sea igual a 18 caracteres o a 3 caracteres ya que cuando el mensaje se queda en el estatus expirado la fecha sale con los caracteres “---“.

 linqToHtml

Descargas

Codigo Linq To HTML aqui.
Archivo geekPhones.html aqui. (este archivo es necesario ponerlo en el disco C:\)

Plus

Dentro de la aplicación también encontraran un Tab llamado leer imágenes el cual tiene la funcionalidad de leer las imágenes de una dirección web dada y mostrar el largo y el ancho de la imagen.

LinqToHTMLImg

y el Codigo para esto es:

 HtmlAgilityPack.HtmlWeb hweb = new HtmlAgilityPack.HtmlWeb();
            string strUrl = @textBox1.Text;
            Uri url = new Uri(strUrl);
            HtmlAgilityPack.HtmlDocument doc = hweb.Load(strUrl);
            


            var xdoc = doc.ToXMLDocument();
            var imgs = from x in xdoc.Descendants()
                       let width = int.Parse((x.Attribute("width") ?? new XAttribute(XName.Get("width"), "0")).Value.TrimEnd('%'))
                       let height = int.Parse((x.Attribute("height") ?? new XAttribute(XName.Get("height"), "0")).Value.TrimEnd('%'))
                       let metrica = Math.Sqrt(width * height)
                       where x.Name.LocalName == "img"
                       orderby metrica descending
                       select new
                       {
                           Src = x.Attribute(XName.Get("src")).Value,
                           Width = width,
                           Height = height
                       };

 

Espero que le haya sido de utilidad.

linq

 

 

LINQ o Language integrated query es un lenguaje de consultas integrado al lenguaje que fue introducido en las nuevas versiones de Visual Studio 2008, LINQ nos permite una sintaxis estándar para consultar diferentes fuentes de datos, sea SQL, XML u objetos en memoria.

Antes del framework 3.5, los desarrolladores típicamente usábamos ADO para consultar alguna que otra base de datos relacional, es decir si queríamos conectarnos y consultar alguna tabla usábamos las librerías de ADO específicamente System.Data.SqlClient. Si queríamos traer datos de la manera más rápida posible, entonces usábamos DataReaders, pero la responsabilidad del mantenimiento de la Data estaba a cargo del Desarrollador, y si el performance no era una de nuestras prioridades entonces optábamos por usar Datasets.

Luego de una conversación con mi amigo Dany Paredes, discutíamos acerca del Performance de LINQ TO SQL, para mi entender desarrollar con LINQ TO SQL es bastante rápido el desarrollo y todo eso, pero que ¿tal el performance?, decidí hacer las pruebas por mí mismo.

Escribí una Aplicación de Consola, para probar que tal el performance de LINQ TO SQL, ADO Datasets y ADO Datareader. La aplicación contiene 3 métodos los cuales cada uno de ellos consultan la tabla Customer de la base de datos northwind que contiene 91 registros 10,000 veces. En el caso para popular el Datareader cree una clase llamada clCustomer.

 

using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Configuration;
using System.Linq;



namespace LinqToSqlTest
{
    public class Program
    {
        public static string myconnectionstring = @"Data Source=.;Initial Catalog=northwind;User Id=sa;Password=sa;";

        static void Main(string[] args)
        {
            DateTime start;
            DateTime endTime;

            start = DateTime.Now;
            GetDataFromDatasets();
            endTime = DateTime.Now;
            Tiempo(start, endTime, "Usando Datasets");

            start = DateTime.Now;
            GetDataFromLinqToSQL();
            endTime = DateTime.Now;
            Tiempo(start, endTime, "Usando LINQ TO SQL");


            start = DateTime.Now;
            GetDataFromDataReaders();
            endTime = DateTime.Now;
            Tiempo(start, endTime, "Usando DataReaders");

            System.Console.ReadLine();
        }

        /// <summary>
        /// Traer los datos desde LINQ TO SQL
        /// </summary>
        private static void GetDataFromLinqToSQL()
        {
            LinqToSqlTestDataContext con = new LinqToSqlTestDataContext();
            var query = con.Customers;

            for (int i = 0; i < 10000; i++)
            {
                query.ToList();
            }
        }

        /// <summary>
        /// Metodo para Traer los datos en un reader
        /// </summary>
        private static void GetDataFromDataReaders()
        {
            SqlConnection con = new SqlConnection(myconnectionstring);
            string query = "select [CustomerID], [CompanyName], [ContactName], [ContactTitle], " +
            "[Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax]  from [dbo].[Customers]";
            SqlCommand command = new SqlCommand(query, con);
            con.Open();
            clCustomer sp = new clCustomer();
            for (int i = 0; i < 10000; i++)
            {
                SqlDataReader rdr = command.ExecuteReader();
                while (rdr.Read())
                {
                    sp.CustomerID = rdr["CustomerID"].ToString();
                    sp.CompanyName = rdr["CompanyName"].ToString();
                    sp.ContactName = rdr["ContactName"].ToString();
                    sp.ContactTitle = rdr["ContactTitle"].ToString();
                    sp.Address = rdr["Address"].ToString();
                    sp.City = rdr["City"].ToString();
                    sp.Region = rdr["Region"].ToString();
                    sp.PostalCode = rdr["PostalCode"].ToString();
                    sp.Country = rdr["Country"].ToString();
                    sp.Phone = rdr["Phone"].ToString();
                    sp.Fax = rdr["Fax"].ToString();

                }
                rdr.Close();
            }
        }

        /// <summary>
        /// Metodo para traer los resultados en un Dataset
        /// </summary>
        private static void GetDataFromDatasets()
        {
            SqlConnection con = new SqlConnection(myconnectionstring);
            string query = "select [CustomerID], [CompanyName], [ContactName], [ContactTitle], " +
            "[Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax]  from [dbo].[Customers]";
            SqlCommand command = new SqlCommand(query, con);
            SqlDataAdapter da = new SqlDataAdapter(command);
            DataSet ds = new DataSet();
            for (int i = 0; i < 10000; i++)
            {
                da.Fill(ds);
            }
        }

        private static void Tiempo(DateTime dt1, DateTime dt2, string message)
        {
            string time = ((dt2.Ticks - dt1.Ticks) / 10000000.0).ToString();
            System.Console.WriteLine(message + ": " + time + " Segundos");
        }
    }

    public class clCustomer
    {
        public string CustomerID { get; set; }
        public string CompanyName { get; set; }
        public string ContactName { get; set; }
        public string ContactTitle { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string Region { get; set; }
        public string PostalCode { get; set; }
        public string Country { get; set; }
        public string Phone { get; set; }
        public string Fax { get; set; }

    }
}

¿Cuáles fueron los resultados?

linqtosqlScreen

  • Datasets (29.313 segundos)
  • LINQ TO SQL (18.629 segundos)
  • DataReaders (18.037 segundos)

Así que tenemos que LINQ TO SQL es mas rápido que un Dataset y ligeramente más lento que un DataReader.

Si quieres puedes probarlo tu mismo copiando el código y creando un Linq To Sql Class llamado northwind.dbml. Solamente es necesario la tabla Customers.

Espero que les sea de utilidad.

communitylaunch

Hola amigos, este mes vamos a estar dando el evento “Desarrollo de Aplicaciones Web con Prototype + Ajax + WCF” todo esto tiene que ver con los “Heroes Community launch” que estamos celebrando en nuestra País República Dominicana.

Primera tanda:
27 de Mayo, 6:00 p.m., salón 204-205

Tema:
Desarrollo de aplicaciones Web con Prototype, Ajax y Windows communication Foundation
Lugar: Universidad Iberoamericana (UNIBE)
Speaker: Esteban Zavala & Mayreni Vargas

Segunda tanda:
Tema: Visual Studio 2008 & SQL 2008: Coming together
Lugar: Universidad Iberoamericana (UNIBE)
Speaker: Ismael Mendez & Hector Minaya

Para los primero 50 en llegar:
1 kit de developers para training
1 Windows Vista Ultimate (de evaluación, por 1 año)

Rifaremos:
20 Libros de Linq
5 Vouchers para exámenes de certificación con un 40% de descuento en los mismos y 5 Vouchers mas si dices que viste esto en geeks.ms :P
5 kits de lanzamiento, incluyen Windows server 2008 trial de 1 año, SQL Server 2008 Developer, Visual Studio 2008 Standard Full.

searchcommands
Microsoft Office 2007 ha sustituido los menús convencionales y ha integrado una nueva tecnología llamada Ribbon, esta tecnología tiene la particularidad que combina los menús y las herramientas en un solo lugar para así tener un fácil acceso a las opciones que nos brinda office.

Sin embargo, hemos visto como en nuestras lugares de trabajo, familiares, amigos, se han quejado, reprochándonos (tal como si fuera un empleado de Microsoft) que no encuentran las opciones que estaban acostumbrados a usar.

Debido a esto Microsoft Office Labs ha lanzando un nueva herramienta que se integra con Office 2007 English version, específicamente con Word, Excel y Power Point llamada Search Commands, esta nos ayuda a encontrar comandos, opciones, asistentes y galerías, simplemente escribiendo la opción y esta traerá una lista de las posibles opciones.

Pueden ver más información enlace:
http://www.officelabs.com/projects/searchcommands/Pages/default.aspx
silhouette_1_thumb





















 




Luego de varias semanas de espera, por fin he recibido el {Heroes Community Launch Kit} y asi poder ser un {Heroe} mas de las comunidades Microsoft.

Dicho Kit contiene:

1 {Exclusive} Windows Server 2008 Deep technical “event-in-a-box”

- 5 Windows Server 2008 Enterprise Edition DVDs

- 5 Visual Studio Standard DVDs

- 5 SQL Server 2008 CTP5 DVDs and a NFR voucher for SQL Server 2008 Enterprise redeemable when SQL Server 2008 is Generally Available (GA)

- 2 Full bit DVDs of Vista Ultimate SP1 NFR 

- 3 Vouchers for a Free 1 year subscription to TechNet Plus

- 1 WS08 Application Readiness Resource kit enhanced with Solutions Accelerator modules

- Microsoft Learning Solutions 40% off Exam Vouchers

- 1 SQL Server 2008 Technical Readiness kit 

- 1 .NET 3.5 Dev Resource Kit

- 1 AMD “Virtualization for Dummies” Handbook

- 40% off TechNet Plus Subscriptions with Full Bit/No Technical Time Bomb Product Download/Eval for All of your attendees

- Heroes {Community} Launch Poster

- CPLS  Certification Poster

 

Luego publicaremos los lugares en la Republica Dominicana donde se daran los eventos para poder repartir el material, dichos eventos seran impartidos por la nueva comunidad de desarrollo que vamos a lanzar que se llamara DotNetLab.

Saludos

  photo-01 photo-02 photo-03
windows-vista-logo-1

Cuando uno instala el Service Pack 1 en nuestras computadoras,  este no elimina algunos archivos de la antigua version de Windows Vista de nuestro disco duro. Esto es a causa de que estos archivos podrian ser requerido en caso de que decidamos desinstalar el Service pack 1.

Logicamente estos archivos ocupan un importante espacio en nuestro disco duro, en mi caso personal 1.2 GB, entonces si estas sastifecho (como yo) con los resultados obtenidos con el Service Pack 1 y no tienes interes alguno en un futuro de desinstalarlo, entonces porque no reclamas el espacio que estos archivos ocupan en tu disco duro.

Para reclamar este espacio basta solamente seguir los siguientes pasos:

  1. Inicio -> Abrir el command prompt escribiendo cmd en el start search
  2. En el command prompt escribir vsp1cln.exe (Vista SP1 Cleaner).

Estos nos tomara algunos minutos (dependiendo de la maquina) para remover los archivos de la antigua version

  vsp1cln
Esta accion hace que el Windows Vista Service pack 1 se quede de forma permanente en tu computadora. Y el espacio extra nos sirve para ocuparlo con archivos importantes.

Para ejecutar el Vista Sp1 Cleaner no necesitas estar conectado a internet y no podras en un futuro eliminar el Service pack 1, asi que si lo ejecutas es bajo riezgo propio.

Espero que le sea de utilidad.

Despues de pasar muchas horas pensando, debuggiando y buscandole la vuelta a una solucion que consistia en hacerle una auditoria a una base de datos SQL 2005, pudimos desarrollar una herramienta llamada SQLTableHistory esta herramienta nos da la facilidad de que podemos seleccionar las tablas que queremos auditar.

Pero navegando me encontre con una excelente solucion hecha por Jon Galloway, en la cual consiste en crear un solo script y que este se encarge de crear los triggers necesarios para cada tabla de la base de datos seleccionada, la diferencia con SQLTableHistory es que con nuestra herramienta podemos seleccionar las tablas que queremos que se le haga su respectiva auditoria y con la solucion presentada en este blog.

Aqui un ejemplo de como se verian los datos con la solucion de Jon Galloway

 

Con esta informacion podemos hacer reportes de una manera sencilla tales como:

  • Cuales tablas han sufridos cambios recientemente.
  • Cuales tablas no sufrieron cambios el pasado año.
  • Cuales tablas jamaz han sufrido cambios.
  • Mostrar todos los cambios a las tablas por un usuario y periodo especifico.
  • Mostrar las tablas mas activas en un determinado periodo.

    Con estas herramientas es posible volver al estado anterior de la tabla y volver en un punto especifico, claro esta ya depende de las nuevas extensiones que ustedes le hagan.

    Aqui os dejo el script completo que crea la tabla de auditoria y corre el script para crear los triggers a todas las tablas de la base de datos.

    USE MYDATABASE--Ponerle el nombre de la base de datos que va hacer auditada

    GO

     

    IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= 'Audit')

    CREATE TABLE Audit

    (

    AuditID [int]IDENTITY(1,1) NOT NULL,

    Type char(1),

    TableName varchar(128),

    PrimaryKeyField varchar(1000),

    PrimaryKeyValue varchar(1000),

    FieldName varchar(128),

    OldValue varchar(1000),

    NewValue varchar(1000),

    UpdateDate datetime DEFAULT (GetDate()),

    UserNamevarchar(128)

    )

    GO

     

    DECLARE @sql varchar(8000), @TABLE_NAMEsysname

    SET NOCOUNT ON

     

    SELECT @TABLE_NAME= MIN(TABLE_NAME)

    FROM INFORMATION_SCHEMA.Tables

    WHERE

    TABLE_TYPE= 'BASE TABLE'

    AND TABLE_NAME!= 'sysdiagrams'

    AND TABLE_NAME!= 'Audit'

     

    WHILE @TABLE_NAMEIS NOT NULL

     BEGIN

    EXEC('IF OBJECT_ID (''' + @TABLE_NAME+ '_ChangeTracking'', ''TR'') IS NOT NULL DROP TRIGGER ' + @TABLE_NAME+ '_ChangeTracking')

    SELECT @sql =

    '

    create trigger ' + @TABLE_NAME+ '_ChangeTracking on ' + @TABLE_NAME+ ' for insert, update, delete

    as

     

    declare @bit int ,

    @field int ,

    @maxfield int ,

    @char int ,

    @fieldname varchar(128) ,

    @TableName varchar(128) ,

    @PKCols varchar(1000) ,

    @sql varchar(2000),

    @UpdateDate varchar(21) ,

    @UserName varchar(128) ,

    @Type char(1) ,

    @PKFieldSelect varchar(1000),

    @PKValueSelect varchar(1000)

     

    select @TableName = ''' + @TABLE_NAME+ '''

     

    -- date and user

    select @UserName = system_user ,

    @UpdateDate = convert(varchar(8), getdate(), 112) + '' '' + convert(varchar(12), getdate(), 114)

     

    -- Action

    if exists (select * from inserted)

    if exists (select * from deleted)

    select @Type = ''U''

    else

    select @Type = ''I''

    else

    select @Type = ''D''

     

    -- get list of columns

    select * into #ins from inserted

    select * into #del from deleted

     

    -- Get primary key columns for full outer join

    select@PKCols = coalesce(@PKCols + '' and'', '' on'') + '' i.'' + c.COLUMN_NAME + '' = d.'' + c.COLUMN_NAME

    fromINFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,

    INFORMATION_SCHEMA.KEY_COLUMN_USAGE c

    where pk.TABLE_NAME = @TableName

    andCONSTRAINT_TYPE = ''PRIMARY KEY''

    andc.TABLE_NAME = pk.TABLE_NAME

    andc.CONSTRAINT_NAME = pk.CONSTRAINT_NAME

     

    -- Get primary key fields select for insert

    select @PKFieldSelect = coalesce(@PKFieldSelect+''+'','''') + '''''''' + COLUMN_NAME + ''''''''

    fromINFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,

    INFORMATION_SCHEMA.KEY_COLUMN_USAGE c

    where pk.TABLE_NAME = @TableName

    andCONSTRAINT_TYPE = ''PRIMARY KEY''

    andc.TABLE_NAME = pk.TABLE_NAME

    andc.CONSTRAINT_NAME = pk.CONSTRAINT_NAME

     

    select @PKValueSelect = coalesce(@PKValueSelect+''+'','''') + ''convert(varchar(100), coalesce(i.'' + COLUMN_NAME + '',d.'' + COLUMN_NAME + ''))''

    from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,   

    INFORMATION_SCHEMA.KEY_COLUMN_USAGE c  

    where  pk.TABLE_NAME = @TableName  

    and CONSTRAINT_TYPE = ''PRIMARY KEY''  

    and c.TABLE_NAME = pk.TABLE_NAME  

    and c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME

     

    if @PKCols is null

    begin

    raiserror(''no PK on table %s'', 16, -1, @TableName)

    return

    end

     

    select @field = 0, @maxfield = max(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName

    while @field < @maxfield

    begin

    select @field = min(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName and ORDINAL_POSITION > @field

    select @bit = (@field - 1 )% 8 + 1

    select @bit = power(2,@bit - 1)

    select @char = ((@field - 1) / 8) + 1

    if substring(COLUMNS_UPDATED(),@char, 1) & @bit > 0 or @Type in (''I'',''D'')

    begin

    select @fieldname = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName and ORDINAL_POSITION = @field

    select @sql = ''insert Audit (Type, TableName, PrimaryKeyField, PrimaryKeyValue, FieldName, OldValue, NewValue, UpdateDate, UserName)''

    select @sql = @sql + '' select '''''' + @Type + ''''''''

    select @sql = @sql + '','''''' + @TableName + ''''''''

    select @sql = @sql + '','' + @PKFieldSelect

    select @sql = @sql + '','' + @PKValueSelect

    select @sql = @sql + '','''''' + @fieldname + ''''''''

    select @sql = @sql + '',convert(varchar(1000),d.'' + @fieldname + '')''

    select @sql = @sql + '',convert(varchar(1000),i.'' + @fieldname + '')''

    select @sql = @sql + '','''''' + @UpdateDate + ''''''''

    select @sql = @sql + '','''''' + @UserName + ''''''''

    select @sql = @sql + '' from #ins i full outer join #del d''

    select @sql = @sql + @PKCols

    select @sql = @sql + '' where i.'' + @fieldname + '' <> d.'' + @fieldname

    select @sql = @sql + '' or (i.'' + @fieldname + '' is null and  d.'' + @fieldname + '' is not null)''

    select @sql = @sql + '' or (i.'' + @fieldname + '' is not null and  d.'' + @fieldname + '' is null)''

    exec (@sql)

    end

    end

    '

    SELECT @sql

    EXEC(@sql)

    SELECT @TABLE_NAME= MIN(TABLE_NAME) FROM INFORMATION_SCHEMA.Tables

    WHERE TABLE_NAME> @TABLE_NAME

    AND TABLE_TYPE= 'BASE TABLE'

    AND TABLE_NAME!= 'sysdiagrams'

    AND TABLE_NAME!= 'Audit'

    END

     


    Para mas informacion:
  • Jon Galloway
    SQL Server 2005's DDL triggers
    Nigel Rivett's SQL Server Auditing triggers

    Espero que les sea de utilidad!!!

    Ayer Microsoft anuncio al mundo en la conferencia MIX08 en las vegas la publicacion del primer Beta de Internet explorer 8 para desarrolladores y diseñadores Web. Este primer Beta no trae muchos cambios en la apariencia pero si introduce un nuevo motor de renderizado basado en normas y estandares de la industria entre otras caracteristicas. Entre la que se destacan nuevas herramientas para los desarrolladores , activities y webslides.

    Como pueden ver la UI del explorer no han habido cambios significativos, la primera vez que corremos el explorer nos saldra la ventana de Setup para configurar nuestro explorer.

    firsttime

    Activities

    Activities son nuevas vias que nos brinda internet explorer 8 a los desarrolladores para usar servicios de otros portales web eliminando asi la necesidad de copiar y pegar informacion hacia otro website, me explico anteriormente uno necesitaba copiar una direccion y encontrar la localizacion de dicha direccion en live maps, ahora con activities en IE8 simplemente seleccionamos el texto que contiene la direccion, entonces nos saldra un menu donde estaran las opciones posibles que podriamos hacer con el texto seleccionado, en este caso seleccionamos "Map with live maps" y esta nos brinda un preview del resultado de la opcion seleccionada. Microsoft nos brinda tambien la posibilidad de agregar nuevos activity providers para mas info http://ie.microsoft.com/activities/en-en/Default.aspx

    activities

    Video

    Webslides

    Los Webslides es otra de las nuevas caracteristicas de IE8 permitiendo esta suscribirse a las actualizaciones de un website. Una de los casos donde es bastante util es en ebay. Con los webslides podemos ver de manera facil y si estar actualizando la ventana de ebay los cambios que esta teniendo el producto al cual nos hemos suscribido. La misma caracteristica tambien se puede usar en facebook y otros portales.

    Video

    Este primer beta del internet explorer esta orientado mas como dije al principio a diseñadores y desarrolladores web, muchos portales no se podran ver de manera correcta debido a los cambios en el motor de renderizacion que nos trae IE8. Gracias a Dios y a Microsoft se creo la opcion para emular el IE7 y usar el motor anterior al IE8. Asi que hay que esperar los nuevos cambios y retos que nos traera microsoft con el internet explorer y no desesperarze y juzgar antes de tiempo como han hechos muchos que ya han catalogado al internet explorer 8 como una decepcion total, al parecer se les ha olvidado el significado de Beta y se dejan llevar por el odio despiadado hacia microsoft dejando asi de ser objectivos :P, espero que tambien analizen otras compañias donde a mi entender tienen una pecera de Pez Beta estando casi todos sus productos por mas de 2 y 3 años en fase beta.

    Saludos y bendiciones!!! ;)

    SQLTableHistory es una utilidad que hicimos junto a un compañero que nos permite llevar un rastro de auditoria de tablas especificas que podemos seleccionar desde la aplicacion, mantiendo asi un registro de cada accion(insertar, actualizar, eliminar) que involucre las tablas que se le quiera hacer la auditoria.

    Requerimientos
    • .Net Framework 3.5
    • Sql Server 2000-2005

    Arquitectura

    La aplicacion consta de de una sola tabla llamada AUDIT donde guarda cada uno de los registros de las tablas, guardando asi el nombre de la tabla, nombre de la columna que fue afectada el valor anterior y el valor nuevo de la columna, el usuario de la transaccion, fecha y  asi tambien el tipo de transaccion que fue realizada(insertar, actualizar, eliminar).

    Para ser posible esto, la utilidad nos crea tres triggers por cada una de las tablas, uno para insertar, actualizar e eliminar.

    tableaudit

    Script:

    Tabla Audit:

    /****** Object:  Default [DF_Audit_Date]    Script Date: 02/22/2008 19:27:40 ******/
    IF  EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[DF_Audit_Date]') AND type = 'D')
    BEGIN
    ALTER TABLE [dbo].[Audit] DROP CONSTRAINT [DF_Audit_Date]

    END
    GO
    /****** Object:  Table [dbo].[Audit]    Script Date: 02/22/2008 19:27:40 ******/
    IF  EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[Audit]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
    DROP TABLE [dbo].[Audit]
    GO
    /****** Object:  Table [dbo].[Audit]    Script Date: 02/22/2008 19:27:40 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[Audit]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
    BEGIN
    CREATE TABLE [dbo].[Audit](
        [AuditID] [int] IDENTITY(1,1) NOT NULL,
        [Table] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        [Column] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        [OldValue] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
        [NewValue] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
        [UserID] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
        [Date] [datetime] NOT NULL,
        [Type] [int] NOT NULL,
    CONSTRAINT [PK_Audit] PRIMARY KEY CLUSTERED
    (
        [AuditID] ASC
    )
    )
    END
    GO
    /****** Object:  Default [DF_Audit_Date]    Script Date: 02/22/2008 19:27:40 ******/
    IF Not EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[DF_Audit_Date]') AND type = 'D')
    BEGIN
    ALTER TABLE [dbo].[Audit] ADD  CONSTRAINT [DF_Audit_Date]  DEFAULT (getdate()) FOR [Date]

    END
    GO

     

    Tabla AuditType:

    /****** Object:  Table [dbo].[AuditType]    Script Date: 02/22/2008 19:35:13 ******/
    IF  EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[AuditType]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
    DROP TABLE [dbo].[AuditType]
    GO
    /****** Object:  Table [dbo].[AuditType]    Script Date: 02/22/2008 19:35:13 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[AuditType]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
    BEGIN
    CREATE TABLE [dbo].[AuditType](
        [AuditTypeID] [int] NOT NULL,
        [Name] [varchar](20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    CONSTRAINT [PK_AuditType] PRIMARY KEY CLUSTERED
    (
        [AuditTypeID] ASC
    )
    )
    END
    GO

    Y debemos tener estos tres valores por default en nuestra base de datos:
    INSERT [dbo].[AuditType] ([AuditTypeID], [Name]) VALUES (1, convert(text, N'Agregar' collate SQL_Latin1_General_CP1_CI_AS))
    INSERT [dbo].[AuditType] ([AuditTypeID], [Name]) VALUES (2, convert(text, N'Remover' collate SQL_Latin1_General_CP1_CI_AS))
    INSERT [dbo].[AuditType] ([AuditTypeID], [Name]) VALUES (3, convert(text, N'Modificar' collate SQL_Latin1_General_CP1_CI_AS))


    Clases

    Usando Linq to SQL y a la vez el Designer, tenemos las siguientes clases:

    clasese

    Donde:

    SysTable: es la clase que contiene todas las tablas de nuestra base de datos seleccionada, se conecta a la tabla sys.tables

    Table: clase que contiene el schema de las tablas, se conecta a la tabla INFORMATION_SCHEMA.TABLES

    Trigger: es la clase que contiene los triggers de la base de datos, se usa la tabla del sistema sys.triggers

    Column: clase que contiene el schema de las columnas de cada tabla de nuestra base de datos, para obtener esto se usa la tabla del sistema INFORMATION_SCHEMA.COLUMNS

    Si se fijan para todo esto usamos tablas del sistema, ya que estas nos pueden proveer el schema de las tablas y poder asi crear los triggers de una manera dinamica.

    Deben configurar el archivo app.config en la cadena de conexion y espeficiar el connectionstring correspondiente a su base de datos... en un futuro lo pondre para que se pueda hacer de manera mas dinamica.

    Si les interesa pueden descargar el codigo fuente y asi poder echarle una miradita al codigo.

    Preview de la utilidad:

    app

    Espero que les sea de utilidad.

    Con la llegada de Windows Vista Service pack microsoft corregira muchos de los errores reportados por un gran numero de usuarios (entre los que me incluyo), tales como:

    • Escalabilidad
    • Seguridad
    • Rendimiento
    • Soporte de nuevos estandares
    • otros

    Para mas detalle pueden ver la entrada que hizo Joshua Saenz en este enlace. Pero para tener todas estas nuevas bondades que nos trae nuestro amigo Vista y poder descargarlo desde Windows update tenemos que esperar hasta mediados de marzo.

    Si tienes la fiebre como yo de poder tener el Service pack 1 instalado desde ya, hemos visto esta entrada en el blog The .Net Aficionado en la cual se publico una porcion de codigo que nos habilita la descarga via Windows Update del Service pack 1. Puedes copiar y pegar este codigo en un archivo .cmd y correrlo (logicamente si lo corres es bajo riesgo propio)

     

    @echo off

    reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\VistaSp1 /f > NUL 2>&1
    reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\WindowsUpdate\VistaSP1 /f > NUL 2>&1

    reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\VistaSp1 /v Beta1 /t REG_SZ /d dcf99ef8-d784-414e-b411-81a910d2761d /f
    IF NOT %errorlevel% == 0 ( goto ERROR)

    :SUCCESS
    @echo.
    echo ===========================================================
    echo  Windows Vista SP1 registry key has been set successfully.
    echo  Please check for updates in Windows Update.
    echo ===========================================================
    @echo.
    goto END

    :ERROR
    @echo.
    echo ===========================================================
    echo  FAILED to set Windows Vista SP1 registry keys.
    echo  Please run this script by right clicking and selecting
    echo  "Run as Administrator".
    echo ===========================================================
    @echo.
    goto END

    :END
    pause

    Espero que les sea de utilidad.

    Luego de la presentación sobre LINQ, despertamos y lo primero que vemos es una tremenda noticia, microsoft ofrece por yahoo la modica suma de $44.600 millones de dólares. lo referente a 31 dólares por acción, un 62% del valor que tenían los títulos a día de ayer.

    Es una tremenda oferta ya que todos hemos podido ver como en los ultimos meses las acciones de yahoo se han desplomado, esta oferta ha provocado que las acciones de yahoo suban en mas de un 59%.

    Creo la posible fusion entre yahoo y microsoft, provocaria un fuerte binomio que atentaria con la supremacia total que tiene google en la red.

    Esperemos a ver como se desenvuelve esta noticia.

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/fondo1.gif

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/logo.gifhttp://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/fondo2.gif

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/trans.gif

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/top_msdn.jpg

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/top_msdnTour.jpg

    http://www.microsoft.com/costarica/envios/imagestnb/aspnetlinq.jpg

    ¿Qué es ASP .NET Provider?

    Probablemente uno de los mayores beneficios que puede dar ASP .NET es el sistema de profiles, el cual permite mantener la data sobre los visitantes a su Web Site (sea este anónimo o no). El sistema anónimo de Profiles que es provisto por ASP.NET 2.0 puede ser utilizado en la mayoría de los Websites.
    ASP.NET 2.0 usa un modelo llamado "Provider Model" que permite el reemplazo o la extensión de su implementación para ajustarse al diseño y especificaciones de su WebSite. En esta sección veremos ejemplos concretos de cómo poner a trabajar esta importante herramienta la cual le ahorrará muchas horas de programación con la implementación de dicho modelo.

    ¿Qué es "LINQ"?

    Modelo de programación y diseño alrededor de la unificación de acceso de datos.
    LINQ apunta a reducir la complejidad para los desarrolladores y ayudar a aumentar su productividad a través de un conjunto de extensiones para lenguajes de programación de Visual Basic y C#, así como Microsoft .NET Framework que proporcionan consultas integradas a objetos, bases de datos y datos XML. Al utilizar LINQ, los desarrolladores podrán escribir consultas de forma nativa en C# o Visual Basic sin tener que utilizar lenguajes especializados, como los lenguaje de consulta estructurado (SQL) y XPath.

    Nivel de la Charla: Intermedio (200)

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/boton_naranja_info.jpghttp://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/boton_naranja_recomiendalo.jpghttp://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/boton_naranja_registrese.jpg

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/trans.gif

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/agenda.jpg

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/trans.gif

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/flecha.gif

    Fecha:

    Jueves, 31 de Enero de 2008

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/flecha.gif

    Horario:

    6:00 p.m. - 7:00 p.m. (ASP .NET PROVIDER)
    7:00 P.M. - 8:00 p.m. (LINQ)

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/flecha.gif

    Lugar :

    Fundación Global Democracia y Desarrollo

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/flecha.gif

    Salón:

    Auditorio

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/flecha.gif

    Dirección:

    c/ Capitan Eugenio de Marchena # 26
    La Esperilla, Santo Domingo Republica Dominicana

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/flecha.gif

    Información:

    1-888-751-2323 (libre de cargos excepto desde teléfonos celulares)http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/trans.gif

    En este evento serán entregados todos los premios y libros prometidos en el evento "Lo Mejor de 2007!!" de Diciembre pasado.
    Reserve su espacio a tiempo. Cupo Limitado.

    http://www.microsoft.com/costarica/images_mails/imagesTech_MSDN/logo_fund.jpg

     

    Estaremos dando la charla de Linq, te esperamos!!!!

    Publicado 29/1/2008 15:07 por Esteban Zavala | 1 comment(s)
    Archivado en:

    Luego de el paso de la Tormenta Noel en nuestro país, los labores deben seguir, pues el pasado viernes tuvimos una pequeña Charla
    titulada “Mi primer Juego con XNA” en la universidad autónoma de Santo Domingo, esto para cubrir todo el calendario de University Tour e Imagine Cup.

    En la chara tuvimos como agenda:

    • Que es XNA
    • Componentes de un Juego
    • Introduccion a los Sprites y Animaciones
    • Demo
    • Preguntas y Respuestas

    Tomamos como ejemplo los webcast que hizo Edgar Sanchez para MSDN Media Center

     

    El Señor Gilberto Molina gerente de relaciones academicas para Microsoft

    photo-14photo-18

     

    photo-20photo-21

     

     photo-19 photo-22

    photo-23photo-30

    photo-31 photo-32

     

    Para descargar el codigo de la session aqui.

    Publicado 8/11/2007 17:05 por Esteban Zavala | con no comments
    Archivado en: ,

    Luego de un largo descanso por unas largas y merecidas vacaciones y de no aparecerme por estos alrededores queria hacer uso de este medio para pedirle a todos los geeks que nos visitan, que ayuden a la Republica Dominicana. Hace una semana  nuestro bello pais fue envestido por la tormenta Noel dejando en saldo mas de 84 personas muertas y a la vez muchisimos desaparecidos, esta tormenta nos agarro de forma repentina dejando asi daños incalculabes a nuestra nacion.

     Tormenta Noel

     

     Quiero pedirles por favor que se acerquen a la embajada Dominicana de sus respectivos paises y ayuden a esta noble causa, ya sea con Dinero, Comida, Ropa, Etc, se que sera de gran ayuda para nosotros.
    Gracias de antemano
     

    Publicado 7/11/2007 14:09 por Esteban Zavala | 1 comment(s)
    Archivado en:

    Primero quería pedir mis disculpas porque tenía tantas ganas de postear, pero he estado requeté ocupado
    proyectos en la oficina, algunos pendientes por afuera pa el "picoteo" como decimos aquí :P y sobre todo estudiando para certificarme
    por cierto ya soy MCTS Windows y Web el examen que tome fue el 70-526.

    Manos a la obra…

    Hace tiempo, un cliente nos pidió un FileUpload, pues que fácil no!!! Pero uno de los requerimientos del mismo era que
    tenía que incluir un progress Bar, pues yo rompiéndome la cabeza y sin saber qué hacer, encontré una solución.

    Consiste en un simple UserControl con un FIleUpload y un botón, con el siguiente código de declaración:

    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="Uploader.ascx.cs" Inherits="Uploader" %>

    <asp:FileUpload ID="upUserCtrl" runat="server" />

    <asp:Button ID="btnUpload" runat="server" OnClick="btnUpload_Click" Text="Upload" />

    En el CodeBehind, tenemos dos funciones javascripts, una para imprimir el progress bar y otra por supuesto para eliminar cuando el archivo ya se haya guardado
    en nuestra carpeta o BD, como la quieran guardar.

    Aquí les dejo el código completo:

    using System;

    using System.Data;

    using System.Configuration;

    using System.Collections;

    using System.Web;

    using System.Web.Security;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    using System.Web.UI.WebControls.WebParts;

    using System.Web.UI.HtmlControls;

    using System.Text;

    using System.Threading;

    public partial class Uploader : System.Web.UI.UserControl

    {

    //

    public string strLocation = "c:\\Geeks\\progressBar";

    protected void Page_Load(object sender, EventArgs e)

    {

    }

    //Codigo JavaScript para Imprimir el Progres

    public static void Imprimir()

    {

    StringBuilder sb = new StringBuilder();

    sb.Append("<div id='updiv' style='Font-weight:bold;font-size:11pt;Left:320px;COLOR:black;font-family:verdana;Position:absolute;Top:140px;Text-Align:center;'>");

    sb.Append("&nbsp;<script> var up_div=document.getElementById('updiv');up_div.innerText='';</script>");

    sb.Append("<script language=javascript>");

    sb.Append("var dts=0; var dtmax=10;");

    sb.Append("function ShowWait(){var output;output='Espere mientras se carga el archivo!';dts++;if(dts>=dtmax)dts=1;");

    sb.Append("for(var x=0;x < dts; x++){output+='';}up_div.innerText=output;up_div.style.color='red';}");

    sb.Append("function StartShowWait(){up_div.style.visibility='visible';ShowWait();window.setInterval('ShowWait()',100);}");

    sb.Append("StartShowWait();</script>");

    HttpContext.Current.Response.Write(sb.ToString());

    HttpContext.Current.Response.Flush();

    }

    //Codigo javascript para borrar el progressbar

    public static void Clear()

    {

    StringBuilder sbc = new StringBuilder();

    sbc.Append("<script language='javascript'>");

    sbc.Append("alert('Se ha completado correctamente!');");

    sbc.Append("up_div.style.visibility='hidden';");

    sbc.Append("history.go(-1)");

    sbc.Append("</script>");

    HttpContext.Current.Response.Write(sbc);

    }

    protected void btnUpload_Click(object sender, EventArgs e)

    {

    string strFileName = System.IO.Path.GetFileName(upUserCtrl.PostedFile.FileName);

    try

    {

    if (strFileName != "")

    {

    //Imprimir el ProgressBar

    Imprimir();

    upUserCtrl.PostedFile.SaveAs(strLocation + strFileName);

    Thread.Sleep(2000);

    Clear();

    }

    }

    catch(Exception ex)

    {

    Response.Write(ex.Message);

    }

    }

    }

    Bueno y logicamente llamamos nuestro userControl desde una pagina .aspx, en este caso llamemosla Default.aspx

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

    <%@ Register Src="Uploader.ascx" TagName="Uploader" TagPrefix="uc1" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml" >

    <head id="Head1" runat="server">

    <title>Geeks Bar</title>

    </head>

    <body>

    <form id="form1" runat="server">

    <div>

    <uc1:Uploader ID="Uploader1" runat="server" />

    </div>

    </form>

    </body>

    </html>

    Espero le sea de utilidad.

    Update:

    Por peticion, un lector nos pidio que hicieramos el codigo en VB.

    Aqui esta el codigo 

     

    <%@ Control Language="VB" AutoEventWireup="true" CodeFile="Uploader.ascx.vb" Inherits="Uploader" %>

    <asp:FileUpload ID="upUserCtrl" runat="server" />

    <asp:Button ID="btnUpload" runat="server" OnClick="btnUpload_Click" Text="Upload" /> 

     

    Imports System

    Imports System.Data

    Imports System.Configuration

    Imports System.Collections

    Imports System.Web

    Imports System.Web.Security

    Imports System.Web.UI

    Imports System.Web.UI.WebControls

    Imports System.Web.UI.WebControls.WebParts

    Imports System.Web.UI.HtmlControls

    Imports System.Text

    Imports System.Threading

    Partial Public Class Uploader

    Inherits System.Web.UI.UserControl

    Public strlocation As String = "C:\\Geeks\\progressbar"

     

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    End Sub

    'Codigo Javascript para Imprimir el Progress

    Public Sub Imprimir()

    Dim sb As New StringBuilder()

    sb.Append("<div id='updiv' style='Font-weight:bold;font-size:11pt;Left:320px;COLOR:black;font-family:verdana;Position:absolute;Top:140px;Text-Align:center;'>")

    sb.Append("&nbsp;<script> var up_div=document.getElementById('updiv');up_div.innerText='';</script>")

    sb.Append("<script language=javascript>")

    sb.Append("var dts=0; var dtmax=10;")

    sb.Append("function ShowWait(){var output;output='Espere mientras se carga el archivo!';dts++;if(dts>=dtmax)dts=1;")

    sb.Append("for(var x=0;x < dts; x++){output+='';}up_div.innerText=output;up_div.style.color='red';}")

    sb.Append("function StartShowWait(){up_div.style.visibility='visible';ShowWait();window.setInterval('ShowWait()',100);}")sb.Append("StartShowWait();</script>")

    HttpContext.Current.Response.Write(sb.ToString())

    HttpContext.Current.Response.Flush()

    End Sub

    'Codigo javascript para borrar el progressbar

    Public Sub Clear()

    Dim sbc As New StringBuilder()

    sbc.Append("<script language='javascript'>")

    sbc.Append("alert('Se ha completado correctamente!');")

    sbc.Append("up_div.style.visibility='hidden';")

    sbc.Append("history.go(-1)")

    sbc.Append("</script>")

    HttpContext.Current.Response.Write(sbc)

    End Sub

    Protected Sub btnUpload_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnUpload.Click

    Dim strFileName As String = System.IO.Path.GetFileName(upUserCtrl.PostedFile.FileName)

    Try

    If strFileName <> "" Then

    'Imprimir el ProgressBar

    Imprimir()

    upUserCtrl.PostedFile.SaveAs(strLocation + strFileName)

    Thread.Sleep(2000)

    Clear()

    End If

    Catch ex As Exception

    Response.Write(ex.Message)

    End Try

    End Sub

    end Class

     

    <%@ Page Language="VB" AutoEventWireup="true" CodeFile="Default.aspx.VB" Inherits="_Default" %>

    <%@ Register Src="Uploader.ascx" TagName="Uploader" TagPrefix="uc1" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml" >

    <head id="Head1" runat="server">

    <title>Geeks Bar</title>

    </head>

    <body>

    <form id="form1" runat="server">

    <div>

    <uc1:Uploader ID="Uploader1" runat="server" />

    </div>

    </form>

    </body>

    </html>

     Espero que le sea de utilidad

     

    Publicado 22/7/2007 0:13 por Esteban Zavala | 31 comment(s)
    Archivado en:

    Mi primer post.... que grata noticia al leer en mi email "Bienvenido a Geeks.ms", siendo sincero tengo mucho tiempo dandole seguimiento a esta grandiosa comunidad y leyendo articulos interesantisimo de Rodrigo Corral, Jorge Serrano, Percey Reyes y un sin numero mas de personas que hacen que esta sea una referencia casi obligatoria(Por no decir obligatoria) para toda la comunidad de hispanohablante.

    Quien Soy?... soy un joven de 22 años de edad procedente de la Republica Dominicana, apolitico, amante de la programacion, ejerciendola mas por hobby que por oficio , estoy desde los 16 años programando desde Delphi, Vb6 y actualmente en vb.net, asp.net y C# siendo este ultimo mi lenguaje favorito, tambien he trabajo con ajax, javascript, desarrollo de modulos y skins para dotnetnuke y otras tantas cosas.

    Saludos y manos a la obra!!!!

    Publicado 12/6/2007 22:03 por Esteban Zavala | 6 comment(s)
    Archivado en: