HTTPWebRequest クラスを使用して大量のデータを送信すると、POST または PUT 要求が失敗する

この記事は、 クラスを使用HttpWebRequestして Microsoft .NET Frameworkを実行しているコンピューターに大量のデータを送信するときにエラーがスローされる問題を解決するのに役立ちます。

元の製品バージョン: .NET Framework
元の KB 番号: 908573

現象

クラスをHttpWebRequest使用して または PUT 要求を使用して大量のデータをPOST送信すると、.NET Frameworkを実行しているコンピューターで要求が失敗する可能性があります。 また、メモリ不足またはタイムアウトのエラー メッセージが表示される場合があります。

メモリ不足またはタイムアウトのエラー メッセージが表示されない場合は、クラスを使用するアプリケーションで大量のメモリが使用されていることに HttpWebRequest 気付く場合があります。 パフォーマンス モニターを使用して クラスを使用HttpWebRequestするアプリケーションを監視すると、データの送信に伴い、Private Bytes カウントは引き続き増加します。 そのため、メモリとリソース使用率の増加が発生するため、コンピューターや他のアプリケーションでもパフォーマンスが低下する可能性があります。

注:

既定でアップロードできるデータの量は、メモリとコンピューターで使用できるリソースによって異なります。

原因

この問題は、クラスを使用すると、.NET Frameworkによって既定で送信データがバッファーされるために発生しますHttpWebRequest

回避策

この問題を回避するには、 プロパティを HttpWebRequest.AllowWriteStreamBuffering false に設定します。

回避策に起因するエラー

プロパティを false に設定すると、次の例のようなエラー メッセージが HttpWebRequest.AllowWriteStreamBuffering 表示されることがあります。

この要求では、リダイレクトの認証を成功させるためにデータのバッファリングが必要です。

プロパティが false に設定されているときに HttpWebRequest.AllowWriteStreamBuffering または PUT 要求をPOST使用して大量のデータを正常に送信するには、使用する認証方法に応じて、次のいずれかの方法を使用します。

匿名認証

匿名認証を使用するように Web サーバーが構成されている場合は、 プロパティを HttpWebRequest.AllowWriteStreamBuffering false に設定します。 その他の変更は必要ありません。

基本認証

インターネット インフォメーション サービス (IIS) Web サーバーが基本認証を使用するように構成されており、プロパティを HttpWebRequest.AllowWriteStreamBuffering false に設定できる場合は、または PUT 要求を送信HEADする前に、接続を事前認証するための要求を送信するPOST必要があります。 また、 プロパティを HttpWebRequest.PreAuthenticate true に設定する必要があります。 次に、 または PUT 要求をPOST送信し、応答を受け取ります。 これを行うには、次のコード例のようなコードを使用します。

public void test(Uri URL)
{
    HttpWebRequest WRequest;
    HttpWebResponse WResponse;
    //preAuth the request
    // You can add logic so that you only pre-authenticate the very first request.
    // You should not have to pre-authenticate each request.
    WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
    // Set the username and the password.
    WRequest.Credentials = new NetworkCredential(user, password);
    WRequest.PreAuthenticate = true;
    WRequest.UserAgent = "Upload Test";
    WRequest.Method = "HEAD";
    WRequest.Timeout = 10000;
    WResponse = (HttpWebResponse)WRequest.GetResponse();
    WResponse.Close();
    // Make the real request.
    WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
    // Set the username and the password.
    WRequest.Credentials = new NetworkCredential(user, password);
    WRequest.PreAuthenticate = true;
    WRequest.UserAgent = "Upload Test";
    WRequest.Method = "POST";
    WRequest.AllowWriteStreamBuffering = false;
    WRequest.Timeout = 10000;
    FileStream ReadIn = new FileStream("c:\\testuploadfile.txt", FileMode.Open, FileAccess.Read);
    ReadIn.Seek(0, SeekOrigin.Begin); // Move to the start of the file.
    WRequest.ContentLength = ReadIn.Length; // Set the content length header to the size of the file.
    Byte[] FileData = new Byte[ReadIn.Length]; // Read the file in 2 KB segments.
    int DataRead = 0;
    Stream tempStream = WRequest.GetRequestStream();
    do
    {
        DataRead = ReadIn.Read(FileData,0,2048);
        if (DataRead > 0) //we have data
        {
            tempStream.Write(FileData,0,DataRead);
            Array.Clear(FileData,0, 2048); // Clear the array.
        }
    } while (DataRead > 0);

    WResponse = (HttpWebResponse)WRequest.GetResponse();
    // Read your response data here.
    // Close all streams.
    ReadIn.Close();
    tempStream.Close();
    WResponse.Close();
}

