c# - alternative - webclient vs httpclient
Decidir entre HttpClient y WebClient (3)
En primer lugar, no soy una autoridad en WebClient frente a HttpClient, específicamente. En segundo lugar, a partir de sus comentarios anteriores, parece sugerir que WebClient es ÚNICAMENTE sincronización, mientras que HttpClient es ambos.
Hice una prueba de rendimiento rápido para ver cómo funciona WebClient (llamadas de sincronización), HttpClient (sincronización y Async). Y aquí están los resultados.
Veo eso como una gran diferencia cuando pienso para el futuro, es decir, procesos de larga ejecución, GUI receptiva, etc. (agregue al beneficio que sugiere el marco 4.5, que en mi experiencia real es mucho más rápido en IIS)
Nuestra aplicación web se ejecuta en .Net Framework 4.0. La interfaz de usuario llama a los métodos de control a través de llamadas ajax.
Necesitamos consumir el servicio REST de nuestro proveedor. Estoy evaluando la mejor manera de llamar al servicio REST en .Net 4.0. El servicio REST requiere el Esquema básico de autenticación y puede devolver datos tanto en XML como en JSON. No hay ningún requisito para cargar / descargar datos enormes y no veo nada en el futuro. Eché un vistazo a algunos proyectos de código fuente abierto para el consumo de REST y no encontré ningún valor para justificar una dependencia adicional en el proyecto. Empecé a evaluar WebClient
y HttpClient
. Descargué HttpClient para .Net 4.0 desde NuGet.
Busqué las diferencias entre WebClient
y HttpClient
y este sitio mencionó que HttpClient solo puede manejar llamadas concurrentes y puede reutilizar DNS resuelto, configuración de cookies y autenticación. Todavía tengo que ver valores prácticos que podemos ganar debido a las diferencias.
Hice una prueba de rendimiento rápido para ver cómo funciona WebClient
(llamadas de sincronización), HttpClient
(sincronización y asincronización). Y aquí están los resultados:
Usar la misma instancia de HttpClient
para todas las solicitudes (mínimo - máximo)
Sincronización webClient: 8 ms - 167 ms
HttpClient sync: 3 ms - 7228 ms
HttpClient async: 985 - 10405 ms
Usar un nuevo HttpClient
para cada solicitud (min - max)
Sincronización webClient: 4 ms - 297 ms
HttpClient sync: 3 ms - 7953 ms
HttpClient async: 1027 - 10834 ms
Código
public class AHNData
{
public int i;
public string str;
}
public class Program
{
public static HttpClient httpClient = new HttpClient();
private static readonly string _url = "http://localhost:9000/api/values/";
public static void Main(string[] args)
{
#region "Trace"
Trace.Listeners.Clear();
TextWriterTraceListener twtl = new TextWriterTraceListener(
"C://Temp//REST_Test.txt");
twtl.Name = "TextLogger";
twtl.TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime;
ConsoleTraceListener ctl = new ConsoleTraceListener(false);
ctl.TraceOutputOptions = TraceOptions.DateTime;
Trace.Listeners.Add(twtl);
Trace.Listeners.Add(ctl);
Trace.AutoFlush = true;
#endregion
int batchSize = 1000;
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = batchSize;
ServicePointManager.DefaultConnectionLimit = 1000000;
Parallel.For(0, batchSize, parallelOptions,
j =>
{
Stopwatch sw1 = Stopwatch.StartNew();
GetDataFromHttpClientAsync<List<AHNData>>(sw1);
});
Parallel.For(0, batchSize, parallelOptions,
j =>
{
Stopwatch sw1 = Stopwatch.StartNew();
GetDataFromHttpClientSync<List<AHNData>>(sw1);
});
Parallel.For(0, batchSize, parallelOptions,
j =>
{
using (WebClient client = new WebClient())
{
Stopwatch sw = Stopwatch.StartNew();
byte[] arr = client.DownloadData(_url);
sw.Stop();
Trace.WriteLine("WebClient Sync " + sw.ElapsedMilliseconds);
}
});
Console.Read();
}
public static T GetDataFromWebClient<T>()
{
using (var webClient = new WebClient())
{
webClient.BaseAddress = _url;
return JsonConvert.DeserializeObject<T>(
webClient.DownloadString(_url));
}
}
public static void GetDataFromHttpClientSync<T>(Stopwatch sw)
{
HttpClient httpClient = new HttpClient();
var response = httpClient.GetAsync(_url).Result;
var obj = JsonConvert.DeserializeObject<T>(
response.Content.ReadAsStringAsync().Result);
sw.Stop();
Trace.WriteLine("HttpClient Sync " + sw.ElapsedMilliseconds);
}
public static void GetDataFromHttpClientAsync<T>(Stopwatch sw)
{
HttpClient httpClient = new HttpClient();
var response = httpClient.GetAsync(_url).ContinueWith(
(a) => {
JsonConvert.DeserializeObject<T>(
a.Result.Content.ReadAsStringAsync().Result);
sw.Stop();
Trace.WriteLine("HttpClient Async " + sw.ElapsedMilliseconds);
}, TaskContinuationOptions.None);
}
}
}
Mis preguntas
- Las llamadas REST regresan en 3-4, lo cual es aceptable. Las llamadas al servicio REST se inician en métodos de controlador que se invocan desde llamadas ajax. Para empezar, las llamadas se ejecutan en un hilo diferente y no bloquean la IU. Entonces, ¿puedo seguir con las llamadas de sincronización?
- El código anterior se ejecutó en mi localbox. En la configuración de prod, se utilizarán la búsqueda de DNS y proxy. ¿Hay alguna ventaja de usar
HttpClient
sobreWebClient
? - ¿La concurrencia de
HttpClient
es mejor queWebClient
? A partir de los resultados de las pruebas, veo que las llamadas de sincronizaciónWebClient
funcionan mejor. - ¿Será
HttpClient
una mejor opción de diseño si actualizamos a .Net 4.5? El rendimiento es el factor de diseño clave.
HttpClient es la más nueva de las API y tiene los beneficios de
- tiene un buen modelo de programación asíncrona
- Henrik F Nielson, quien básicamente es uno de los inventores de HTTP, y él diseñó la API, por lo que es fácil para usted seguir el estándar HTTP, por ejemplo, generar encabezados que cumplan con los estándares.
- está en .Net framework 4.5, por lo que tiene cierto nivel garantizado de soporte para el futuro previsible
- también tiene la versión xcopyable / portable-framework de la biblioteca si desea usarla en otras plataformas: .Net 4.0, Windows Phone, etc.
Si está escribiendo un servicio web que está realizando llamadas REST a otros servicios web, le conviene usar un modelo de programación asíncrono para todas sus llamadas REST, de modo que no golpee la falta de hilo. Probablemente también desee utilizar el compilador de C # más nuevo que tiene soporte async / await.
Nota: No es más efectivo AFAIK. Es probable que tenga un rendimiento similar si crea una prueba justa.
Vivo en los mundos F # y Web API.
Hay muchas cosas buenas que suceden con la API web, especialmente en forma de manejadores de mensajes para seguridad, etc.
Sé que la mía es solo una opinión, pero solo recomendaría el uso de HttpClient
para cualquier trabajo futuro . Quizás haya alguna forma de aprovechar algunas de las otras piezas que salen de System.Net.Http
sin usar ese ensamblaje directamente, pero no puedo imaginar cómo funcionaría en este momento.
Hablando de comparar estos dos
- HttpClient está más cerca de HTTP que de WebClient.
- HttpClient no pretendía ser un reemplazo completo de Web Client, ya que hay aspectos como el progreso del informe, el esquema de URI personalizado y las llamadas FTP que proporciona WebClient, pero HttpClient no lo hace.
Si está utilizando .NET 4.5, utilice la bondad async con HttpClient que Microsoft proporciona a los desarrolladores. HttpClient es muy simétrico para los hermanos del lado del servidor HTTP que son HttpRequest y HttpResponse.
Actualización: 5 razones para usar la nueva API de HttpClient:
- Cabeceras fuertemente tipadas.
- Cachés compartidos, cookies y credenciales
- Acceso a cookies y cookies compartidas
- Controle el almacenamiento en caché y la memoria caché compartida.
- Inyecte su módulo de código en la tubería ASP.NET. Código más limpio y modular.
Referencia
C # 5.0 Joseph Albahari
(Channel9 - Video Build 2013)
Cinco buenas razones para usar la nueva API HttpClient para conectarse a servicios web