.NET Core 使用 WebApiClient.JIT 调用第三方接口
开始前首先通过 NuGet 引入包,当前使用版本为 v1.0.9,发布日期 2019年5月21日
Github:https://github.com/dotnetcore/WebApiClient/tree/WebApiClient.JITAOT 注意底部有Wiki文档对使用非常有帮助,请仔细阅读。
1.新建 xxxHttpsModule 并在 Startup ConfigureServices 中注入。(单独新建 HttpsModule 是为了将不同的业务分离)
public static class xxxHttpsModule
{
public static IServiceCollection Register(IServiceCollection services, IConfigurationRoot appConfiguration)
{
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
void config(HttpApiConfig c)
{
c.HttpHost = new Uri(appConfiguration["Server:Url"]);//AppSettings.json 中的服务器地址
c.GlobalFilters.Add(new DefaultHeaderAttribute(appConfiguration));
}
services.AddHttpApi<IxxxApi>().ConfigureHttpApiConfig(config);//注入接口
return services;
}
}
AddHttpApi 是一个扩展方法,这样写只是为了在多次使用时,看起来更协调。
/// <summary>
/// 基于DependencyInjection的扩展
/// </summary>
public static class DependencyInjectionExtensions
{
/// <summary>
/// 添加HttpApi
/// 返回HttpApi工厂
/// </summary>
/// <typeparam name="TInterface">接口类型</typeparam>
/// <param name="services"></param>
/// <returns></returns>
public static HttpApiFactoryBuilder<TInterface> AddHttpApi<TInterface>(this IServiceCollection services)
where TInterface : class, IHttpApi
{
return new HttpApiFactoryBuilder<TInterface>(services);
}
}
IxxxApi 接口中的内容就是第三方接口的内容
[TraceFilter(OutputTarget = OutputTarget.Console)]//这个设置可以将日志输入到控制台
public interface IxxxApi : IHttpApi
{
/// <summary>
/// 创建xxx信息
/// </summary>
/// <param name="input">实体</param>
/// <returns></returns>
[Timeout(10000)]
[HttpPost("/api/v2/x/xxx")]
ITask<AjaxResponse<List<xxxApiDto>>> GetxxxPagedList([JsonContent] xxxDto input);
/// <summary>
/// 获取xxx信息
/// </summary>
/// <param name="pageIndex">页码</param>
/// <returns></returns>
[Timeout(10000)]
[HttpGet("/api/v2/x/xxx")]
ITask<AjaxResponse<List<xxxApiDto>>> GetxxxPagedList(int pageIndex);
}
2.创建 HttpApi 实例工厂创建器类,具体内容如下。目前没有修改过里面的内容。
using System;
using WebApiClient;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
/// <summary>
/// HttpApi实例工厂创建器
/// </summary>
/// <typeparam name="TInterface"></typeparam>
public class HttpApiFactoryBuilder<TInterface> where TInterface : class, IHttpApi
{
private bool keepCookieContainer = true;
private TimeSpan lifeTime = TimeSpan.FromMinutes(2d);
private TimeSpan cleanupInterval = TimeSpan.FromSeconds(10d);
private Action<HttpApiConfig, IServiceProvider> configOptions;
private Func<IServiceProvider, HttpMessageHandler> handlerFactory;
/// <summary>
/// HttpApi实例工厂创建器
/// </summary>
/// <param name="services"></param>
public HttpApiFactoryBuilder(IServiceCollection services)
{
services.AddSingleton<IHttpApiFactory<TInterface>, HttpApiFactory<TInterface>>(p =>
{
return new HttpApiFactory<TInterface>()
.SetLifetime(this.lifeTime)
.SetCleanupInterval(this.cleanupInterval)
.SetKeepCookieContainer(this.keepCookieContainer)
.ConfigureHttpMessageHandler(() => this.handlerFactory?.Invoke(p));
});
services.AddTransient(p =>
{
var factory = p.GetRequiredService<IHttpApiFactory<TInterface>>();
factory.ConfigureHttpApiConfig(c =>
{
c.ServiceProvider = p;
this.configOptions?.Invoke(c, p);
});
return factory.CreateHttpApi();
});
}
/// <summary>
/// 配置HttpApiConfig
/// </summary>
/// <param name="configOptions">配置选项</param>
/// <exception cref="ArgumentNullException"></exception>
/// <returns></returns>
public HttpApiFactoryBuilder<TInterface> ConfigureHttpApiConfig(Action<HttpApiConfig> configOptions)
{
if (configOptions == null)
{
throw new ArgumentNullException(nameof(configOptions));
}
return this.ConfigureHttpApiConfig((c, p) => configOptions.Invoke(c));
}
/// <summary>
/// 配置HttpApiConfig
/// </summary>
/// <param name="configOptions">配置选项</param>
/// <exception cref="ArgumentNullException"></exception>
/// <returns></returns>
public HttpApiFactoryBuilder<TInterface> ConfigureHttpApiConfig(Action<HttpApiConfig, IServiceProvider> configOptions)
{
this.configOptions = configOptions ?? throw new ArgumentNullException(nameof(configOptions));
return this;
}
/// <summary>
/// 配置HttpMessageHandler的创建
/// </summary>
/// <param name="handlerFactory">创建委托</param>
/// <exception cref="ArgumentNullException"></exception>
/// <returns></returns>
public HttpApiFactoryBuilder<TInterface> ConfigureHttpMessageHandler(Func<HttpMessageHandler> handlerFactory)
{
if (handlerFactory == null)
{
throw new ArgumentNullException(nameof(handlerFactory));
}
return this.ConfigureHttpMessageHandler(p => handlerFactory.Invoke());
}
/// <summary>
/// 配置HttpMessageHandler的创建
/// </summary>
/// <param name="handlerFactory">创建委托</param>
/// <exception cref="ArgumentNullException"></exception>
/// <returns></returns>
public HttpApiFactoryBuilder<TInterface> ConfigureHttpMessageHandler(Func<IServiceProvider, HttpMessageHandler> handlerFactory)
{
this.handlerFactory = handlerFactory ?? throw new ArgumentNullException(nameof(handlerFactory));
return this;
}
/// <summary>
/// 置HttpApi实例的生命周期
/// </summary>
/// <param name="lifeTime">生命周期</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
/// <returns></returns>
public HttpApiFactoryBuilder<TInterface> SetLifetime(TimeSpan lifeTime)
{
if (lifeTime <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(lifeTime));
}
this.lifeTime = lifeTime;
return this;
}
/// <summary>
/// 获取或设置清理过期的HttpApi实例的时间间隔
/// </summary>
/// <param name="interval">时间间隔</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
/// <returns></returns>
public HttpApiFactoryBuilder<TInterface> SetCleanupInterval(TimeSpan interval)
{
if (interval <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(interval));
}
this.cleanupInterval = interval;
return this;
}
/// <summary>
/// 设置是否维护使用一个CookieContainer实例 该实例为首次创建时的CookieContainer
/// </summary>
/// <param name="keep">true维护使用一个CookieContainer实例</param>
/// <returns></returns>
public HttpApiFactoryBuilder<TInterface> SetKeepCookieContainer(bool keep)
{
this.keepCookieContainer = keep;
return this;
}
}
3.调用就和我们自己写的接口一样在构造函数中注入使用,如果不告诉你这是一个第三方接口,完全感觉不出来。
4.WebApiClient 还可以通过 AliasAs 属性自定义字段名称
[Serializable]
public class xxxApiDto
{
/// <summary>
/// 序列号
/// </summary>
[AliasAs("serialNum")]
public string SerialNumber { get; set; }
}
目前发现如果在 xxxApiDto 类中属性存在类时, AliasAs 则不会被识别,目前的解决方案是使用 [JsonProperty(PropertyName = "serialNum")],再通过 JsonConvert.SerializeObject(xxx) 转换成 JSON 字符串。
5.请求注入 Headers ,可以通过继承 ApiActionFilterAttribute 类,然后重写 OnBeginRequestAsync 实现。