注:

アプリケーションの設計方法によっては、要求を送信して各要求を事前に認証する HEAD 必要がない場合があります。

統合 Windows 認証

ネゴシエートまたは Windows チャレンジ/応答 (NTLM) Windows 認証を使用して、IIS がインストールされているコンピューターを構成して応答できます。 WINDOWS 認証にネゴシエートを使用するように IIS が構成されている場合、クライアントは Kerberos または NTLM を使用して認証できます。 NTLM 認証を使用するように IIS が構成されている場合、NTLM 認証のみを使用でき、Kerberos 認証はサポートされていません。

Kerberos 認証を使用してネゴシエートする場合は、次の回避策を使用します。 NTLM が使用されている場合、回避策は失敗します。

Kerberos 認証を使用してネゴシエートする

IIS Web サーバーがネゴシエート認証を使用するように構成されており、プロパティを HttpWebRequest.AllowWriteStreamBuffering false に設定する必要がある場合は、POST または PUT 要求を送信する前に、接続を事前認証するためのHEAD要求を送信する必要があります。 プロパティを true に HttpWebRequest.PreAuthenticate 設定することもできます。 さらに、 プロパティを true に設定 HttpWebRequest.UnsafeAuthenticatedConnectionSharing する必要があります。 次に、POST または PUT 要求を送信し、応答を受け取ります。 これを行うには、次のコード例のようなコードを使用できます。

注:

クライアントがネゴシエート認証で Kerberos を使用できない場合、この回避策は失敗します。 また、プロパティが true に設定されていることを HttpWebRequest.KeepAlive 確認する必要もあります。 既定では、 プロパティの HttpWebRequest.KeepAlive 設定は true です。 Kerberos と Basic 認証のロジックはほぼ同じです。

public void test(Uri URL)
{
    HttpWebRequest WRequest;
    HttpWebResponse WResponse;
    CredentialCache myCredCache = new CredentialCache();
    myCredCache.Add(URL,"Negotiate",(NetworkCredential) CredentialCache.DefaultCredentials);
    // Pre-authenticate the request.
    WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
    // Set the username and the password.
    WRequest.Credentials = myCredCache;
    // This property must be set to true for Kerberos authentication.
    WRequest.PreAuthenticate = true;
    // Keep the connection alive.
    WRequest.UnsafeAuthenticatedConnectionSharing = true;
    WRequest.UserAgent = "Upload Test";
    WRequest.Method = "HEAD";
    WRequest.Timeout = 10000;
    WResponse = (HttpWebResponse)WRequest.GetResponse(); 
    WResponse.Close();
    // Make the real request.
    WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
    // Set the username and the password.
    WRequest.Credentials = myCredCache;
    // This property must be set to true for Kerberos authentication.
    WRequest.PreAuthenticate = true;
    // Keep the connection alive.
    WRequest.UnsafeAuthenticatedConnectionSharing = true;
    WRequest.UserAgent = "Upload Test";
    WRequest.Method = "POST";
    WRequest.AllowWriteStreamBuffering = false;
    WRequest.Timeout = 10000;
    FileStream ReadIn = new FileStream("c:\\testuploadfile.txt ", FileMode.Open, FileAccess.Read);
    ReadIn.Seek(0, SeekOrigin.Begin); // Move to the start of the file.
    WRequest.ContentLength = ReadIn.Length; // Set the content length header to the size of the file.
    Byte[] FileData = new Byte[ReadIn.Length]; // Read the file in 2 KB segments.
    int DataRead = 0;
    Stream tempStream = WRequest.GetRequestStream();
    do
    {
        DataRead = ReadIn.Read(FileData,0,2048);
        if (DataRead > 0) // We have data.
        {
            tempStream.Write(FileData,0,DataRead);
            Array.Clear(FileData,0, 2048); // Clear the array.
        }
    }while(DataRead > 0);

    WResponse = (HttpWebResponse)WRequest.GetResponse(); 
    // Read your response data here.
    // Close all streams
    ReadIn.Close();
    tempStream.Close();
    WResponse.Close();
}

