.NET Core微服务还有哪些不同的实现途径?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1238个文字,预计阅读时间需要5分钟。
前言:基于.net core的微服务,网上许多介绍都是千篇一律的示例,基于类似webapi的格式,通过HTTP请求形式进行访问,但这并不符合大型企业的使用习惯。如何像[GetServiceIOrderService()]SaveOrder(orderInfo)这样的方式,直接调用?
解答:为了满足大型企业的使用习惯,我们可以采用如下方法来实现类似[GetServiceIOrderService()]SaveOrder(orderInfo)的调用方式:
1. 创建一个统一的调用代理类,封装微服务调用逻辑。
2.在代理类中,根据需要调用的微服务接口,动态创建相应的服务实例。
3.使用反射或代码生成等技术,自动生成调用方法的参数和返回类型。
以下是一个简单的示例:
csharp
public class ServiceProxy{ public void SaveOrder(OrderInfo orderInfo) { var orderService=GetService(); orderService.SaveOrder(orderInfo); }private T GetService() { // 根据需要调用的微服务接口,动态创建服务实例 // 这里只是一个示例,具体实现取决于你的服务发现和注册机制 var serviceInstance=// ... 获取服务实例 return (T)serviceInstance; }}
public interface IOrderService{ void SaveOrder(OrderInfo orderInfo);}
public class OrderInfo{ // ... 订单信息}
这样,你就可以像调用本地方法一样调用微服务了。当然,具体的实现细节还需要根据你的实际项目需求进行调整。
前言
基于.net core 的微服务,网上很多介绍都是千篇一律基于类似webapi,通过localhost:8801/api/svc" }, { "ServiceId": "XZL.Api.IUserService", "Address": "localhost:8802/api/svc" } ]
AppRuntime.Instance.GetService<TService>()的实现.
private static List<(string typeName, Type svcType)> svcTypeDic; private static ConcurrentDictionary<string, Object> svcInstance = new ConcurrentDictionary<string, object>(); public static TService GetService<TService>() { var serviceId = typeof(TService).FullName; //读取服务配置 var serviceInfo = ServiceConfonfig.Instance.GetServiceInfo(serviceId); if (serviceInfo == null) { return (TService)Activator.CreateInstance(GetSvcType(serviceId)); } else { var rs = GetService<TService>(serviceId + (serviceInfo.IsRemote ? "|Remote" : ""), serviceInfo.IsSingle); if (rs != null && rs is RemoteServiceProxy) { var temp = rs as RemoteServiceProxy; temp.Address = serviceInfo.Address; //指定服务地址 } return rs; } } public static TService GetService<TService>(string interfaceId, bool isSingle) { //服务非单例模式 if (!isSingle) { return (TService)Activator.CreateInstance(GetSvcType(interfaceId)); } object obj = null; if (svcInstance.TryGetValue(interfaceId, out obj) && obj != null) { return (TService)obj; } var svcType = GetSvcType(interfaceId); if (svcType == null) { throw new ICVIPException($"系统中未找到[{interfaceId}]的代理类"); } obj = Activator.CreateInstance(svcType); svcInstance.TryAdd(interfaceId, obj); return (TService)obj; } //获取服务的实现类 public static Type GetSvcType(string interfaceId, bool? isLocal = null) { if (!_loaded) { LoadServiceType(); } Type rs = null; var tempKey = interfaceId; var temp = svcTypeDic.Where(x => x.typeName == tempKey).ToList(); if (temp == null || temp.Count == 0) { return rs; } if (isLocal.HasValue) { if (isLocal.Value) { rs = temp.FirstOrDefault(t => !typeof(RemoteServiceProxy).IsAssignableFrom(t.svcType)).svcType; } else { rs = temp.FirstOrDefault(t => typeof(RemoteServiceProxy).IsAssignableFrom(t.svcType)).svcType; } } else { rs = temp[0].svcType; } return rs; }
为了性能影响,我们在程序启动的时候可以将当前所有的ApiService类型缓存.
public static void LoadServiceType() { if (_loaded) { return; } lock (_sync) { if (_loaded) { return; } try { svcTypeDic = new List<(string typeName, Type svcType)>(); var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory; var dir = new DirectoryInfo(path); var files = dir.GetFiles("XZL*.dll"); foreach (var file in files) { var types = LoadAssemblyFromFile(file); svcTypeDic.AddRange(types); } _loaded = true; } catch { _loaded = false; } } } //加载指定文件中的ApiService实现 private static List<(string typeName, Type svcType)> LoadAssemblyFromFile(FileInfo file) { var lst = new List<(string typeName, Type svcType)>(); if (file.Extension != ".dll" && file.Extension != ".exe") { return lst; } try { var types = Assembly.Load(file.Name.Substring(0, file.Name.Length - 4)) .GetTypes() .Where(c => c.IsClass && !c.IsAbstract && c.IsPublic); foreach (Type type in types) { //客户端代理基类 if (type == typeof(RemoteServiceProxy)) { continue; } if (!typeof(IApiService).IsAssignableFrom(type)) { continue; } //绑定现类 lst.Add((type.FullName, type)); foreach (var interfaceType in type.GetInterfaces()) { if (!typeof(IApiService).IsAssignableFrom(interfaceType)) { continue; } //绑定接口与实际实现类 lst.Add((interfaceType.FullName, type)); } } } catch { } return lst; }
具体api远程服务代理示例
public class UserServiceProxy : RemoteServiceProxy, IUserService { private string serviceId = typeof(IUserService).FullName; public void IncreaseScore(int userId,int score) { return InvokeWithoutReturn(serviceId, nameof(IncreaseScore), userId,score); } public UserInfo GetUserById(int userId) { return Invoke<UserInfo >(serviceId, nameof(GetUserById), userId); } }
结语
经过以上改造后, 我们便可很方便的通过形如 AppRuntime.Instance.GetService<TService>().MethodXX()无感的访问远程服务, 服务是部署在远程还是在本地以dll依赖形式存在,这个便对调用者透明了.无缝的对接上了大家固有习惯.
PS: 但是此番改造后, 遗留下来了另外一个问题: 客户端调用远程服务,需要手动创建一个服务代理( 从 RemoteServiceProxy 继承),虽然每个代理很方便写,只是文中提到的简单两句话,但终究显得繁琐, 是否有一种方式能够根据远程api接口动态的生成这个客户端代理呢? 答案是肯定的,因本文较长了,留在下篇再续
附上动态编译文章链接:www.jb51.net/article/144101.htm
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对易盾网络的支持。
本文共计1238个文字,预计阅读时间需要5分钟。
前言:基于.net core的微服务,网上许多介绍都是千篇一律的示例,基于类似webapi的格式,通过HTTP请求形式进行访问,但这并不符合大型企业的使用习惯。如何像[GetServiceIOrderService()]SaveOrder(orderInfo)这样的方式,直接调用?
解答:为了满足大型企业的使用习惯,我们可以采用如下方法来实现类似[GetServiceIOrderService()]SaveOrder(orderInfo)的调用方式:
1. 创建一个统一的调用代理类,封装微服务调用逻辑。
2.在代理类中,根据需要调用的微服务接口,动态创建相应的服务实例。
3.使用反射或代码生成等技术,自动生成调用方法的参数和返回类型。
以下是一个简单的示例:
csharp
public class ServiceProxy{ public void SaveOrder(OrderInfo orderInfo) { var orderService=GetService(); orderService.SaveOrder(orderInfo); }private T GetService() { // 根据需要调用的微服务接口,动态创建服务实例 // 这里只是一个示例,具体实现取决于你的服务发现和注册机制 var serviceInstance=// ... 获取服务实例 return (T)serviceInstance; }}
public interface IOrderService{ void SaveOrder(OrderInfo orderInfo);}
public class OrderInfo{ // ... 订单信息}
这样,你就可以像调用本地方法一样调用微服务了。当然,具体的实现细节还需要根据你的实际项目需求进行调整。
前言
基于.net core 的微服务,网上很多介绍都是千篇一律基于类似webapi,通过localhost:8801/api/svc" }, { "ServiceId": "XZL.Api.IUserService", "Address": "localhost:8802/api/svc" } ]
AppRuntime.Instance.GetService<TService>()的实现.
private static List<(string typeName, Type svcType)> svcTypeDic; private static ConcurrentDictionary<string, Object> svcInstance = new ConcurrentDictionary<string, object>(); public static TService GetService<TService>() { var serviceId = typeof(TService).FullName; //读取服务配置 var serviceInfo = ServiceConfonfig.Instance.GetServiceInfo(serviceId); if (serviceInfo == null) { return (TService)Activator.CreateInstance(GetSvcType(serviceId)); } else { var rs = GetService<TService>(serviceId + (serviceInfo.IsRemote ? "|Remote" : ""), serviceInfo.IsSingle); if (rs != null && rs is RemoteServiceProxy) { var temp = rs as RemoteServiceProxy; temp.Address = serviceInfo.Address; //指定服务地址 } return rs; } } public static TService GetService<TService>(string interfaceId, bool isSingle) { //服务非单例模式 if (!isSingle) { return (TService)Activator.CreateInstance(GetSvcType(interfaceId)); } object obj = null; if (svcInstance.TryGetValue(interfaceId, out obj) && obj != null) { return (TService)obj; } var svcType = GetSvcType(interfaceId); if (svcType == null) { throw new ICVIPException($"系统中未找到[{interfaceId}]的代理类"); } obj = Activator.CreateInstance(svcType); svcInstance.TryAdd(interfaceId, obj); return (TService)obj; } //获取服务的实现类 public static Type GetSvcType(string interfaceId, bool? isLocal = null) { if (!_loaded) { LoadServiceType(); } Type rs = null; var tempKey = interfaceId; var temp = svcTypeDic.Where(x => x.typeName == tempKey).ToList(); if (temp == null || temp.Count == 0) { return rs; } if (isLocal.HasValue) { if (isLocal.Value) { rs = temp.FirstOrDefault(t => !typeof(RemoteServiceProxy).IsAssignableFrom(t.svcType)).svcType; } else { rs = temp.FirstOrDefault(t => typeof(RemoteServiceProxy).IsAssignableFrom(t.svcType)).svcType; } } else { rs = temp[0].svcType; } return rs; }
为了性能影响,我们在程序启动的时候可以将当前所有的ApiService类型缓存.
public static void LoadServiceType() { if (_loaded) { return; } lock (_sync) { if (_loaded) { return; } try { svcTypeDic = new List<(string typeName, Type svcType)>(); var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory; var dir = new DirectoryInfo(path); var files = dir.GetFiles("XZL*.dll"); foreach (var file in files) { var types = LoadAssemblyFromFile(file); svcTypeDic.AddRange(types); } _loaded = true; } catch { _loaded = false; } } } //加载指定文件中的ApiService实现 private static List<(string typeName, Type svcType)> LoadAssemblyFromFile(FileInfo file) { var lst = new List<(string typeName, Type svcType)>(); if (file.Extension != ".dll" && file.Extension != ".exe") { return lst; } try { var types = Assembly.Load(file.Name.Substring(0, file.Name.Length - 4)) .GetTypes() .Where(c => c.IsClass && !c.IsAbstract && c.IsPublic); foreach (Type type in types) { //客户端代理基类 if (type == typeof(RemoteServiceProxy)) { continue; } if (!typeof(IApiService).IsAssignableFrom(type)) { continue; } //绑定现类 lst.Add((type.FullName, type)); foreach (var interfaceType in type.GetInterfaces()) { if (!typeof(IApiService).IsAssignableFrom(interfaceType)) { continue; } //绑定接口与实际实现类 lst.Add((interfaceType.FullName, type)); } } } catch { } return lst; }
具体api远程服务代理示例
public class UserServiceProxy : RemoteServiceProxy, IUserService { private string serviceId = typeof(IUserService).FullName; public void IncreaseScore(int userId,int score) { return InvokeWithoutReturn(serviceId, nameof(IncreaseScore), userId,score); } public UserInfo GetUserById(int userId) { return Invoke<UserInfo >(serviceId, nameof(GetUserById), userId); } }
结语
经过以上改造后, 我们便可很方便的通过形如 AppRuntime.Instance.GetService<TService>().MethodXX()无感的访问远程服务, 服务是部署在远程还是在本地以dll依赖形式存在,这个便对调用者透明了.无缝的对接上了大家固有习惯.
PS: 但是此番改造后, 遗留下来了另外一个问题: 客户端调用远程服务,需要手动创建一个服务代理( 从 RemoteServiceProxy 继承),虽然每个代理很方便写,只是文中提到的简单两句话,但终究显得繁琐, 是否有一种方式能够根据远程api接口动态的生成这个客户端代理呢? 答案是肯定的,因本文较长了,留在下篇再续
附上动态编译文章链接:www.jb51.net/article/144101.htm
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对易盾网络的支持。

