sunpengfei
2025-08-08 7d043fd99fa51de6c0816aba75d020bf0f40b0b0
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;
@@ -42,79 +43,14 @@
        /// <typeparam name="TRequest"></typeparam>
        /// <typeparam name="TResponse"></typeparam>
        /// <param name="request"></param>
        /// <param name="provider"></param>
        /// <returns></returns>
        public static async Task<TResponse> SendHttpAsync<TRequest, TResponse>(TRequest request)
        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 token = App.HttpContext.Request.Headers["Authorization"].ToString();
            var refreshToken = App.HttpContext.Request.Headers["X-Authorization"].ToString();
            TResponse response;
            switch (resource.Method)
            {
                case EnumResourceMethod.Get:
                    response = await httpRemoteService.GetAsAsync<TResponse>(
                        $"{domain}{resource.Route}",
                        it =>
                            it.WithQueryParameters(request)
                            .AddAuthentication(new AuthenticationHeaderValue("Authorization", token))
                            .AddAuthentication(new AuthenticationHeaderValue("X-Authorization", refreshToken)));
                    break;
                case EnumResourceMethod.Post:
                    response = await httpRemoteService.PostAsAsync<TResponse>(
                        $"{domain}{resource.Route}",
                        it =>
                            it.SetJsonContent(request)
                            .WithHeader("Authorization", token)
                            .WithHeader("X-Authorization", refreshToken));
                    break;
                case EnumResourceMethod.Put:
                    response = await httpRemoteService.PutAsAsync<TResponse>(
                        $"{domain}{resource.Route}",
                        it =>
                            it.SetJsonContent(request)
                            .AddAuthentication(new AuthenticationHeaderValue("Authorization", token))
                            .AddAuthentication(new AuthenticationHeaderValue("X-Authorization", refreshToken)));
                    break;
                case EnumResourceMethod.Delete:
                    response = await httpRemoteService.DeleteAsAsync<TResponse>(
                        $"{domain}{resource.Route}",
                        it =>
                            it.SetJsonContent(request)
                            .AddAuthentication(new AuthenticationHeaderValue("Authorization", token))
                            .AddAuthentication(new AuthenticationHeaderValue("X-Authorization", refreshToken)));
                    break;
                default:
                    throw Oops.Oh(EnumErrorCodeType.s400, $"不支持请求方式{resource.Method}");
            }
            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>
@@ -181,13 +117,13 @@
                        model.ResponseTypeName = responseType.GetCSharpFriendlyName();
                        model.ResponseTypeFullName = responseType.FullName;
                    }
                    models.Add(model);
                    await App.GetRequiredService<IDistributedCache>().SetStringAsync($"ResourceModel|{model.RequestTypeFullName}", model.ToJson());
                }
            }
            var resources = await SaveResourcesAsync(models, traceId, rep);
            var resources = await SaveResourcesAsync(models, rep);
            DynamicControllersHotPlug(resources, provider);
@@ -201,7 +137,7 @@
        /// <param name="traceId"></param>
        /// <param name="rep"></param>
        /// <returns></returns>
        private static async Task<List<Resource>> SaveResourcesAsync(List<ResourceModel> models, string traceId, IRepository<Resource> rep = null)
        private static async Task<List<Resource>> SaveResourcesAsync(List<ResourceModel> models, IRepository<Resource> rep = null)
        {
            rep = rep ?? Db.GetRepository<Resource>();
            var resources = await rep.AsQueryable()
@@ -213,22 +149,33 @@
                if (resource == null)
                {
                    resource = new Resource();
                    resource.Id = IDGen.NextID();
                    resource.CreatedTime = DateTimeOffset.Now;
                    model.Adapt(resource);
                    await rep.InsertAsync(resource);
                    resources.Add(resource);
                }
                else
                {
                    model.Adapt(resource);
                    await rep.UpdateAsync(resource);
                    var resourceBakModel = new ResourceModel();
                    resource.Adapt(resourceBakModel);
                    resourceBakModel.TraceId = model.TraceId;
                    resourceBakModel.DynamicAssemblyName = model.DynamicAssemblyName;
                    if (resourceBakModel.ToJson() != model.ToJson())
                    {
                        model.Adapt(resource);
                        resource.UpdatedTime = DateTimeOffset.Now;
                        await rep.UpdateAsync(resource);
                    }
                }
            }
            var expiredResources = resources.Where(it => it.TraceId != traceId).ToList();
            var expiredResources = resources.Where(it => !models.Any(m => m.Route == it.Route && m.Method == it.Method)).ToList();
            foreach (var expiredResource in expiredResources)
            {
                expiredResource.IsExpired = true;
                await rep.UpdateAsync(expiredResource);
                //expiredResource.IsExpired = true;
                //await rep.UpdateAsync(expiredResource);
                await rep.DeleteAsync(expiredResource);
            }
            return resources.Where(it => !it.IsExpired).ToList();
@@ -276,9 +223,10 @@
                    code += $@"
        [AllowAnonymous]";
                }
                var result = resource.ResponseTypeName.IsNull() ? "Task" : $"Task<{resource.ResponseTypeName}>";
                code += $@"
        [Http{resource.Method}]
        public Task<{resource.ResponseTypeName}> {resource.ActionName}({resource.RequestTypeName} request)
        public {result} {resource.ActionName}({resource.RequestTypeName} request)
        {{
            return mediator.Send(request);
        }}
@@ -286,10 +234,18 @@
    }}
}}
";
                var dynamicAssembly = App.CompileCSharpClassCode(code);
                provider.AddAssembliesWithNotifyChanges(dynamicAssembly);
                var dynamicAssemblyName = dynamicAssembly.GetName().Name;
                resource.DynamicAssemblyName = dynamicAssemblyName;
                try
                {
                    var dynamicAssembly = App.CompileCSharpClassCode(code);
                    provider.AddAssembliesWithNotifyChanges(dynamicAssembly);
                    var dynamicAssemblyName = dynamicAssembly.GetName().Name;
                    resource.DynamicAssemblyName = dynamicAssemblyName;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(code);
                    throw;
                }
            }
        }