起因
在項目中需要訪問Http請求的時候,通常都是使用WebRequest,主要是老項目(你懂得).如果不是老項目,應該使用HttpClient,但在.Net Core 2.1之后,官方可推薦使用使用HttpClientFactory.
1. HttpClient的使用
public static async void UseHttp()
{
//在項目中HttpClient要靜態單實例
//這里只是為了方便
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://localhost:5000"); //要訪問的基地址,ip加端口
string result = await httpClient.GetStringAsync("/Home/GethtmlData");
Console.WriteLine(result);
}
2.在Asp.Net Core使用HttpClientFactory
在Startup文件的ConfigureServices函數,注冊HttpClient中間件
//1.在容器中注冊HttpClient中間件
services.AddHttpClient("baidu", client =>
{
client.BaseAddress = new Uri("http://localhost:5000");
//還可以請求定制化
});
/// <summary>
/// 在控制器中的構造函數注入IHttpClientFactory
/// </summary>
/// <param name="logger">日志</param>
/// <param name="cache">緩存</param>
/// <param name="httpClientFactory">容器在實例化HomeController的時候,會先實現IHttpClientFactory的實現DefaultHttpClientFactory(AddHttpClient在容器中注冊)</param>
public HomeController(ILogger<HomeController> logger,
IMemoryCache cache,
IHttpClientFactory httpClientFactory)
{
Console.WriteLine("有參數構造 HomeController");
this._logger = logger;
this._httpClientFactory = httpClientFactory;
}
/// <summary>
/// 在Action中使用HttpClient請求
/// </summary>
/// <returns></returns>
public async Task<string> GetHtmlData()
{
//通過DefaultHttpClientFactory的CreateClient獲取HttpClient實例
var client = _httpClientFactory.CreateClient("baidu");
return await client.GetStringAsync("/");
}
在Asp.Net Core的HttpClient中間件源碼
Asp.Net Core 5源碼(2022.03.15,剛剛對比最新的代碼,好像變化不大):
public static IServiceCollection AddHttpClient(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.AddLogging();
services.AddOptions();
//
// 向容器添加DefaultHttpClientFactory實例
//
services.TryAddTransient<HttpMessageHandlerBuilder, DefaultHttpMessageHandlerBuilder>();
services.TryAddSingleton<DefaultHttpClientFactory>();
services.TryAddSingleton<IHttpClientFactory>(serviceProvider => serviceProvider.GetRequiredService<DefaultHttpClientFactory>());
services.TryAddSingleton<IHttpMessageHandlerFactory>(serviceProvider => serviceProvider.GetRequiredService<DefaultHttpClientFactory>());
//
// Typed Clients
//
services.TryAdd(ServiceDescriptor.Transient(typeof(ITypedHttpClientFactory<>), typeof(DefaultTypedHttpClientFactory<>)));
services.TryAdd(ServiceDescriptor.Singleton(typeof(DefaultTypedHttpClientFactory<>.Cache), typeof(DefaultTypedHttpClientFactory<>.Cache)));
//
// Misc infrastructure
//
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHttpMessageHandlerBuilderFilter, LoggingHttpMessageHandlerBuilderFilter>());
// This is used to track state and report errors **DURING** service registration. This has to be an instance
// because we access it by reaching into the service collection.
services.TryAddSingleton(new HttpClientMAppingRegistry());
// Register default client as HttpClient
services.TryAddTransient(s =>
{
return s.GetRequiredService<IHttpClientFactory>().CreateClient(string.Empty);
});
return services;
}
public static IHttpClientBuilder AddHttpClient(this IServiceCollection services, string name)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
AddHttpClient(services);
return new DefaultHttpClientBuilder(services, name);
}
public static IHttpClientBuilder AddHttpClient(this IServiceCollection services, string name, Action<HttpClient> configureClient)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
if (configureClient == null)
{
throw new ArgumentNullException(nameof(configureClient));
}
AddHttpClient(services);
var builder = new DefaultHttpClientBuilder(services, name);
builder.ConfigureHttpClient(configureClient);
return builder;
}
public static IServiceCollection AddHttpClient(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.AddLogging();
services.AddOptions();
//
// Core abstractions
//
services.TryAddTransient<HttpMessageHandlerBuilder, DefaultHttpMessageHandlerBuilder>();
services.TryAddSingleton<DefaultHttpClientFactory>();
services.TryAddSingleton<IHttpClientFactory>(serviceProvider => serviceProvider.GetRequiredService<DefaultHttpClientFactory>());
services.TryAddSingleton<IHttpMessageHandlerFactory>(serviceProvider => serviceProvider.GetRequiredService<DefaultHttpClientFactory>());
//
// Typed Clients
//
services.TryAdd(ServiceDescriptor.Transient(typeof(ITypedHttpClientFactory<>), typeof(DefaultTypedHttpClientFactory<>)));
services.TryAdd(ServiceDescriptor.Singleton(typeof(DefaultTypedHttpClientFactory<>.Cache), typeof(DefaultTypedHttpClientFactory<>.Cache)));
//
// Misc infrastructure
//
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHttpMessageHandlerBuilderFilter, LoggingHttpMessageHandlerBuilderFilter>());
// This is used to track state and report errors **DURING** service registration. This has to be an instance
// because we access it by reaching into the service collection.
services.TryAddSingleton(new HttpClientMappingRegistry());
// Register default client as HttpClient
services.TryAddTransient(s =>
{
return s.GetRequiredService<IHttpClientFactory>().CreateClient(string.Empty);
});
return services;
}
public static IHttpClientBuilder AddHttpClient(this IServiceCollection services, string name)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
AddHttpClient(services);
return new DefaultHttpClientBuilder(services, name);
}
public static IHttpClientBuilder AddHttpClient(this IServiceCollection services, string name, Action<HttpClient> configureClient)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
if (configureClient == null)
{
throw new ArgumentNullException(nameof(configureClient));
}
AddHttpClient(services);
var builder = new DefaultHttpClientBuilder(services, name);
builder.ConfigureHttpClient(configureClient);
return builder;
}
在Asp.Net Core 6加入Minimal API
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
//在Asp.Net 6中,使用Minimal api
builder.Services.AddHttpClient("test", client =>
{
client.BaseAddress = new Uri("http://localhost:5000");
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
//在這里注入IHttpClientFactory
app.MapGet("/", async (IHttpClientFactory httpClientFactory) =>
{
var client = httpClientFactory.CreateClient("test");
return await client.GetStringAsync("/");
});
app.Run();
在Asp.Net Core 6中使用Minimal API簡化項目