Descarga de Archivos utilizando WebRequest y WebResponse Fecha: 30/Oct/2004 (28 Octubre 2004)
|
Contenido
Introducción
Creando las Clases
Desmenuzando las clases
Llamando el componente
Conclusión
Introducción
Día con día las aplicaciones apuntan hacía la revolución que sigue siendo Internet, esto nos ha llevado a utilizar este recurso como una funcionalidad ya sea para descargar actualizaciones, sincronizar información, actualización de catálogos etc. Aun cuando esto lo podemos lograr utilizando por ejemplo WebServices no siempre la implementación de estas tecnologías depende completamente de nosotros obligándonos a utilizar otro medio de interacción para lograr la funcionalidad requerida.
.Net Framework nos proporciona clases para poder trabajar con recursos de red
System.Net el cual nos proporciona clases que encapsulan la funcionalidad de la mayoría de los protocolos y servicios que actualmente se manejan en Internet http, ftp, dns, autenticación etc.
System.Net.Sockets que es una implementación de los sockets de windows, pero a diferencia System.Net este no proporciona ninguna clase directa para el manejo de los protocolos actuales (http,ftp.https), con lo cual toda la interacción con ellos deberá ser programada completamente.
Del espacio de nombres System.Net se desprenden las clases WebRequest y WebResponse las cuales proporcionan la funcionalidad necesaria para conectarse y obtener información común de la mayoría de los protocolos conectables (http, https, ftp) , si se necesitará obtener información especifica de un determinado protocolo se pueden utilizar sus clases derivadas como HttpWebRequest la cual administra los detalles de una conexión http (propiedades del tipo Refer o Host por ejemplo)
Creando las Clases
Para la realización de nuestro componente utilizaremos 4 clases:
DescargaArchivo Será el punto de entrada de nuestra componente, la cual expondrá todas las propiedades y métodos necesarios para realizar la descarga de un archivo vía HTTP
Autentificación Proporciona la clase NetworkCredentials que nos permitirá enviar las credenciales correspondientes del usuario en caso de que el usuario necesite estar autentificado.
Proxy Proporciona la clase WebProxy la cual es necesaria en caso de tener salida a la red a través de un Proxy.
ProgresoEventArgs Proporciona los argumentos que contendrá el evento Progreso, el cual nos indicara el numero de bytes que se han sido descargados
Desmenuzando las clases
Declaración del método principal
public void Descargar()
{
try
{
//Igualo las propiedades al valor original por si no han sido inicializadas y originen su propio error.
this.direccionArchivo = this.direccionArchivo;
this.guardarEn = this.guardarEn;
La clase WebRequest es la encargada de procesar la solicitud del recurso, dado que es una clase abstracta se debe de utilizar el método “Create(uri)” para poder crear una instancia. En nuestro caso el URI es la dirección de Internet del archivo a descargar.
//Se inicializa la petición
WebRequest WRPeticion = WebRequest.Create(_direccionArchivo);
Antes de realizar la solicitud al recurso, es posible que se tenga que configurar la autentificación del servidor al cual se esta realizando la petición. También de igual manera puede ser necesario realizar la configuración de un Proxy en caso de que la aplicación necesite utilizar alguno para acceder a Internet.
En esta sección de código se verifica si es necesario utilizar un Proxy.
//Asigna el proxy
if (this.requiereProxy)
{
WRPeticion.Proxy = _Proxy.WebProxy;
}
En caso de que la propiedad “RequiereProxy” sea verdadera, con anterioridad debió inicializar la propiedad “WebProxy” que a su vez regresa una instancia de nuestra clase Proxy mediante la cual se crea la clase WebProxy correspondiente
public Proxy WebProxy()
{
return _Proxy;
}
La única propiedad requerida de la clase WebProxy es “Direccion” la cual debe ser una dirección URI valida (“http://www.neo-mx.com”), la comprobación se puede realizar utilizando la clase URI la cual será asignada a la propiedad “Address” de la clase “WebProxy”
public class Proxy
{
WebProxy _proxy;
string _direccion = "";
string _password = "";
string _usuario = "";
public Proxy(){_proxy = new WebProxy();}
public WebProxy WebProxy
{
get
{
try
{
this.Direccion = this.Direccion;
_proxy.Address = new Uri(this.Direccion);
En caso de que nuestro Proxy necesite autentificación es necesario utilizar la clase NetworkCredential, especificando un usuario y un password en las propiedades correspondientes de la clase Proxy (Proxy.Usuario, Proxy.Password) aunque este último puede ser una cadena vacía
if (_usuario != "")
{
_proxy.Credentials = new NetworkCredential(_usuario,_password);
}
}
En caso de que el recurso al cual queremos acceder necesite autentificación entonces el procedimiento será similar.
//Asigna las credenciales
if (this.requiereAutentificacion)
{
WRPeticion.Credentials = _Autentificacion.networkCredential;
}
La diferencia es que en este caso la clase que es instanciada es “Autentificación” a través de la propiedad “WebAutentificacion”
public Autentificacion WebAutentificacion()
{
return _Autentificacion;
}
La clase “Autentificacion” crea una clase NetworkCredentials
public NetworkCredential networkCredential
{
get
{
try
{
this.Usuario = this.Usuario;
return new NetworkCredential(this.Usuario,this.Password);
}
catch(Exception ex)
{
throw new Exception(ex.Message,ex);
}
}
}
Ya que nuestra clase “WebRequest” ha sido configurada correctamente se realiza la solicitud al servidor utilizando el método “GetResponse”, este método contiene la respuesta de la solicitud del recurso la cual tiene que ser asignado a una clase WebResponse la cual será la encargada de obtener la secuencia de información correspondiente.
//Obtengo la respuesta
WebResponse WRRespuesta = WRPeticion.GetResponse();
Dependiendo del tipo de archivo seleccionado basándose en la enumeración “eTipoArchivo” (Binario o Texto) se guardara la información pero utilizando su secuencia correspondiente
//Dependiendo del tipo de archivo se llama a la función
if (this.tipoArchivo == (int)eTipoArchivo.Binario)
{
this.archivoBinario(ref WRRespuesta);
}
else
{
this.archivoTexto(ref WRRespuesta);
}
Si el tipo de archivo seleccionado es Binario, entonces llamaremos al método “archivoBinario” al cual se le pasa como parámetro el objeto WebResponse creado con anterioridad, se obtiene el tamaño del archivo a través de la propiedad ContentLength, el cual posteriormente se enviara como parte de los argumentos del evento “Progreso”
Se crea una matriz de 1024 bytes, dentro del cual se ira almacenando de manera progresiva la respuesta de la secuencia de información recibida de la clase WebResponse
private void archivoBinario(ref WebResponse WRRespuesta)
{
try
{
long tamañoArchivo = WRRespuesta.ContentLength;
byte[] Buffer = new byte[1024];
int intBytesLeidos = 0;
_bitesRecibidos = 0;
Debido a que la secuencia a recibir será binaria, se crean dos clases BinaryReader y BinaryWriter.
BinaryReader será la encargada de obtener la secuencia de datos, esta es obtenida a través del método “GetResponseStream” de la clase WebResponse
BinaryWriter por su parte, guardara la secuencia obtenida del BinaryReader en un archivo especificado utilizando la clase FileStream, la ruta del archivo a guardar la tomara de la propiedad “guardarEn”,
BinaryReader BRRespuesta = new BinaryReader(WRRespuesta.GetResponseStream());
BinaryWriter BWEscritorBin = new BinaryWriter(new FileStream(this.guardarEn,FileMode.Create,FileAccess.Write,FileShare.None));
Se invocara al método “Read” de la clase BinaryReader, este método lee de la secuencia y el resultado lo almacenara en el buffer de bytes previamente definido, el resultado será el numero de bytes leídos de la secuencia.
Si el número de bytes leídos es mayor a cero, entonces se guardara la secuencia guardada en el buffer, para esto se utiliza la propiedad “Write” de la clase BinaryWriter.
Una vez que es guardada la secuencia del buffer se invoca al evento “Progreso”, este evento envía la clase ProgresoEventArgs, la cual contiene la definición de los argumentos del evento que son el número de bytes recibidos hasta el momento y el número total de bytes del archivo.
Este proceso es repetido hasta que se lee por completo la secuencia desde el BinaryReader
intBytesLeidos = BRRespuesta.Read(Buffer,0,1024);
while (intBytesLeidos > 0 != this.cancelaDescarga)
{
//Guardo la información en el archivo
BWEscritorBin.Write(Buffer,0,intBytesLeidos);
_bitesRecibidos += intBytesLeidos;
ProgresoEventArgs e = new ProgresoEventArgs(_bitesRecibidos,tamañoArchivo);
OnProgreso(e);
intBytesLeidos = BRRespuesta.Read(Buffer,0,1024);
}
BWEscritorBin.Close(); //Cerramos la conexión
Llamando al componente
El código de ejemplo incluye un proyecto mediante el cual es utilizado el componente creado.
Este cliente utiliza toda la funcionalidad de la clase DescargaArchivo
Si quiere conocer el proceso de descarga es necesario ligar el evento “Progreso” , con el cual podríamos por ejemplo crear una barra de progreso que nos indique el porcentaje de descarga del archivo.
private void btnDescargar_Click(object sender, System.EventArgs e)
{
try
{
objDescarga.tipoArchivo = (int) cboTipoArchivo.SelectedIndex;
objDescarga.Progreso += new ProgresoEventHandler(objDescarga_Progreso);
objDescarga.Descargar();
MessageBox.Show("Terminado","Información del sistema",MessageBoxButtons.OK,MessageBoxIcon.Information);
}
private void objDescarga_Progreso(object sender, ProgresoEventArgs e)
{
try
{
PBProgreso.Maximum = (int) e.BytesTotales;
PBProgreso.Value = (int) e.BytesRecibidos;
}
Conclusión
La clases WebRequest y WebResponse representan un poderoso mecanismo de comunicación con la mayoría de los protocolos conectables (HTTP,HTTPS,FTP),
Aunque para la descarga de archivos existe la clase WebClient esta de igual manera utiliza la clase WebRequest para acceder al recurso solicitado, la descarga de archivos no es el único fin que tienen estas clases ya que pueden ser útiles en varias circunstancias como la sincronización de información entre servidores Web, acceso a servidores Ftp, descarga de paginas Web etc.
Fichero con el código de ejemplo: neo_mx_DescargaArchivos.zip - Tamaño 19 KB