Como verificar se System.Net.WebClient.DownloadData está baixando um arquivo binário?

StackOverflow https://stackoverflow.com/questions/153451

  •  03-07-2019
  •  | 
  •  

Pergunta

Eu estou tentando usar WebClient para baixar um arquivo de web usando um aplicativo WinForms. No entanto, eu realmente só quer baixar o arquivo HTML. Qualquer outro tipo I vai querer ignorar.

Eu verifiquei o WebResponse.ContentType, mas o seu valor é sempre null.

Alguém tem alguma idéia do que poderia ser a causa?

Foi útil?

Solução

Dada a sua atualização, você pode fazer isso alterando o .Method em 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, você pode verificar o cabeçalho ao substituir GetWebRespons (), talvez lançar uma exceção se não é o que você queria:

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

Outras dicas

Eu não tenho certeza a causa, mas talvez você não tivesse baixado nada ainda. Esta é a maneira preguiçosa para obter o tipo de conteúdo de um arquivo / página remota (Eu não tenho verificado se este é eficiente no fio. Pelo que sei, ele pode baixar enormes pedaços de conteúdo)

        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();
        }

WebResponse é uma classe abstrata e a propriedade ContentType é definida em herdar classes. Por exemplo, no HttpWebRequest objecto Este método é sobrecarregado para fornecer o cabeçalho do tipo de conteúdo. Eu não tenho certeza do que instância de WebResponse o WebClient está usando. Se pretender apenas arquivos HTML, a sua melhor de usar o objeto HttpWebRequest diretamente.

Você pode emitir o primeiro pedido com o verbo HEAD, e verificar o cabeçalho de resposta tipo de conteúdo? [Editar] Parece que você terá que usar HttpWebRequest para isso, no entanto.

A sua pergunta é um pouco confuso: se você estiver usando uma instância da classe Net.WebClient, o Net.WebResponse não entra na equação (além do fato de que ele é de fato uma classe abstrata, e você' d seja utilizando uma aplicação concreta, tais como HttpWebResponse, como as pontas de outra resposta).

De qualquer forma, ao usar WebClient, você pode conseguir o que você quer, fazendo algo parecido com isto:

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

Note que você tem que verificar a existência do cabeçalho Content-Type, como o servidor não é garantido para devolvê-lo (embora a maioria dos servidores HTTP modernas sempre incluí-lo). Se nenhum cabeçalho Content-Type está presente, você pode cair de volta para outro método de detecção de HTML, por exemplo, abrir o arquivo, ler as primeiras 1K caracteres ou menos em uma string, e ver se que contém o substring

Além disso, note que este é um pouco desperdício, como você vai sempre transferir o arquivo completo, antes de decidir se quer ou não. Para contornar isso, a mudança para as classes Net.HttpWebRequest / resposta pode ajudar, mas se o código extra vale a pena depende da sua aplicação ...

Peço desculpas por não sido muito claro. Eu escrevi uma classe de invólucro que se estende WebClient. Nesta classe de mensagens publicitárias, acrescentei contêiner de cookie e exposto a propriedade tempo limite para o WebRequest.

Eu estava usando DownloadDataAsync () a partir desta classe de mensagens publicitárias e eu não era capaz de recuperar o conteúdo do tipo de WebResponse desta classe wrapper. Minha intenção principal é interceptar a resposta e determinar se a sua de text / html natureza. Se não for, vou abortar este pedido.

Eu consegui obter o tipo de conteúdo após substituindo WebClient.GetWebResponse método (WebRequest, IAsyncResult).

A seguir é um exemplo da minha classe wrapper:

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;
    }
}

Aqui está um método que utiliza TCP, que http é construído em cima de. Ele irá retornar quando ligado ou depois do tempo de espera (milissegundos), então o valor pode precisar de ser alterada dependendo da sua situação

var result = false;
try {
    using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) {
        var asyncResult = socket.BeginConnect(yourUri.AbsoluteUri, 80, null, null);
        result = asyncResult.AsyncWaitHandle.WaitOne(100, true);
        socket.Close();
    }
}
catch { }
return result;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top