Nosso aplicativo da web está sendo executado no .Net Framework 4.0. A interface do usuário chama métodos de controlador por meio de chamadas ajax.
Precisamos consumir o serviço REST do nosso fornecedor. Estou avaliando a melhor maneira de chamar o serviço REST no .Net 4.0. O serviço REST requer Esquema de autenticação básica e pode retornar dados em XML e JSON. Não há necessidade de fazer upload / download de grandes dados e não vejo nada no futuro. Analisei alguns projetos de código-fonte aberto para consumo REST e não encontrei nenhum valor para justificar dependência adicional no projeto. Começou a avaliar WebClient
e HttpClient
. Eu baixei o HttpClient for .Net 4.0 do NuGet.
Eu procurei por diferenças entre WebClient
e HttpClient
e neste site mencionado esse único HttpClient pode manipular chamadas simultâneas e pode reutilizar resolvido DNS, configuração de cookies e autenticação. Ainda estou para ver valores práticos que podemos obter devido às diferenças.
Fiz um teste rápido de desempenho para descobrir como WebClient
(chamadas de sincronização), HttpClient
(sincronização e assíncrona) se comportam. e aqui estão os resultados:
Usando a mesma HttpClient
instância para todas as solicitações (mín. - máx.)
Sincronização do WebClient: 8 ms - 167 ms
Sincronização do HttpClient: 3 ms - 7228 ms
Assinatura do HttpClient: 985 - 10405 ms
Usando um novo HttpClient
para cada solicitação (min - max)
Sincronização de cliente da Web: 4 ms - 297 ms
Sincronização de HttpClient: 3 ms - 7953 ms
Assinatura de HttpClient: 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);
}
}
}
Minhas perguntas
- As chamadas REST retornam em 3-4s, o que é aceitável. As chamadas para o serviço REST são iniciadas nos métodos do controlador que são chamados a partir de chamadas ajax. Para começar, as chamadas são executadas em um thread diferente e não bloqueiam a interface do usuário. Então, posso ficar com as chamadas de sincronização?
- O código acima foi executado no meu localbox. Na configuração do produto, a pesquisa de DNS e proxy estará envolvida. Existe alguma vantagem em usar
HttpClient
maisWebClient
? - A
HttpClient
concorrência é melhor queWebClient
? A partir dos resultados do teste, vejo que asWebClient
chamadas de sincronização têm melhor desempenho. - Será
HttpClient
uma escolha de design melhor se atualizarmos para o .Net 4.5? O desempenho é o principal fator de design.
GetDataFromHttpClientAsync
porque é executado primeiro, as outras invocações se beneficiam de ter dados coletados em potencial (seja na máquina local ou em qualquer proxy transparente entre você e o destino) e serão mais rápidos. Além disso, nas condições corretas,var response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;
pode resultar em um impasse devido ao esgotamento dos encadeamentos do conjunto de encadeamentos. Você nunca deve bloquear uma atividade que dependa do conjunto de encadeamentos nos encadeamentos ThreadPool; emawait
vez disso, retorne o encadeamento novamente para o conjunto.Respostas:
Eu moro no mundo do F # e da API da Web.
Há muitas coisas boas acontecendo com a API da Web, especialmente na forma de manipuladores de mensagens para segurança, etc.
Sei que a minha é apenas uma opinião, mas eu recomendaria apenas o uso
HttpClient
para trabalhos futuros . Talvez haja alguma maneira de aproveitar algumas das outras peças que saemSystem.Net.Http
sem usar diretamente essa montagem, mas não consigo imaginar como isso funcionaria no momento.Falando em comparar esses dois
Se você estiver usando o .NET 4.5, use a bondade assíncrona com o HttpClient que a Microsoft fornece aos desenvolvedores. HttpClient é muito simétrico aos irmãos do HTTP do lado do servidor, que são HttpRequest e HttpResponse.
Atualização: 5 razões para usar a nova API HttpClient:
Referência
C # 5.0 Joseph Albahari
(Channel9 - Compilação de vídeo 2013)
Cinco grandes motivos para usar a nova API HttpClient para conectar-se a serviços da Web
HttpClient vs WebClient vs HttpWebRequest
fonte
WebClient
parece ter métodos assíncronos agora.WebClient
não está disponível,.Net Core
masHttpClient
está.HttpClient é a mais nova das APIs e possui os benefícios de
Se você estiver gravando um serviço da Web que está fazendo chamadas REST para outros serviços da Web, convém usar um modelo de programação assíncrona para todas as suas chamadas REST, para não atingir a falta de thread. Você provavelmente também deseja usar o compilador C # mais recente, que possui suporte a assíncrono / espera.
Nota: Não é um AFAIK com melhor desempenho. Provavelmente é um desempenho semelhante se você criar um teste justo.
fonte
Em primeiro lugar, eu não sou uma autoridade no WebClient vs. HttpClient, especificamente. Em segundo lugar, pelos seus comentários acima, parece sugerir que o WebClient é SOMENTE Sincronizado, enquanto HttpClient é ambos.
Eu vejo isso como uma enorme diferença ao pensar no futuro, ou seja, processos de longa execução, GUI responsiva etc. (adicione o benefício que você sugere na estrutura 4.5 - que na minha experiência real é muito mais rápida no IIS)
fonte
WebClient
parece ter recursos assíncronos nas últimas versões do .NET. Eu gostaria de saber por que parece estar superando o HttpClient em uma escala tão grande.HttpClientFactory
É importante avaliar as diferentes maneiras de criar um HttpClient, e parte disso é entender o HttpClientFactory.
https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
Esta não é uma resposta direta, eu sei - mas é melhor começar por aqui do que acabar com
new HttpClient(...)
todos os lugares.fonte
Eu tenho benchmark entre HttpClient, WebClient, HttpWebResponse e chamo Rest Web Api
e resultado Chamar referência de API da Web Rest Rest
--------------------- Etapa 1 ---- 10 Solicitação
{00: 00: 17.2232544} ====> HttpClinet
{00: 00: 04.3108986} ====> WebRequest
{00: 00: 04.5436889} ====> WebClient
--------------------- Etapa 1 ---- 10 Pedido - Tamanho pequeno
{00: 00: 17.2232544} ====> HttpClinet
{00: 00: 04.3108986} ====> WebRequest
{00: 00: 04.5436889} ====> WebClient
--------------------- Etapa 3 ---- 10 Solicitação de sincronização - Tamanho pequeno
{00: 00: 15.3047502} ====> HttpClinet
{00: 00: 03.5505249} ====> WebRequest
{00: 00: 04.0761359} ====> WebClient
--------------------- Etapa 4 ---- Pedido de sincronização 100 - Tamanho pequeno
{00: 03: 23.6268086} ====> HttpClinet
{00: 00: 47.1406632} ====> WebRequest
{00: 01: 01.2319499} ====> WebClient
--------------------- Etapa 5 ---- 10 Solicitação de sincronização - Tamanho máximo
{00: 00: 58.1804677} ====> HttpClinet
{00: 00: 58.0710444} ====> WebRequest
{00: 00: 38.4170938} ====> WebClient
--------------------- Etapa 6 ---- 10 Solicitação de sincronização - Tamanho máximo
{00: 01: 04.9964278} ====> HttpClinet
{00: 00: 59.1429764} ====> WebRequest
{00: 00: 32.0584836} ====> WebClient
_____ WebClient É mais rápido ()
//-------------------------Funções
fonte
Talvez você possa pensar sobre o problema de uma maneira diferente.
WebClient
eHttpClient
são implementações essencialmente diferentes da mesma coisa. O que eu recomendo é implementar o padrão de injeção de dependência com um contêiner de IoC em todo o aplicativo. Você deve construir uma interface do cliente com um nível de abstração mais alto que a transferência HTTP de baixo nível. Você pode escrever classes concretas que usam ambosWebClient
eHttpClient
, e depois usar o contêiner IoC para injetar a implementação via config.O que isso permitiria é alternar entre
HttpClient
eWebClient
facilmente, para que você possa testar objetivamente no ambiente de produção.Então, perguntas como:
Na verdade, pode ser respondido objetivamente alternando entre as duas implementações do cliente usando o contêiner IoC. Aqui está um exemplo de interface da qual você pode depender, que não inclui nenhum detalhe sobre
HttpClient
ouWebClient
.Código completo
Implementação HttpClient
Você pode usar
Task.Run
paraWebClient
executar de forma assíncrona em sua implementação.A injeção de dependência, quando bem feita, ajuda a aliviar o problema de ter que tomar decisões de baixo nível antecipadamente. Por fim, a única maneira de saber a resposta verdadeira é tentar em um ambiente ao vivo e ver qual funciona melhor. É bem possível que
WebClient
funcione melhor para alguns clientes eHttpClient
funcione melhor para outros. É por isso que a abstração é importante. Isso significa que o código pode ser rapidamente trocado ou alterado com a configuração sem alterar o design fundamental do aplicativo.fonte
Opinião impopular de 2020:
Quando se trata de ASP.NET aplicativos eu ainda prefiro
WebClient
maisHttpClient
porque:fonte