Come verificare se System.Net.WebClient.DownloadData sta scaricando un file binario?

Sto cercando di utilizzare WebClient per scaricare un file dal web utilizzando un’applicazione WinForms. Tuttavia, voglio solo scaricare il file HTML. Qualunque altro tipo vorrò ignorare.

Ho controllato il WebResponse.ContentType , ma il suo valore è sempre null .

Qualcuno ha idea di quale potrebbe essere la causa?

Dato il tuo aggiornamento, puoi farlo cambiando il metodo .Method in 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; } } 

In alternativa, puoi controllare l’intestazione quando esegui l’override di GetWebRespons (), magari lanciando un’eccezione se non è ciò che volevi:

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

Non sono sicuro della causa, ma forse non hai ancora scaricato nulla. Questo è il modo pigro per ottenere il tipo di contenuto di un file / pagina remoto (non ho controllato se questo è efficiente sul cavo. Per quello che ne so, può scaricare enormi pezzi di contenuto)

  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 è una class astratta e la proprietà ContentType è definita nelle classi ereditanti. Ad esempio nell’object HttpWebRequest questo metodo viene sovraccaricato per fornire l’intestazione content-type. Non sono sicuro dell’istanza di WebResponse che WebClient sta utilizzando. Se vuoi SOLO file HTML, è meglio usare direttamente l’object HttpWebRequest.

È ansible emettere la prima richiesta con il verbo HEAD e controllare l’intestazione di risposta del tipo di contenuto? [modifica] Sembra che dovrai utilizzare HttpWebRequest per questo, comunque.

La tua domanda è un po ‘confusa: se stai usando un’istanza della class Net.WebClient, Net.WebResponse non entra nell’equazione (a parte il fatto che si tratta in effetti di una class astratta, e staresti usando un’implementazione concreta come HttpWebResponse, come indicato in un’altra risposta).

Ad ogni modo, quando usi WebClient, puoi ottenere ciò che vuoi facendo qualcosa del genere:

 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 

Si noti che è necessario verificare l’esistenza dell’intestazione Content-Type, in quanto al server non è garantito il ritorno (sebbene la maggior parte dei moderni server HTTP lo includa sempre). Se non è presente un’intestazione Content-Type, è ansible ricorrere a un altro metodo di rilevamento HTML, ad esempio aprendo il file, leggendo i primi 1K caratteri in una stringa e verificando se contiene la sottostringa

Nota anche che questo è un po ‘dispendioso, poiché trasferirai sempre il file completo, prima di decidere se lo vuoi o no. Per ovviare a ciò, passare alle classi Net.HttpWebRequest / Response potrebbe essere d’aiuto, ma se il codice extra vale la pena dipende dalla tua applicazione …

Mi scuso per non essere stato molto chiaro. Ho scritto una class wrapper che estende WebClient. In questa class di wrapper, ho aggiunto un contenitore di cookie e ho esposto la proprietà di timeout per WebRequest.

Stavo usando DownloadDataAsync () da questa class wrapper e non ero in grado di recuperare il tipo di contenuto da WebResponse di questa class wrapper. La mia intenzione principale è intercettare la risposta e determinare se la sua natura text / html. Se non lo è, abortirò questa richiesta.

Sono riuscito ad ottenere il tipo di contenuto dopo aver sovrascritto il metodo WebClient.GetWebResponse (WebRequest, IAsyncResult).

Quello che segue è un esempio della mia class 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; } } 

Ecco un metodo che usa TCP, che http è costruito sopra. Verrà ripristinato quando è collegato o dopo il timeout (millisecondi), quindi potrebbe essere necessario modificare il valore in base alla situazione

 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;