FlexJobApi.Core/FlexJobApi.Core.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
FlexJobApi.Core/FlexJobApiCoreStartup.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
FlexJobApi.Core/Models/FlexJobServer/Tasks/Repositories/TaskInfoRepository.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
FlexJobApi.Core/Utils/ResourceUtils/ResourceHttpUtils.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
FlexJobApi.Core/Utils/ResourceUtils/ResourceModel.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
FlexJobApi.FlexJobServer.Test/FlexJobApi.FlexJobServer.Test.csproj | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
FlexJobApi.FlexJobServer.Test/Program.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
FlexJobApi.FlexJobServer.Test/Startup.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
FlexJobApi.FlexJobServer.Test/Tasks/TaskUnitTest.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
FlexJobApi.Core/FlexJobApi.Core.xml
@@ -5640,6 +5640,23 @@ </summary> <returns></returns> </member> <member name="M:FlexJobApi.Core.ResourceHttpUtils.SendHttpAsync``2(``0,FlexJobApi.Core.IResourceHttpProvider)"> <summary> 发送HTTP请求 </summary> <typeparam name="TRequest"></typeparam> <typeparam name="TResponse"></typeparam> <param name="request"></param> <param name="provider"></param> <returns></returns> </member> <member name="M:FlexJobApi.Core.ResourceHttpUtils.GetHealthyServiceDomain(FlexJobApi.Core.ResourceModel)"> <summary> 获取健康服务域名 </summary> <param name="resource"></param> <returns></returns> </member> <member name="P:FlexJobApi.Core.ResourceModel.TraceId"> <summary> 跟踪Id @@ -5798,13 +5815,6 @@ <typeparam name="TResponse"></typeparam> <param name="request"></param> <param name="provider"></param> <returns></returns> </member> <member name="M:FlexJobApi.Core.ResourceUtils.GetHealthyServiceDomain(FlexJobApi.Core.Resource)"> <summary> 获取健康服务域名 </summary> <param name="resource"></param> <returns></returns> </member> <member name="M:FlexJobApi.Core.ResourceUtils.BuildDynamicControllersAsync"> FlexJobApi.Core/FlexJobApiCoreStartup.cs
@@ -43,14 +43,15 @@ services.AddConfigurableOptions<AliyunOptions>(); services.AddHttpRemote(); services.AddComponent<ConsulServiceComponent>(); services.AddComponent<EventBusServiceComponent>(); services.AddComponent<DistributedCacheServiceComponent>(); services.AddHttpRemote(); services.AddSingleton<ResourceHttpUtils>(); services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(App.Assemblies.ToArray())); services.AddHostedService<XmlDocBuildHostedService>(); FlexJobApi.Core/Models/FlexJobServer/Tasks/Repositories/TaskInfoRepository.cs
@@ -25,7 +25,10 @@ logier = logier ?? JwtUtils.GetCurrentLogier(); return rep.AsQueryable().AsNoTracking() .OrderBy(it => it.BeginTime) .Where(it => it.EnterpriseId == logier.EnterpriseId); .Where(it => logier.Type == EnumUserType.Enterprise ? it.EnterpriseId == logier.EnterpriseId : true); } } } FlexJobApi.Core/Utils/ResourceUtils/ResourceHttpUtils.cs
New file @@ -0,0 +1,81 @@ using Consul; using Furion; using Furion.FriendlyException; using Furion.HttpRemote; using Microsoft.Extensions.Caching.Distributed; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FlexJobApi.Core { public class ResourceHttpUtils { private readonly IDistributedCache distributedCache; private readonly IHttpRemoteService httpRemoteService; private readonly IConsulClient consulClient; public ResourceHttpUtils( IDistributedCache distributedCache, IHttpRemoteService httpRemoteService, IConsulClient consulClient) { this.distributedCache = distributedCache; this.httpRemoteService = httpRemoteService; this.consulClient = consulClient; } /// <summary> /// 发送HTTP请求 /// </summary> /// <typeparam name="TRequest"></typeparam> /// <typeparam name="TResponse"></typeparam> /// <param name="request"></param> /// <param name="provider"></param> /// <returns></returns> public async Task<TResponse> SendHttpAsync<TRequest, TResponse>( TRequest request, IResourceHttpProvider provider = null) where TRequest : class, new() { var requestTypeFullName = typeof(TRequest).FullName; var jsonResourceModels = await distributedCache.GetStringAsync($"ResourceModel|{requestTypeFullName}"); var resource = jsonResourceModels.JsonTo<ResourceModel>(); var domain = await GetHealthyServiceDomain(resource); var builder = HttpRequestBuilder.Create(resource.GetHttpMethod(), $"{domain}{resource.Route}"); if (resource.Method == EnumResourceMethod.Get) builder = builder.WithQueryParameters(request); else builder = builder.SetJsonContent(request); provider = provider ?? new DefaultResourceHttpProvider(); builder = provider.AddAuthentication(builder); var response = await provider.SendAsAsync<TResponse>(httpRemoteService, builder); return response; } /// <summary> /// 获取健康服务域名 /// </summary> /// <param name="resource"></param> /// <returns></returns> public async Task<string> GetHealthyServiceDomain(ResourceModel resource) { var queryResult = await consulClient.Health.Service(resource.ServiceName, null, true); if (queryResult.StatusCode != System.Net.HttpStatusCode.OK) throw Oops.Oh(EnumErrorCodeType.s404, $"微服务{resource.Service}"); var domains = queryResult.Response .Select(s => $"http://{s.Service.Address}:{s.Service.Port}") .ToList(); if (domains.IsNull()) throw Oops.Oh(EnumErrorCodeType.s404, $"微服务{resource.Service}"); // 轮询选择实例 int randomIndex = new Random().Next(domains.Count); return domains[randomIndex]; } } } FlexJobApi.Core/Utils/ResourceUtils/ResourceModel.cs
@@ -1,7 +1,9 @@ using System; using Furion.FriendlyException; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; @@ -103,5 +105,22 @@ /// 响应类型全名 /// </summary> public string ResponseTypeFullName { get; set; } public HttpMethod GetHttpMethod() { switch (Method) { case EnumResourceMethod.Get: return HttpMethod.Get; case EnumResourceMethod.Post: return HttpMethod.Post; case EnumResourceMethod.Put: return HttpMethod.Put; case EnumResourceMethod.Delete: return HttpMethod.Delete; default: throw Oops.Oh(EnumErrorCodeType.s400, "不支持的请求类型"); } } } } FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs
@@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Routing; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; @@ -44,48 +45,12 @@ /// <param name="request"></param> /// <param name="provider"></param> /// <returns></returns> public static async Task<TResponse> SendHttpAsync<TRequest, TResponse>( public static Task<TResponse> SendHttpAsync<TRequest, TResponse>( TRequest request, IResourceHttpProvider provider = null) where TRequest : class, new() { var requestTypeFullName = typeof(TRequest).FullName; var resource = await Db.GetRepository<Resource>().AsQueryable().AsNoTracking() .Where(it => !it.IsExpired && it.RequestTypeFullName == requestTypeFullName) .FirstOrDefaultAsync(); var domain = await GetHealthyServiceDomain(resource); var httpRemoteService = App.GetRequiredService<IHttpRemoteService>(); var builder = HttpRequestBuilder.Create(resource.GetHttpMethod(), $"{domain}{resource.Route}"); if (resource.Method == EnumResourceMethod.Get) builder = builder.WithQueryParameters(request); else builder = builder.SetJsonContent(request); provider = provider ?? new DefaultResourceHttpProvider(); builder = provider.AddAuthentication(builder); var response = await provider.SendAsAsync<TResponse>(httpRemoteService, builder); return response; } /// <summary> /// 获取健康服务域名 /// </summary> /// <param name="resource"></param> /// <returns></returns> public static async Task<string> GetHealthyServiceDomain(Resource resource) { var client = App.GetRequiredService<IConsulClient>(); var queryResult = await client.Health.Service(resource.ServiceName, null, true); if (queryResult.StatusCode != System.Net.HttpStatusCode.OK) throw Oops.Oh(EnumErrorCodeType.s404, $"微服务{resource.Service}"); var domains = queryResult.Response .Select(s => $"http://{s.Service.Address}:{s.Service.Port}") .ToList(); if (domains.IsNull()) throw Oops.Oh(EnumErrorCodeType.s404, $"微服务{resource.Service}"); // 轮询选择实例 int randomIndex = new Random().Next(domains.Count); return domains[randomIndex]; return App.GetRequiredService<ResourceHttpUtils>().SendHttpAsync<TRequest, TResponse>(request, provider); } /// <summary> @@ -152,9 +117,9 @@ model.ResponseTypeName = responseType.GetCSharpFriendlyName(); model.ResponseTypeFullName = responseType.FullName; } models.Add(model); await App.GetRequiredService<IDistributedCache>().SetStringAsync($"ResourceModel|{model.RequestTypeFullName}", model.ToJson()); } } FlexJobApi.FlexJobServer.Test/FlexJobApi.FlexJobServer.Test.csproj
@@ -17,8 +17,9 @@ <ItemGroup> <PackageReference Include="coverlet.collector" Version="6.0.2" /> <PackageReference Include="Furion.Xunit" Version="4.9.7.108" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" /> <PackageReference Include="xunit" Version="2.9.2" /> <PackageReference Include="xunit" Version="2.9.3" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" /> </ItemGroup> FlexJobApi.FlexJobServer.Test/Program.cs
New file @@ -0,0 +1 @@ Serve.Run(RunOptions.Default.WithArgs(args)); FlexJobApi.FlexJobServer.Test/Startup.cs
New file @@ -0,0 +1,71 @@ using Consul; using FlexJobApi.Core; using Furion; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FlexJobApi.FlexJobServer.Test { public class Startup : AppStartup { public void ConfigureServices(IServiceCollection services, IConfiguration config) { services.AddSingleton<IConsulClient, ConsulClient>(p => new ConsulClient(options => { var address = config["Consul:Address"] ?? "http://localhost:8500"; options.Address = new Uri(address); })); services.AddComponent<DistributedCacheServiceComponent>(); services.AddHttpRemote(); services.AddSingleton<ResourceHttpUtils>(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConfiguration config) { var consulClient = app.ApplicationServices.GetRequiredService<IConsulClient>(); var lifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>(); // 服务配置(从appsettings.json读取) var serviceName = config["Consul:ServiceName"] ?? "UnknownService"; var serviceHost = config["Consul:ServiceIP"] ?? "localhost"; var servicePort = int.Parse(config["Consul:ServicePort"]); // 或直接用启动端口 // 服务唯一ID(避免同一服务多实例冲突) var serviceId = $"{serviceName}-{serviceHost}-{servicePort}"; // 服务注册信息 var registration = new AgentServiceRegistration { ID = serviceId, Name = serviceName, Address = serviceHost, Port = servicePort, // 健康检查配置 Check = new AgentServiceCheck { HTTP = $"http://{serviceHost}:{servicePort}{config["Consul:ServiceHealthCheck"]}", Interval = TimeSpan.FromSeconds(10), Timeout = TimeSpan.FromSeconds(5), DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(30) } }; // 注册服务 consulClient.Agent.ServiceRegister(registration).Wait(); // 应用停止时注销服务 lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(serviceId).Wait(); }); } } } FlexJobApi.FlexJobServer.Test/Tasks/TaskUnitTest.cs
@@ -5,10 +5,17 @@ { public class TaskUnitTest { private readonly ResourceHttpUtils http; public TaskUnitTest(ResourceHttpUtils http) { this.http = http; } [Fact] public async Task Test1() { var categories = await ResourceUtils.SendHttpAsync< var categories = await http.SendHttpAsync< GetDictionaryCategorySelectQuery, FriendlyResult<SelectOption<Guid, GetDictionaryCategorySelectQueryOption>>>( new GetDictionaryCategorySelectQuery());