Se produce un error en una solicitud POST o PUT cuando se usa la clase HttpWebRequest para enviar muchos datos

Este artículo le ayuda a resolver un problema en el que se puede producir un error al usar la clase para enviar muchos datos en un equipo que ejecuta microsoft HttpWebRequest .NET Framework.

Versión del producto original:   .NET Framework
Número KB original:   908573

Síntomas

Cuando se usa la clase para enviar una gran cantidad de datos mediante una o solicitud, es posible que la solicitud falle en un equipo que ejecuta HttpWebRequest POST el PUT .NET Framework. Además, puede recibir un mensaje de error de falta de memoria o tiempo de espera.

Si no recibe un mensaje de error de falta de memoria o tiempo de espera, puede observar que la aplicación que usa la clase usa HttpWebRequest muchas memorias. Al usar el Monitor de rendimiento para supervisar la aplicación que usa la clase, el recuento de bytes privados seguirá aumentando a medida que HttpWebRequest se envíen los datos. Por lo tanto, también puede experimentar un rendimiento lento en el equipo y en otras aplicaciones porque se produce un mayor uso de la memoria y los recursos.

Nota

La cantidad de datos que se pueden cargar de forma predeterminada variará según la memoria y los recursos disponibles en el equipo.

Causa

Este problema se produce porque el .NET Framework almacena en búfer los datos salientes de forma predeterminada cuando se usa la HttpWebRequest clase.

Solución alternativa

Para evitar este problema, establezca la HttpWebRequest.AllowWriteStreamBuffering propiedad en false.

Error causado por la solución alternativa

Puede recibir un mensaje de error como el siguiente ejemplo al establecer la HttpWebRequest.AllowWriteStreamBuffering propiedad en false:

Esta solicitud requiere el almacenamiento en búfer de datos para que la autenticación de redirección se pueda realizar correctamente.

Para enviar correctamente una gran cantidad de datos mediante una o una solicitud cuando la propiedad se establece en false, use uno de los métodos siguientes, según el método de autenticación que POST PUT desee HttpWebRequest.AllowWriteStreamBuffering usar.

Autenticación anónima

Si el servidor web está configurado para usar la autenticación anónima, establezca la HttpWebRequest.AllowWriteStreamBuffering propiedad en false. No se necesitan otros cambios.

Autenticación básica

Si el servidor web de Internet Information Services (IIS) está configurado para usar la autenticación básica y puede establecer la propiedad en false, debe enviar una solicitud para autenticar previamente la conexión antes de enviar la solicitud HttpWebRequest.AllowWriteStreamBuffering HEAD POST PUT o. También debe establecer la HttpWebRequest.PreAuthenticate propiedad en true. A continuación, envíe POST la solicitud o PUT y, a continuación, reciba la respuesta. Para ello, use código como el siguiente ejemplo de código.

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

Nota

Dependiendo de cómo se diseñe la aplicación, es posible que no tenga que autenticar previamente cada solicitud enviando una HEAD solicitud.

Autenticación integrada de Windows

Puede configurar un equipo en el que IIS esté instalado para responder mediante Negotiate o Windows Challenge/Response (NTLM) Windows autenticación. Si IIS está configurado para usar Negotiate Windows autenticación, el cliente puede usar Kerberos o NTLM para autenticarse. Si IIS está configurado para usar la autenticación NTLM, solo se puede usar la autenticación NTLM y no se admite la autenticación Kerberos.

Si se usa Negociar con la autenticación Kerberos, use la siguiente solución alternativa. La solución alternativa producirá un error si se usa NTLM.

Negociar con la autenticación Kerberos

Si el servidor web iis está configurado para usar la autenticación Negotiate y debe establecer la propiedad en false, debe enviar una solicitud HEAD para autenticar previamente la conexión antes de enviar la solicitud POST o HttpWebRequest.AllowWriteStreamBuffering PUT. También puede establecer la HttpWebRequest.PreAuthenticate propiedad en true. Además, es posible que tenga que establecer la HttpWebRequest.UnsafeAuthenticatedConnectionSharing propiedad en true. A continuación, envíe la solicitud POST o PUT y, a continuación, reciba la respuesta. Para ello, puede usar código similar al siguiente ejemplo de código.

Nota

Esta solución alternativa producirá un error si el cliente no puede usar Kerberos con la autenticación Negotiate. También debe asegurarse de que la HttpWebRequest.KeepAlive propiedad está establecida en true. De forma predeterminada, el valor de la HttpWebRequest.KeepAlive propiedad es true. La lógica para la autenticación kerberos y básica es casi la misma.

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

Nota

Según cómo se diseñe la aplicación, es posible que no tenga que autenticar previamente cada solicitud enviando una solicitud HEAD.

Autenticación NTLM

Si el servidor web iis también está configurado para usar la autenticación NTLM con autenticación Windows-Integrated y debe establecer la propiedad en false, puede establecer el tipo de autenticación en NTLM en el código de HttpWebRequest.AllowWriteStreamBuffering cliente. Después de configurar IIS para que use la autenticación Negotiate y NTLM y establecer el tipo de autenticación en NTLM en el código de cliente, puede configurar el modo en que IIS administra las solicitudes de autenticación estableciendo la propiedad de la metabase de IIS en AuthPersistSingleRequest false.

Nota

Para obtener más información acerca de cómo configurar IIS para admitir la autenticación negotiate y NTLM, vea la sección Referencias.

También debe enviar una solicitud para autenticar previamente la conexión antes de enviar la solicitud y HEAD establecer la propiedad en POST HttpWebrequest.UnsafeAuthenticatedConnectionSharing true. A continuación, establezca la HttpWebRequest.PreAuthenticate propiedad en false. Por último, envíe la POST solicitud o PUT y, a continuación, reciba la respuesta. Para ello, use código similar al ejemplo de código siguiente.

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

Nota

Dependiendo de cómo se diseñe la aplicación, es posible que no tenga que autenticar previamente cada solicitud enviando una HEAD solicitud.

Referencias