core3.1⾼性能微服务架构:封装调⽤外部服务的接⼝⽅法--HttpClient。。。
众所周知,微服务架构是由⼀众微服务组成,项⽬中调⽤其他微服务接⼝更是常见的操作。为了便于调⽤外部接⼝,我们的常⽤思路⼀般都是封装⼀个外部接⼝的客户端,使⽤
时候直接调⽤相应的⽅法。webservice或WCF的做法就是引⽤服务,⾃动⽣成客户端。在webapi2.0⾥,我们都会⼿动封装⼀个静态类。那么在core3.1的微服务时代,我们
该如何处理这个问题呢? ----思路都是⼀样的,封装⼀个外部服务,并且使⽤依赖注⼊和 HttpFactory⼯⼚等core特有的⽅式提升性能。接下来我们⼀步⼀步说下详细的步骤:
第1步:--创建项⽬
为了便于构建⽣成nuget包,我们⼀般都每个外部服务创建⼀个独⽴的项⽬;如下图:
在解决⽅案⾥,我们创建了⼀个项⽬名为:"MuXue.Zyiz.Template.OuterClient",(项⽬起名⼀般为公司名.部门名.项⽬名.xxx)。
第2步:创建⼀个IServiceCollection扩展服务,便于将服务注册信息。(重点)
public static class MsgApiClientServiceCollectionExtensions
{
public static IServiceCollection AddMsgApiClient(this IServiceCollection services, IConfiguration MsgClientConfiguration)
{
services.Configure<MsgClientConfiguration>(MsgClientConfiguration)
.AddHttpClient<IMsgApiClient, MsgApiClient>()
.ConfigureHttpClient(config=> {
config.BaseAddress = new Uri(MsgClientConfiguration.GetSection("url").Value);
config.Timeout = TimeSpan.FromSeconds(30);
});
return services;
}
}
该段代码虽然很短,但是最关键的部分:
代码的执⾏过程如下:
(1)  services⾸先注册⼀个操作配置⽂件的实例:
services.Configure<MsgClientConfiguration>(MsgClientConfiguration)
(2)添加HttpClientFactory⼯⼚并且关联到services⾥,并将Client强制类型为IMsgApiClient(⾃定义的外部微服务接⼝名称):
.AddHttpClient<IMsgApiClient, MsgApiClient>();//IMsgApiClient为接下来要创建的客户端
(3)设置HttpClient的相关配置参数:
.ConfigureHttpClient(config=> {
config.BaseAddress = new Uri(MsgClientConfiguration.GetSection("url").Value);//外部微服务接⼝域名
config.Timeout = TimeSpan.FromSeconds(30);  // 接⼝调⽤超时时间
});
还有如下注意点:
(1)以静态类和静态⽅法⽅式;
(2) this IServiceCollection services ,这个参数我就不多解释了。
(3) ⼀般我们都需要读取appsettings.json配置⽂件⾥的参数所以这⾥接收了⼀个参数---IConfiguration MsgClientConfiguration  ;当然如果你不需要读取配置参数,也可以忽略这
个参数;
第3步:写外部接⼝调⽤的具体逻辑代码:
(1)创建⼀个接⼝,⽐如IMsgApiClient
调用webservice服务///<summary>
///企业消息发送客户端
///</summary>
public interface IMsgApiClient
{
///<summary>
///调⽤接⼝接⼝:向发送消息
///</summary>
///<param name="hrcodeStr">hrcode,多个以|隔开</param>
///<param name="msg">消息内容</param>
///<returns></returns>
Task<Result<string>> SendWxWorkMsgAsync(string hrcodeStr, string msg);
}
(2)实现该接⼝:
///<summary>
///调⽤外部接⼝:向SD发送消息
///</summary>
///<param name="hrcodeStr">hrcode,多个以|隔开</param>
///<param name="msg">消息内容</param>
///<returns></returns>
public async Task<Result<string>> SendWxWorkMsgAsync(string hrcodeStr, string msg)
{
Result<string> result = new Result<string>();
string funName = "【调⽤外部接⼝:企业消息推送接⼝】";
try
{
//具体的业务逻辑---根据⾃⾝业务来写
MsgApiResult<WeiXinWorkMessageResponse> sendRet = await ZyizHttpClientExtensions.PostData<MsgApiResult<WeiXinWorkMessageResponse>>(_client, _logger, "/api/weixin/work/messages/send", msgReq);
if (sendRet != null)
{
_logger.LogInformation($"{funName},{hrcodeStr}推送消息成功");
result.state = true;
result.data = sendRet.Return_data.MessageId;
}
else
{
result.state = false;
<_msg = sendRet.Return_msg;
_logger.LogError($"{funName}:{hrcodeStr}推送消息失败:{sendRet.Return_msg}");
}
}
catch (Exception ex)
{
result.state = false;
<_code = ErrorCode.OuterApiError;
<_msg = funName + "调⽤外部接⼝异常:。" + ex.Message;
_logger.LogError(ex, $"{funName}向{hrcodeStr}推送消息处理异常:{ex.Message}");
}
return result;
}
针对HttpClient的Post⽅法我特意封装了⼀个通⽤⽅法,如下:(可以根据⾃⾝项⽬⾃⾏改造)
///<summary>
/// HttpClient扩展⽅法
///</summary>
public class ZyizHttpClientExtensions
{
/
//<summary>
/// httpclient-post⽅法的简单处理,封装成⼀个⽅法,便于调⽤
///</summary>
///<typeparam name="T"></typeparam>
///<param name="_client"></param>
///<param name="_logger"></param>
///<param name="actionUrl">xxx/后⾯之后的地址</param>
///<param name="param">⼀个对象</param>
///<param name="ContentType"></param>
///<param name="BearerToken"></param>
///<returns></returns>
public async static  Task<T> PostData<T>(HttpClient _client, ILogger _logger,string actionUrl, dynamic param, string ContentType = "application/json", string BearerToken = "")        {
string funName = "PostData";
string paramStr = JsonConvert.SerializeObject(param);
string jrclientguid = Guid.NewGuid().ToString("n");
try
{
_logger.LogInformation($"{funName}开始,url={_client.BaseAddress},action={actionUrl},postData={paramStr} ,jrclientguid={jrclientguid}---------");
HttpResponseMessage response;
using (HttpContent httpContent = new StringContent(paramStr, Encoding.UTF8))
{
if (!string.IsNullOrWhiteSpace(BearerToken))
{
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", BearerToken);
}
httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(ContentType);
response = await _client.PostAsync(actionUrl, httpContent);
}
if (response != null && response.IsSuccessStatusCode)
{
Type t = typeof(T);
if (typeof(T) == typeof(string))
{
string respStr = await response.Content.ReadAsStringAsync();
return (T)Convert.ChangeType(respStr, typeof(T));
}
else
{
string respStr = response.Content.ReadAsStringAsync().Result;
T resp = JsonConvert.DeserializeObject<T>(respStr);
return resp;
}
}
else
{
return default(T);
}
}
catch (Exception ex)
{
_logger.LogError(ex,$"{funName}报错啦,url={_client.BaseAddress},action={actionUrl},postData={paramStr} ,jrclientguid={jrclientguid}---,ex={ex.Message}" );
throw;
}
finally
{
_logger.LogInformation($"{funName}结束,url={_client.BaseAddress},action={actionUrl},postData={paramStr} ,jrclientguid={jrclientguid}---------");
}
}
}
第4步:将服务注⼊容器:代码在Startup类的ConfigureServices⽅法⾥:
services.AddZyizMVC(Env)
.AddZyizDbContext(Configuration)
.AddMsgApiClient(Configuration.GetSection(nameof(MsgApiClient)))//就是这⾏
第5步:使⽤:在Controller或其他地⽅都可以使⽤;
(1)⾸先在构造函数⾥注册:
private readonly ILogger _logger;
private IMsgApiClient _IMsgApiClient;
public HealthController(ILogger<HealthController> logger,    IMsgApiClient iMsgApiClient)
{
_logger = logger;
_IMsgApiClient = iMsgApiClient;
}
(2)调⽤⽅法:
///<summary>
///发消息
/
//</summary>
///<returns></returns>
[HttpGet]
public async Task<Result<string>> POk()
{
Result<string> result = new Result<string>();
result = await _IMsgApiClient.SendWxWorkMsgAsync("100001002", "我是沐雪,请明天来我办公室⼀趟!");
//result.state = true;
//result.data = "连接成功";
return result;
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。