From b5c75c9edf9c13a8bd4ba2f0596a1ceaf2563c6b Mon Sep 17 00:00:00 2001 From: sunpengfei <i@angelzzz.com> Date: 星期四, 14 八月 2025 10:05:30 +0800 Subject: [PATCH] feat:开发 --- FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs | 205 +++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 149 insertions(+), 56 deletions(-) diff --git a/FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs b/FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs index fb77aa3..f381e16 100644 --- a/FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs +++ b/FlexJobApi.Core/Utils/ResourceUtils/ResourceUtils.cs @@ -1,24 +1,34 @@ -锘縰sing FlexJobApi.User.Application; +锘縰sing Consul; using Furion; using Furion.DatabaseAccessor; +using Furion.DataEncryption; using Furion.DistributedIDGenerator; using Furion.DynamicApiController; using Furion.FriendlyException; +using Furion.HttpRemote; using Mapster; using MediatR; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ActionConstraints; 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; +using System.ComponentModel; +using System.Diagnostics; using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; using System.Reflection; +using System.Resources; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using static System.Collections.Specialized.BitVector32; namespace FlexJobApi.Core { @@ -35,15 +45,15 @@ var traceId = App.GetTraceId() ?? IDGen.NextID().ToString(); var scopeFactory = App.GetService<IServiceScopeFactory>(); var serviceScope = scopeFactory.CreateScope(); - var rep = serviceScope.ServiceProvider.GetRequiredService<IRepository<Resource>>(); var provider = serviceScope.ServiceProvider.GetRequiredService<IDynamicApiRuntimeChangeProvider>(); + var rep = serviceScope.ServiceProvider.GetRequiredService<IRepository<Resource>>(); var xmlDoc = await XmlDocUtils.GetXmlDocAsync(); var enumWebApiMethods = await EnumUtils.GetModel<EnumResourceMethod>(); var resourceControllers = await EnumUtils.GetModel<EnumResourceController>(); - var requests = App.Assemblies.SelectMany(it => it.GetTypes()).Where(it => typeof(IBaseRequest).IsAssignableFrom(it)).ToList(); - var resources = await rep.AsQueryable() - .Where(it => !it.IsExpired) - .ToListAsync(); + var requests = App.Assemblies + .SelectMany(it => it.GetTypes()) + .Where(it => !it.IsAbstract && typeof(IBaseRequest).IsAssignableFrom(it)) + .ToList(); var models = new List<ResourceModel>(); foreach (var request in requests) { @@ -52,27 +62,25 @@ foreach (var controller in resourceAttribute.Controllers) { - var resourceController = controller.GetType().GetMember(controller.ToString())[0].GetCustomAttribute<ResourceControllerAttribute>(); - var resourceService = resourceController.Service.GetType().GetMember(resourceController.Service.ToString())[0].GetCustomAttribute<ResourceServiceAttribute>(); + var requestXmlDoc = await request.GetXmlDocMemberAsync(xmlDoc); + var resourceController = controller.GetCustomAttribute<EnumResourceController, ResourceControllerAttribute>(); + var resourceService = resourceController.Service.GetCustomAttribute<EnumResourceService, ResourceServiceAttribute>(); var model = new ResourceModel(); model.TraceId = traceId; model.ApplicationName = resourceService.ApplicationName; - model.RouteArea = resourceService.RouteArea; - var name = request.Name; - name = Regex.Replace(name, @"(Command|Query)$", "", RegexOptions.None); - model.ActionName = name; - model.Route = $"/api/{resourceService.RouteArea ?? "main"}/{controller}/{name}"; - var requestXmlDoc = await request.GetXmlDocMemberAsync(xmlDoc); - model.Code = requestXmlDoc.Name; model.Controller = controller; model.ControllerSummary = resourceControllers.GetDescription(controller); - if (controller == EnumResourceController.Role) - { - Console.WriteLine(); - } + model.ActionName = Regex.Replace(request.Name, @"(Command|Query)$", "", RegexOptions.None); + model.ActionSummary = requestXmlDoc?.Summary; + model.Service = resourceController.Service; + model.ServiceName = resourceService.ServiceName; + model.RouteArea = resourceService.RouteArea; + model.Route = $"/api/{resourceService.RouteArea ?? "main"}/{controller}/{model.ActionName}"; model.Method = - request.BaseType?.IsGenericType == true && request.BaseType.GetGenericTypeDefinition() == typeof(PagedListQuery<,>) + resourceAttribute.Method.HasValue + ? resourceAttribute.Method.Value + : request.BaseType?.IsGenericType == true && request.BaseType.GetGenericTypeDefinition() == typeof(PagedListQuery<,>) ? EnumResourceMethod.Post : new List<string> { "Post", "Add", "Create", "Insert", "Submit" }.Any(it => request.Name.StartsWith(it, StringComparison.OrdinalIgnoreCase)) ? EnumResourceMethod.Post @@ -83,7 +91,9 @@ : new List<string> { "Delete", "Remove ", "Clear" }.Any(it => request.Name.StartsWith(it, StringComparison.OrdinalIgnoreCase)) ? EnumResourceMethod.Delete : EnumResourceMethod.Post; - model.Name = requestXmlDoc?.Summary; + model.FileUpload = resourceAttribute.FileUpload; + model.Code = requestXmlDoc?.Name; + model.Name = $"{model.ControllerSummary}-{model.ActionSummary}"; model.AllowAnonymous = resourceAttribute.AllowAnonymous; model.RequestTypeName = request.Name; model.RequestTypeFullName = request.FullName; @@ -94,38 +104,83 @@ model.ResponseTypeName = responseType.GetCSharpFriendlyName(); model.ResponseTypeFullName = responseType.FullName; } - - var resource = resources.FirstOrDefault(it => it.Route == model.Route && it.Method == model.Method); - if (resource == null) - { - resource = new Resource(); - model.Adapt(resource); - await rep.InsertAsync(resource); - resources.Add(resource); - } - else - { - model.Adapt(resource); - await rep.UpdateAsync(resource); - } - models.Add(model); + + await App.GetRequiredService<IDistributedCache>().SetStringAsync($"ResourceModel|{model.RequestTypeFullName}", model.ToJson()); } } - var expiredResources = resources.Where(it => it.TraceId != traceId).ToList(); - foreach (var expiredResource in expiredResources) + var resources = await SaveResourcesAsync(models, rep); + + DynamicControllersHotPlug(resources, provider); + + await rep.SaveNowAsync(); + } + + /// <summary> + /// 淇濆瓨璧勬簮 + /// </summary> + /// <param name="models"></param> + /// <param name="traceId"></param> + /// <param name="rep"></param> + /// <returns></returns> + private static async Task<List<Resource>> SaveResourcesAsync(List<ResourceModel> models, IRepository<Resource> rep = null) + { + rep = rep ?? Db.GetRepository<Resource>(); + var resources = await rep.AsQueryable() + .Where(it => !it.IsExpired) + .ToListAsync(); + foreach (var model in models) { - expiredResource.IsExpired = true; - await rep.UpdateAsync(expiredResource); + var resource = resources.FirstOrDefault(it => it.Route == model.Route && it.Method == model.Method); + 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 + { + 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 controllers = models + var expiredResources = resources.Where(it => !models.Any(m => m.Route == it.Route && m.Method == it.Method)).ToList(); + foreach (var expiredResource in expiredResources) + { + resources.Remove(expiredResource); + await rep.DeleteAsync(expiredResource); + } + + return resources.Where(it => !it.IsExpired).ToList(); + } + + /// <summary> + /// 鍔ㄦ�佹帶鍒跺櫒鐑彃 + /// </summary> + /// <param name="resources"></param> + /// <param name="provider"></param> + public static void DynamicControllersHotPlug(List<Resource> resources, IDynamicApiRuntimeChangeProvider provider = null) + { + provider = provider ?? App.GetRequiredService<IDynamicApiRuntimeChangeProvider>(); + var controllers = resources .GroupBy(it => new { + it.ApplicationName, it.Controller, it.ControllerSummary, - it.ApplicationName, it.RouteArea }) .Select(it => new @@ -146,8 +201,10 @@ using System; using System.Threading.Tasks; using System.Collections.Generic; +using System.ComponentModel; -namespace {controller.Key.ApplicationName} + +namespace {controller.Key.ApplicationName}.{controller.Key.Controller} {{ /// <summary> /// {controller.Key.ControllerSummary} @@ -156,12 +213,14 @@ public class {controller.Key.Controller}AppService(IMediator mediator) : IDynamicApiController {{ private readonly IMediator mediator = mediator;"; + foreach (var action in controller.Actions) { - code += $@" + var result = action.ResponseTypeName.IsNull() ? "Task" : $"Task<{action.ResponseTypeName}>"; + code += @$" /// <summary> - /// {action.Name} + /// {action.ActionSummary} /// </summary> /// <param name=""request""></param> /// <returns></returns>"; @@ -171,22 +230,56 @@ [AllowAnonymous]"; } code += $@" - [Http{action.Method}] - public Task<{action.ResponseTypeName}> {action.ActionName}({action.RequestTypeName} request) + [Http{action.Method}]"; + if (action.FileUpload) + { + code += @" + [Consumes(""multipart/form-data"")]"; + } + code += @$" + public {result} {action.ActionName}("; + if (action.FileUpload) + { + code += "[FromForm] "; + } + code += $@"{action.RequestTypeName} request) {{ return mediator.Send(request); - }} -"; + }}"; } - code += $@" - }} -}} + + code += @" + } +} "; - var dynamicAssembly = App.CompileCSharpClassCode(code); - provider.AddAssembliesWithNotifyChanges(dynamicAssembly); + try + { + var dynamicAssembly = App.CompileCSharpClassCode(code); + provider.AddAssembliesWithNotifyChanges(dynamicAssembly); + var dynamicAssemblyName = dynamicAssembly.GetName().Name; + foreach (var action in controller.Actions) + { + action.DynamicAssemblyName = dynamicAssemblyName; + } + } + catch (Exception ex) + { + Console.WriteLine(code); + throw; + } } - await rep.SaveNowAsync(); + } + + /// <summary> + /// 鍔ㄦ�佹帶鍒跺櫒鐑嫈 + /// </summary> + /// <param name="resource"></param> + /// <param name="provider"></param> + public static void DynamicControllerHotPluck(Resource resource, IDynamicApiRuntimeChangeProvider provider = null) + { + provider = provider ?? App.GetRequiredService<IDynamicApiRuntimeChangeProvider>(); + provider.RemoveAssembliesWithNotifyChanges(resource.DynamicAssemblyName); } /// <summary> @@ -194,7 +287,7 @@ /// </summary> /// <param name="type"></param> /// <returns></returns> - public static string GetCSharpFriendlyName(this Type type) + private static string GetCSharpFriendlyName(this Type type) { // 澶勭悊鍙┖绫诲瀷 if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) -- Gitblit v1.9.1