System.Net.WebClient.DownloadDataがバイナリファイルをダウンロードしているかどうかを確認する方法は?

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

  •  03-07-2019
  •  | 
  •  

質問

WebClientを使用して、WinFormsアプリケーションを使用してWebからファイルをダウンロードしようとしています。ただし、実際にダウンロードしたいのはHTMLファイルのみです。無視したい他のタイプ。

WebResponse.ContentTypeをチェックしましたが、その値は常にnullです。

誰が原因を考えているのですか?

役に立ちましたか?

解決

更新を指定すると、GetWebRequestの.Methodを変更してこれを行うことができます。

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

別の方法として、GetWebRespons()をオーバーライドするときにヘッダーを確認できます。必要でない場合は、おそらく例外をスローします。

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

他のヒント

原因はわかりませんが、まだ何もダウンロードしていない可能性があります。これは、リモートファイル/ページのコンテンツタイプを取得するための怠zyな方法です(これがネットワーク上で効率的かどうかは確認していません。知っている限りでは、膨大なコンテンツの塊をダウンロードする可能性があります)

        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は抽象クラスであり、ContentTypeプロパティは継承クラスで定義されます。たとえば、HttpWebRequestオブジェクトでは、このメソッドはオーバーロードされて、コンテンツタイプヘッダーを提供します。 WebClientが使用しているWebResponseのインスタンスがわかりません。 HTMLファイルのみが必要な場合は、HttpWebRequestオブジェクトを直接使用するのが最善です。

HEAD動詞を使用して最初の要求を発行し、コンテンツタイプの応答ヘッダーを確認できますか? [編集]ただし、これにはHttpWebRequestを使用する必要があるようです。

あなたの質問は少しわかりにくいです:Net.WebClientクラスのインスタンスを使用している場合、Net.WebResponseは方程式に入りません(実際には抽象クラスであるという事実は別として、 d別の応答で指摘されているように、HttpWebResponseなどの具体的な実装を使用します。

とにかく、WebClientを使用しているときは、次のようなことを行うことで目的を達成できます。

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

サーバーはそれを返すことが保証されていないため、Content-Typeヘッダーの存在を確認する必要があることに注意してください(ただし、ほとんどの最新のHTTPサーバーには常に含まれます)。 Content-Typeヘッダーが存在しない場合は、別のHTML検出方法にフォールバックできます。たとえば、ファイルを開き、最初の1K文字などを文字列に読み取り、サブストリング<!> lt; html < !> gt;

また、これは少し無駄になることに注意してください。ファイル全体を転送するので、必要かどうかを決定する前に常に転送します。これを回避するには、Net.HttpWebRequest / Responseクラスに切り替えると役立つ場合がありますが、余分なコードが価値があるかどうかはアプリケーションによって異なります...

あまり明確ではなかったことをおaびします。 WebClientを拡張するラッパークラスを作成しました。このラッパークラスでは、Cookieコンテナーを追加し、WebRequestのタイムアウトプロパティを公開しました。

このラッパークラスのDownloadDataAsync()を使用しており、このラッパークラスのWebResponseからcontent-typeを取得できませんでした。私の主な意図は、応答を傍受し、その応答がtext / htmlかどうかを判断することです。そうでない場合、このリクエストを中止します。

WebClient.GetWebResponse(WebRequest、IAsyncResult)メソッドをオーバーライドした後、コンテンツタイプを取得できました。

以下は私のラッパークラスのサンプルです。

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

これはTCPを使用する方法で、httpはその上に構築されます。接続時またはタイムアウト(ミリ秒)後に戻りますので、状況に応じて値を変更する必要があります

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;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top