注:

アプリケーションの設計方法によっては、HEAD要求を送信して各要求を事前認証する必要がない場合があります。

NTLM 認証

IIS Web サーバーも、Windows-Integrated 認証で NTLM 認証を使用するように構成されており、プロパティを HttpWebRequest.AllowWriteStreamBuffering false に設定する必要がある場合は、クライアント コードで認証の種類を NTLM に設定できます。 ネゴシエート認証と NTLM 認証の両方を使用するように IIS を構成し、クライアント コードで認証の種類を NTLM に設定した後、IIS メタベースのプロパティを AuthPersistSingleRequest false に設定することで、IIS が認証要求を処理する方法を構成できます。

注:

ネゴシエート認証と NTLM 認証の両方をサポートするように IIS を構成する方法の詳細については、「 参照 」セクションを参照してください。

また、要求を送信し、 HEAD プロパティを true に設定する前に、接続を POST 事前認証する要求を HttpWebrequest.UnsafeAuthenticatedConnectionSharing 送信する必要があります。 次に、 プロパティを HttpWebRequest.PreAuthenticate false に設定します。 最後に、 または PUT 要求をPOST送信し、応答を受け取ります。 これを行うには、次のコード例のようなコードを使用します。

public void test(Uri URL)
{
    HttpWebRequest WRequest;
    HttpWebResponse WResponse;
    CredentialCache myCredCache = new CredentialCache();
    myCredCache.Add(URL,"NTLM",(NetworkCredential) CredentialCache.DefaultCredentials);
    // Pre-authenticate the request.
    WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
    // Set the username and the password.
    WRequest.Credentials = myCredCache;
    // For NTLM authentication, you must set the following property to true
    // so the connection does not close.
    WRequest.UnsafeAuthenticatedConnectionSharing = true;
    WRequest.UserAgent = "Upload Test";
    WRequest.Method = "HEAD";
    WRequest.Timeout = 10000;
    WResponse = (HttpWebResponse)WRequest.GetResponse(); 
    WResponse.Close();
    // Make the real request.
    WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
    // Set the username and the password.
    WRequest.Credentials = myCredCache;
    // For NTLM authentication, you must set the following property to true
    // so the connection does not close.
    WRequest.UnsafeAuthenticatedConnectionSharing = true;
    WRequest.UserAgent = "Upload Test";
    WRequest.Method = "POST";
    WRequest.AllowWriteStreamBuffering = false;
    WRequest.Timeout = 10000;
    FileStream ReadIn = new FileStream("c:\\ testuploadfile.txt", FileMode.Open, FileAccess.Read);
    ReadIn.Seek(0, SeekOrigin.Begin); // Move to the start of the file.
    WRequest.ContentLength = ReadIn.Length; // Set the content length header to the size of the file.
    Byte[] FileData = new Byte[ReadIn.Length]; // Read the file in 2 KB segments.
    int DataRead = 0;
    Stream tempStream = WRequest.GetRequestStream();
    do
    {
        DataRead = ReadIn.Read(FileData,0,2048);
        if (DataRead > 0) // We have data.
        {
            tempStream.Write(FileData,0,DataRead);
            Array.Clear(FileData,0, 2048); // Clear the array.
        }
    }while(DataRead > 0);

    WResponse = (HttpWebResponse)WRequest.GetResponse();
    // Read your response data here.
    // Close all streams.
    ReadIn.Close();
    tempStream.Close();
    WResponse.Close();
}

注:

アプリケーションの設計方法によっては、要求を送信して各要求を事前認証する HEAD 必要がない場合があります。

関連情報