为什么需要框架组件
可以对比参考ABP框架中的微服务示例的通讯,abp的微服务示例是使用“异步消息通信”方式。与cp的微服务对比理解下
就是为了方便,把重复的代码都封装好。
参考
组件所在位置:Framework=》Cores
组件和服务的调用关系
中台调用组件(Middleware) ,没调用
注册中心组件(Registry),没调用
断路器Polly组件(Pollys),没调用
框架异常组件(Exceptions),没调用
负载均衡组件(Cluster) ,调用了
- 注册中心组件(Registry)
动态中台调用组件(DynamicMiddleware) ,调用了
- 中台调用组件(Middleware)
- 注册中心组件(Registry)
- 负载均衡组件(Cluster)
微服务客户端组件(MicroClients),调用了
- 动态中台调用组件(DynamicMiddleware)
- 断路器Polly组件(Pollys)
----------------------------------上面的是组件调用组件,下面的是服务调用组件----------------------------------
都是在Startup中使用组件
SeckillAggregateServices(秒杀聚合服务),Startup 调用了
- 微服务客户端组件(MicroClients)
- 使用了该组件的AddMicroClient方法来添加微服务客户端,该方法内实现了以下功能
- 注册AddMiddleware
- 注册客户端工厂
- 注册客户端集合
- 注册代理对象
services.AddMicroClient(options => { //程序集名称 options.AssmelyName = "RuanMou.Projects.SeckillAggregateServices"; //动态中台选项 options.dynamicMiddlewareOptions = mo => { //服务发现选项 mo.serviceDiscoveryOptions = sdo => //服务发现地址 { sdo.DiscoveryAddress = "http://localhost:8500"; }; }; });
OrderServices(订单服务)、PaymentServices(支付服务)、ProductServices(商品服务)、SeckillServices(秒杀服务)、UserServices(用户服务),Startup 调用了
- 注册中心组件(Registry)
- 使用了该组件的AddServiceRegistry方法来服务注册,该方法内实现了以下功能
- 配置选项到 IOC
- 注册consul注册
- 注册开机自动注册服务
- 使用了该组件的AddServiceRegistry方法来服务注册,该方法内实现了以下功能
下面是OrderServices(订单服务)使用注册中心组件示例:
services.AddServiceRegistry(options => { options.ServiceId = Guid.NewGuid().ToString(); //服务ID options.ServiceName = "OrderServices"; //服务名称 options.ServiceAddress = "https://localhost:5002"; //服务地址 options.HealthCheckAddress = "/HealthCheck"; //服务健康检查地址 options.RegistryAddress = "http://localhost:8500"; //服务注册地址 });
中台调用组件(Middleware)
如果要扩展为grpc框架通讯,只要创建一个另外一个类,实现IMiddleService接口的方法就好
中台结果:MiddleResult
JsonConvert.DeserializeObject:将JSON反序列化为指定的.NET类型
变量:
ErrorNo:0是成功,其他都是失败
ErrorInfo:失败信息
属性:
resultDic:用于非结果集返回
resultList:用于结果集返回
Result:返回动态结果(通用)
方法:
//把Json格式的字符串反序列化为MiddleResult
public static MiddleResult JsonToMiddleResult(string jsonStr)
构造函数:
//将JSON反序列化为指定的.NET类型
public MiddleResult(string jsonStr)
using Newtonsoft.Json; using System.Collections.Generic; namespace RuanMou.Projects.Cores.Middleware { /// <summary> /// 中台结果: /// 变量: /// SUCCESS:? /// ErrorNo:0是成功,其他都是失败 /// ErrorInfo:失败信息 /// /// 属性: /// resultDic:用于非结果集返回 /// resultList:用于结果集返回 /// Result:返回动态结果(通用) /// /// 方法: /// JsonToMiddleResult:把Json格式的字符串反序列化为MiddleResult /// /// 构造函数:根据传入的参数更新上面的变量和属性,都没有用到?需要调式确认 /// /// </summary> public class MiddleResult { public const string SUCCESS = "0"; //没有被用过?调式看看 /// <summary> /// 是否成功状态:0是成功,其他都是失败 /// </summary> public string ErrorNo { set; get; } /// <summary> /// 失败信息 /// </summary> public string ErrorInfo { set; get; } /// <summary> /// 用于非结果集返回 /// </summary> public IDictionary<string, object> resultDic { set; get; } /// <summary> /// 用于结果集返回 /// </summary> public IList<IDictionary<string, object>> resultList { set; get; } /// <summary> /// 返回动态结果(通用),使用动态解释数据类型dynamic /// </summary> public dynamic Result { set; get; } /// <summary> /// 构造函数():无参, /// resultDic(用于非结果集返回)=字典, /// resultList(用于结果集返回)=集合<字典> /// </summary> public MiddleResult() { resultDic = new Dictionary<string, object>(); resultList = new List<IDictionary<string, object>>(); } /// <summary> /// 构造函数(string):把Json格式的字符串反序列化为MiddleResult /// </summary> /// <param name="jsonStr"></param> public MiddleResult(string jsonStr) { MiddleResult result = JsonConvert.DeserializeObject<MiddleResult>(jsonStr); } /// <summary> /// 把Json格式的字符串反序列化为MiddleResult /// JsonConvert.DeserializeObject:将JSON反序列化为指定的.NET类型 /// </summary> /// <param name="jsonStr"></param> /// <returns></returns> public static MiddleResult JsonToMiddleResult(string jsonStr) { MiddleResult result = JsonConvert.DeserializeObject<MiddleResult>(jsonStr); return result; } /// <summary> /// 构造函数: /// </summary> /// <param name="errorNo"></param> /// <param name="errorInfo"></param> public MiddleResult(string errorNo, string errorInfo) { this.ErrorNo = errorNo; this.ErrorInfo = errorInfo; resultDic = new Dictionary<string, object>(); resultList = new List<IDictionary<string, object>>(); } //构造函数,引用上面2个参数的构造函数? public MiddleResult(string errorNo, string erroInfo, IDictionary<string, object> resultDic, IList<IDictionary<string, object>> resultList) : this(errorNo, erroInfo) { this.resultDic = resultDic; this.resultList = resultList; this.resultDic = resultDic; this.resultList = resultList; } } }
中台服务接口:IMiddleService
用MiddleResult类声明的方法名,如下
- Get:获取/查询
- Post:创建/新增
- Delete:删除
- Put:更新/修改
- PostDynamic:post请求动态参数
- PutDynamic:put请求动态参数
Http中台请求结果:HttpMiddleService(重点)
IHttpClientFactory:组件的工厂抽象,该组件可使用自定义配置为给定逻辑名称创建 HttpClient 实例
IHttpClientFactory.CreateClient(String):使用与 name
指定的逻辑名称相对应的配置来创建和配置 HttpClient 实例。
HttpClient:提供基本类,用于发送 HTTP 请求和接收来自通过 URI 确认的资源的 HTTP 响应。
HttpClient.PostAsync(string requestUri, HttpContent content):以异步操作将 POST 请求发送给指定 URI。
HttpContent:表示 HTTP 实体正文和内容标头的基类。
StringContent(String, Encoding, String):创建 System.Net.Http.StringContent 类的新实例
HttpResponseMessage:表示包括状态代码和数据的 HTTP 响应消息。
在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求
JsonConvert.SerializeObject:将指定的对象序列化为JSON字符串
核心的4行代码
private readonly IHttpClientFactory httpClientFactory; // HttpClient httpClient = httpClientFactory.CreateClient(String); // HttpContent hc = new StringContent(String, Encoding, String); // HttpResponseMessage response = await httpClient.PostAsync(string requestUri, HttpContent content);
另外添加的方法:
- 将HttpResponseMessage转换成MiddleResult类的Json格式
- private MiddleResult GetMiddleResult(HttpResponseMessage httpResponseMessage)
实现接口IMiddleService的全部方法 :这些方法返回的都是上面的MiddleResult方法,返回Json格式
- Get:获取/查询
- public MiddleResult Get(string middleUrl, IDictionary<string, object> middleParam)
- Post:创建/新增
- public MiddleResult Post(string middleUrl, IDictionary<string, object> middleParam)
- public MiddleResult Post(string middleUrl, IList<IDictionary<string, object>> middleParams)
- Delete:删除
- public MiddleResult Delete(string middleUrl, IDictionary<string, object> middleParam)
- Put:更新/修改
- public MiddleResult Put(string middleUrl, IDictionary<string, object> middleParam)
- public MiddleResult Put(string middleUrl, IList<IDictionary<string, object>> middleParams)
- PostDynamic:post请求动态参数
- public MiddleResult PostDynamic(string middleUrl, dynamic middleParam)
- PutDynamic:put请求动态参数
- public MiddleResult PutDynamic(string middleUrl, dynamic middleParam)
using Newtonsoft.Json; using RuanMou.Projects.Commons.Exceptions; using RuanMou.Projects.Cores.Middleware.transports; using RuanMou.Projects.Cores.Utils; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Text; namespace RuanMou.Projects.Cores.Middleware.support { /// <summary> /// Http中台请求结果: /// 实现接口IMiddleService的全部方法 /// HttpClient:提供用于发送 HTTP 请求并从 URI 标识的资源接收 HTTP 响应的基类 /// .GetAsync、.PostAsync、.PutAsync、.DeleteAsync:以异步操作将这几种请求发送给指定URI /// .Result:获取此 System.Threading.Tasks.Task`1 的结果值 /// IHttpClientFactory:组件的工厂抽象,该组件可使用自定义配置为给定逻辑名称创建 HttpClient 实例 /// IHttpClientFactory.CreateClient:使用与 name 指定的逻辑名称相对应的配置来创建和配置 HttpClient 实例。 /// HttpResponseMessage:表示包括状态代码和数据的 HTTP 响应消息 /// HttpContent:表示 HTTP 实体正文和内容标头的基类 /// JsonConvert.SerializeObject:将指定的对象序列化为JSON字符串。 /// </summary> public class HttpMiddleService : IMiddleService { private IHttpClientFactory httpClientFactory; private const string HttpConst = "mrico"; public HttpMiddleService(IHttpClientFactory httpClientFactory) { this.httpClientFactory = httpClientFactory; } public MiddleResult Delete(string middleUrl, IDictionary<string, object> middleParam) { // 1、获取httpClient HttpClient httpClient = httpClientFactory.CreateClient(HttpConst); // 2、Delete请求 以异步操作将 DELETE 请求发送给指定 URI。 HttpResponseMessage httpResponseMessage = httpClient.DeleteAsync(middleUrl).Result; return GetMiddleResult(httpResponseMessage); } public MiddleResult Get(string middleUrl, IDictionary<string, object> middleParam) { // 1、获取httpClient HttpClient httpClient = httpClientFactory.CreateClient(HttpConst); // 2、参数转换为url方式 string urlParam = HttpParamUtil.DicToHttpUrlParam(middleParam); // 3、Get请求 HttpResponseMessage httpResponseMessage = httpClient.GetAsync(middleUrl + urlParam).Result; return GetMiddleResult(httpResponseMessage); } public MiddleResult Post(string middleUrl, IDictionary<string, object> middleParam) { // 1、获取httpClient HttpClient httpClient = httpClientFactory.CreateClient(HttpConst); // 2、转换成json参数 HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParam), Encoding.UTF8, "application/json"); // 3、Post请求 HttpResponseMessage httpResponseMessage = httpClient.PostAsync(middleUrl, httpContent).Result; return GetMiddleResult(httpResponseMessage); } public MiddleResult Post(string middleUrl, IList<IDictionary<string, object>> middleParams) { // 1、获取httpClient HttpClient httpClient = httpClientFactory.CreateClient(HttpConst); // 2、转换成json参数 HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParams), Encoding.UTF8, "application/json"); // 3、Post请求 HttpResponseMessage httpResponseMessage = httpClient.PostAsync(middleUrl, httpContent).Result; return GetMiddleResult(httpResponseMessage); } public MiddleResult PostDynamic(string middleUrl, dynamic middleParam) { // 1、获取httpClient HttpClient httpClient = httpClientFactory.CreateClient(HttpConst); // 2、转换成json参数 HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParam), Encoding.UTF8, "application/json"); // 3、Post请求 HttpResponseMessage httpResponseMessage = httpClient.PostAsync(middleUrl, httpContent).Result; return GetMiddleResult(httpResponseMessage); } public MiddleResult Put(string middleUrl, IDictionary<string, object> middleParam) { // 1、获取httpClient HttpClient httpClient = httpClientFactory.CreateClient(HttpConst); // 2、转换成json参数 HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParam), Encoding.UTF8, "application/json"); // 3、Put请求 HttpResponseMessage httpResponseMessage = httpClient.PutAsync(middleUrl, httpContent).Result; return GetMiddleResult(httpResponseMessage); } public MiddleResult Put(string middleUrl, IList<IDictionary<string, object>> middleParams) { // 1、获取httpClient HttpClient httpClient = httpClientFactory.CreateClient(HttpConst); // 2、转换成json参数 HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParams), Encoding.UTF8, "application/json"); // 3、Put请求 HttpResponseMessage httpResponseMessage = httpClient.PutAsync(middleUrl, httpContent).Result; return GetMiddleResult(httpResponseMessage); } public MiddleResult PutDynamic(string middleUrl, dynamic middleParam) { // 1、获取httpClient HttpClient httpClient = httpClientFactory.CreateClient(HttpConst); // 2、转换成json参数 HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(middleParam), Encoding.UTF8, "application/json"); // 3、Put请求 HttpResponseMessage httpResponseMessage = httpClient.PutAsync(middleUrl, httpContent).Result; return GetMiddleResult(httpResponseMessage); } /// <summary> /// 将HttpResponseMessage转换成MiddleResult类的Json格式 /// </summary> /// <param name="httpResponseMessage"></param> /// <returns></returns> private MiddleResult GetMiddleResult(HttpResponseMessage httpResponseMessage) { // 3、将HttpResponseMessage转换成MiddleResult if (httpResponseMessage.StatusCode.Equals(HttpStatusCode.OK) || httpResponseMessage.StatusCode.Equals(HttpStatusCode.Created) || httpResponseMessage.StatusCode.Equals(HttpStatusCode.Accepted)) { string httpJsonString = httpResponseMessage.Content.ReadAsStringAsync().Result; // 3.1 创建MiddleResult return MiddleResult.JsonToMiddleResult(httpJsonString); } else { throw new FrameException($"{HttpConst}服务调用错误:{httpResponseMessage.Content.ReadAsStringAsync().ToString()}"); } } } }
中台配置选项:MiddlewareOptions
两个属性:polly熔断降级选项、客户端名称
- public Action<PollyHttpClientOptions> pollyHttpClientOptions { get; }
- public string HttpClientName { set; get; }
中台ServiceCollection扩展方法:MiddlewareServiceCollectionExtensions
使用上面的MiddlewareOptions类
添加中台
- 使用中台配置选项MiddlewareOptions
- 使用自定义的Polly熔断组件
- 注册中台组件:中台组件的接口与实现类注入
using Microsoft.Extensions.DependencyInjection; using RuanMou.Projects.Cores.Cluster.Extentions; using RuanMou.Projects.Cores.HttpClientPolly; using RuanMou.Projects.Cores.Middleware.options; using RuanMou.Projects.Cores.Middleware.support; using RuanMou.Projects.Cores.Middleware.transports; using RuanMou.Projects.Cores.Middleware.Urls; using RuanMou.Projects.Cores.Middleware.Urls.consul; using RuanMou.Projects.Cores.Registry.Extentions; using System; namespace RuanMou.Projects.Cores.Middleware.Extentions { /// <summary> /// 中台组件的ServiceCollection扩展方法:以便在Startup类的ConfigureServices方法可以使用此组件 /// </summary> public static class MiddlewareServiceCollectionExtensions { /// <summary> /// 添加中台 /// </summary> /// <typeparam name="IMiddleService"></typeparam> /// <param name="services"></param> /// <returns></returns> public static IServiceCollection AddMiddleware(this IServiceCollection services) { AddMiddleware(services, options => {}); return services; } /// <summary> /// 添加中台: /// 1 使用中台配置选项MiddlewareOptions /// 2 使用自定义的Polly熔断组件 /// 3 注册中台组件:中台组件的接口与实现类注入 /// </summary> /// <typeparam name="IMiddleService"></typeparam> /// <param name="services"></param> /// <returns></returns> public static IServiceCollection AddMiddleware(this IServiceCollection services, Action<MiddlewareOptions> options) { MiddlewareOptions middlewareOptions = new MiddlewareOptions(); options(middlewareOptions); // 1、注册到IOC services.Configure<MiddlewareOptions>(options); // 2、添加HttpClient,使用自定义的Polly熔断组件 // services.AddHttpClient(middlewareOptions.HttpClientName); services.AddPollyHttpClient(middlewareOptions.HttpClientName, middlewareOptions.pollyHttpClientOptions); // 3、注册中台组件:中台组件的接口与实现类注入 //AddSingleton:将TService 中指定类型的单一实例服务和 TImplementation中指定类型的实现添加到指定的IServiceCollection 中。 services.AddSingleton<IMiddleService, HttpMiddleService>(); return services; } } }
断路器Polly组件封装(Pollys)
注册中心组件封装(Registry)
负载均衡组件封装(Cluster)
动态中台调用组件封装(DynamicMiddleware)
微服务客户端组件封装(MicroClients)
框架异常组件封装(Exceptions)