2008-09-30 35 views
21

Estoy tratando de usar WebClient para descargar un archivo de la web usando una aplicación WinForms. Sin embargo, realmente solo quiero descargar un archivo HTML. Cualquier otro tipo que desee ignorar.¿Cómo verificar si System.Net.WebClient.DownloadData está descargando un archivo binario?

Miré WebResponse.ContentType, pero su valor es siempre null.

¿Alguien tiene alguna idea de cuál podría ser la causa?

+0

Do ¿Quieres imágenes, hojas de estilo y JavaScript? –

Respuesta

53

Dado su actualización, puede hacer esto cambiando el.Método en GetWebRequest:

using System; 
using System.Net; 
static class Program 
{ 
    static void Main() 
    { 
     using (MyClient client = new MyClient()) 
     { 
      client.HeadOnly = true; 
      string uri = "http://www.google.com"; 
      byte[] body = client.DownloadData(uri); // note should be 0-length 
      string type = client.ResponseHeaders["content-type"]; 
      client.HeadOnly = false; 
      // check 'tis not binary... we'll use text/, but could 
      // check for text/html 
      if (type.StartsWith(@"text/")) 
      { 
       string text = client.DownloadString(uri); 
       Console.WriteLine(text); 
      } 
     } 
    } 

} 

class MyClient : WebClient 
{ 
    public bool HeadOnly { get; set; } 
    protected override WebRequest GetWebRequest(Uri address) 
    { 
     WebRequest req = base.GetWebRequest(address); 
     if (HeadOnly && req.Method == "GET") 
     { 
      req.Method = "HEAD"; 
     } 
     return req; 
    } 
} 

Como alternativa, se puede comprobar el encabezado cuando anulando GetWebRespons(), tal vez lanzar una excepción si no es lo que quería:

protected override WebResponse GetWebResponse(WebRequest request) 
{ 
    WebResponse resp = base.GetWebResponse(request); 
    string type = resp.Headers["content-type"]; 
    // do something with type 
    return resp; 
} 
+2

No olvide XHTML: http://www.w3.org/TR/xhtml-media-types/#application-xhtml-xml – bzlm

0

¿Podría emitir la primera solicitud con el verbo HEAD y verificar el encabezado de respuesta de tipo de contenido? [editar] Parece que tendrás que usar HttpWebRequest para esto.

+0

(obsoleto por el seguimiento de OP - vea mi otra respuesta sobre GetWebRequest) –

1

WebResponse es una clase abstracta y la propiedad ContentType se define en clases heredadas. Por ejemplo, en el objeto HttpWebRequest este método está sobrecargado para proporcionar el encabezado de tipo de contenido. No estoy seguro de qué instancia de WebResponse utiliza el WebClient. Si SOLO desea archivos HTML, lo mejor que puede hacer es usar el objeto HttpWebRequest directamente.

0

Su pregunta es un poco confusa: si está utilizando una instancia de la clase Net.WebClient, Net.WebResponse no entra en la ecuación (aparte del hecho de que es de hecho una clase abstracta, y estaría usando una implementación concreta como HttpWebResponse, como se señala en otra respuesta).

De todos modos, cuando se utiliza cliente Web, se puede lograr lo que quiere haciendo algo como esto:

Dim wc As New Net.WebClient() 
Dim LocalFile As String = IO.Path.Combine(Environment.GetEnvironmentVariable("TEMP"), Guid.NewGuid.ToString) 
wc.DownloadFile("http://example.com/somefile", LocalFile) 
If Not wc.ResponseHeaders("Content-Type") Is Nothing AndAlso wc.ResponseHeaders("Content-Type") <> "text/html" Then 
    IO.File.Delete(LocalFile) 
Else 
    '//Process the file 
End If 

Tenga en cuenta que usted tiene que comprobar la existencia de la cabecera Content-Type, que el servidor es no se garantiza que lo devuelva (aunque la mayoría de los servidores HTTP modernos siempre lo incluirán). Si no hay encabezado Content-Type presente, puede recurrir a otro método de detección HTML, por ejemplo, abrir el archivo, leer los primeros 1K caracteres o menos en una cadena y ver si contiene la subcadena html >

También tenga en cuenta que esto es un poco derrochador, ya que siempre transferirá el archivo completo, antes de decidir si lo quiere o no. Para solucionarlo, cambiar a las clases Net.HttpWebRequest/Response puede ayudar, pero si el código adicional lo vale depende de su aplicación ...

0

Pido disculpas por no haber sido muy claro. Escribí una clase contenedora que extiende WebClient. En esta clase de contenedor, agregué el contenedor de cookies y expuse la propiedad de tiempo de espera para WebRequest.

Estaba usando DownloadDataAsync() de esta clase de contenedor y no pude recuperar el tipo de contenido de WebResponse de esta clase contenedora. Mi intención principal es interceptar la respuesta y determinar si es de naturaleza text/html. Si no es así, abortaré esta solicitud.

Logré obtener el tipo de contenido después de anular el método WebClient.GetWebResponse (WebRequest, IAsyncResult).

La siguiente es una muestra de mi clase de contenedor:

public class MyWebClient : WebClient 
{ 
    private CookieContainer _cookieContainer; 
    private string _userAgent; 
    private int _timeout; 
    private WebReponse _response; 

    public MyWebClient() 
    { 
     this._cookieContainer = new CookieContainer(); 
     this.SetTimeout(60 * 1000); 
    } 

    public MyWebClient SetTimeout(int timeout) 
    { 
     this.Timeout = timeout; 
     return this; 
    } 

    public WebResponse Response 
    { 
     get { return this._response; } 
    } 

    protected override WebRequest GetWebRequest(Uri address) 
    { 
     WebRequest request = base.GetWebRequest(address); 

     if (request.GetType() == typeof(HttpWebRequest)) 
     { 
      ((HttpWebRequest)request).CookieContainer = this._cookieContainer; 
      ((HttpWebRequest)request).UserAgent = this._userAgent; 
      ((HttpWebRequest)request).Timeout = this._timeout; 
     } 

     this._request = request; 
     return request; 
    } 

    protected override WebResponse GetWebResponse(WebRequest request) 
    { 
     this._response = base.GetWebResponse(request); 
     return this._response; 
    } 

    protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result) 
    { 
     this._response = base.GetWebResponse(request, result); 
     return this._response; 
    } 

    public MyWebClient ServerCertValidation(bool validate) 
    { 
     if (!validate) ServicePointManager.ServerCertificateValidationCallback += delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; }; 
     return this; 
    } 
} 
+0

En ese caso, cambie .Method - vea mi otra respuesta. –

3

No estoy seguro de la causa, pero quizás aún no has descargado nada. Esta es la manera perezosa para obtener el tipo de contenido de un archivo/página remota (no he comprobado si esto es eficiente en el alambre. Por lo que sé, se puede descargar enormes trozos de contenido)

 Stream connection = new MemoryStream(""); // Just a placeholder 
     WebClient wc = new WebClient(); 
     string contentType; 
     try 
     { 
      connection = wc.OpenRead(current.Url); 
      contentType = wc.ResponseHeaders["content-type"]; 
     } 
     catch (Exception) 
     { 
      // 404 or what have you 
     } 
     finally 
     { 
      connection.Close(); 
     } 
Cuestiones relacionadas