feat: startup适配移动平台

This commit is contained in:
Diego
2024-07-18 20:50:06 +08:00
parent 1af6f4e151
commit 4216002ce5
22 changed files with 161 additions and 77 deletions

View File

@@ -761,7 +761,7 @@ writeEndObject: writer.WriteEndObject();
writer.WriteString(nameof(basicFrameworkVersion), basicFrameworkVersion);
// 获取启动信息
var entryAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
var entryAssemblyName = Assembly.GetEntryAssembly()?.GetName()?.Name;
writer.WriteString(nameof(entryAssemblyName), entryAssemblyName);
// 获取进程信息

View File

@@ -18,6 +18,6 @@ public class SysDictSeedData : ISqlSugarEntitySeedData<SysDict>
/// <inheritdoc/>
public IEnumerable<SysDict> SeedData()
{
return SeedDataUtil.GetSeedData<SysDict>("seed_sys_dict.json");
return SeedDataUtil.GetSeedData<SysDict>(PathExtensions.CombinePathWithOs("SeedData", "Json", "seed_sys_dict.json"));
}
}

View File

@@ -18,6 +18,6 @@ public class SysRelationSeedData : ISqlSugarEntitySeedData<SysRelation>
/// <inheritdoc/>
public IEnumerable<SysRelation> SeedData()
{
return SeedDataUtil.GetSeedData<SysRelation>("seed_sys_relation.json");
return SeedDataUtil.GetSeedData<SysRelation>(PathExtensions.CombinePathWithOs("SeedData", "Json", "seed_sys_relation.json"));
}
}

View File

@@ -18,6 +18,6 @@ public class SysResourceSeedData : ISqlSugarEntitySeedData<SysResource>
/// <inheritdoc/>
public IEnumerable<SysResource> SeedData()
{
return SeedDataUtil.GetSeedData<SysResource>("seed_sys_resource.json").Concat(SeedDataUtil.GetSeedData<SysResource>("seed_sys_resourcebutton.json"));
return SeedDataUtil.GetSeedData<SysResource>(PathExtensions.CombinePathWithOs("SeedData", "Json", "seed_sys_resource.json")).Concat(SeedDataUtil.GetSeedData<SysResource>(PathExtensions.CombinePathWithOs("SeedData", "Json", "seed_sys_resourcebutton.json")));
}
}

View File

@@ -18,6 +18,6 @@ public class SysRoleSeedData : ISqlSugarEntitySeedData<SysRole>
/// <inheritdoc/>
public IEnumerable<SysRole> SeedData()
{
return SeedDataUtil.GetSeedData<SysRole>("seed_sys_role.json");
return SeedDataUtil.GetSeedData<SysRole>(PathExtensions.CombinePathWithOs("SeedData", "Json", "seed_sys_role.json"));
}
}

View File

@@ -30,6 +30,6 @@ public class SysUserSeedData : ISqlSugarEntitySeedData<SysUser>
IsDelete=false,
SortCode=0
}
}.Concat(SeedDataUtil.GetSeedData<SysUser>("seed_sys_user.json"));
}.Concat(SeedDataUtil.GetSeedData<SysUser>(PathExtensions.CombinePathWithOs("SeedData", "Json", "seed_sys_user.json")));
}
}

View File

@@ -23,7 +23,9 @@
<GlobalSearch Menus=@(MenuService.SameLevelMenuItems) />
@* 语言选择 *@
<CultureChooser />
<div class="d-none d-xl-flex ">
<CultureChooser />
</div>
@* 全屏按钮 *@

View File

@@ -18,6 +18,6 @@ public class SysRelationSeedData : ISqlSugarEntitySeedData<SysRelation>
/// <inheritdoc/>
public IEnumerable<SysRelation> SeedData()
{
return SeedDataUtil.GetSeedData<SysRelation>("seed_gateway_relation.json");
return SeedDataUtil.GetSeedData<SysRelation>(PathExtensions.CombinePathWithOs("SeedData", "Json", "seed_gateway_relation.json"));
}
}

View File

@@ -18,6 +18,6 @@ public class SysResourceSeedData : ISqlSugarEntitySeedData<SysResource>
/// <inheritdoc/>
public IEnumerable<SysResource> SeedData()
{
return SeedDataUtil.GetSeedData<SysResource>("seed_gateway_resource.json").Concat(SeedDataUtil.GetSeedData<SysResource>("seed_gateway_resourcebutton.json"));
return SeedDataUtil.GetSeedData<SysResource>(PathExtensions.CombinePathWithOs("SeedData", "Json", "seed_gateway_resource.json")).Concat(SeedDataUtil.GetSeedData<SysResource>(PathExtensions.CombinePathWithOs("SeedData", "Json", "seed_gateway_resourcebutton.json")));
}
}

View File

@@ -23,7 +23,9 @@
<GlobalSearch Menus=@(MenuService.SameLevelMenuItems) />
@* 语言选择 *@
<CultureChooser />
<div class="d-none d-xl-flex ">
<CultureChooser />
</div>

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>6.0.4.15</Version>
<Version>6.0.4.27</Version>
</PropertyGroup>
<ItemGroup>

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;</TargetFrameworks>
<Version>8.8.0</Version>
<Version>8.8.7</Version>
</PropertyGroup>
<ItemGroup>

View File

@@ -1,19 +1,20 @@
@namespace ThingsGateway.Debug
@using BootstrapBlazor.Components
@using Microsoft.AspNetCore.Components.Routing
@using System.Reflection
<Router AppAssembly="@typeof(BlazorApp).Assembly" AdditionalAssemblies="_assemblyList">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
<BootstrapBlazorRoot>
<Router AppAssembly="@typeof(BlazorApp).Assembly" AdditionalAssemblies="_assemblyList">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</BootstrapBlazorRoot>
@code {
private List<Assembly> _assemblyList = new();

View File

@@ -18,7 +18,10 @@
@* 搜索框 *@
<GlobalSearch Menus=@(MenuService.SameLevelMenuItems) />
@* 语言选择 *@
<CultureChooser />
<div class="d-none d-xl-flex ">
<CultureChooser />
</div>

View File

@@ -15,6 +15,7 @@ using CSScriptLib;
using NewLife.Caching;
using System.Reflection;
using System.Text;
namespace ThingsGateway.Gateway.Application;
@@ -95,18 +96,32 @@ public static class CSharpScriptEngineExtension
source = $"return {source}";//只判断简单脚本中可省略return字符串
}
var src = source.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
StringBuilder _using = new StringBuilder();
StringBuilder _body = new StringBuilder();
src.ToList().ForEach(l =>
{
if (l.StartsWith("using "))
{
_using.AppendLine(l);
}
else
{
_body.AppendLine(l);
}
});
// 动态加载并执行代码
runScript = CSScript.Evaluator.With(eval => eval.IsAssemblyUnloadingEnabled = true).LoadCode<T>(
$@"
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ThingsGateway.Core.Json.Extension;
using ThingsGateway.Gateway.Application;
using ThingsGateway.Gateway.Application.Extensions;
{source};
{_using}
{_body}
");
GC.Collect();
Instance.Set(field, runScript);

View File

@@ -14,6 +14,8 @@ using CSScriptLib;
using NewLife.Caching;
using System.Text;
namespace ThingsGateway.Gateway.Application.Extensions;
/// <summary>
@@ -24,6 +26,7 @@ public interface ReadWriteExpressions
object GetNewValue(object a);
}
/// <summary>
/// 表达式扩展
/// </summary>
@@ -81,22 +84,35 @@ public static class ExpressionEvaluatorExtension
{
source = $"return {source}";//只判断简单脚本中可省略return字符串
}
var src = source.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
StringBuilder _using = new StringBuilder();
StringBuilder _body = new StringBuilder();
src.ToList().ForEach(l =>
{
if (l.StartsWith("using "))
{
_using.AppendLine(l);
}
else
{
_body.AppendLine(l);
}
});
// 动态加载并执行代码
runScript = CSScript.Evaluator.With(eval => eval.IsAssemblyUnloadingEnabled = true).LoadCode<ReadWriteExpressions>(
$@"
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ThingsGateway.Gateway.Application;
using ThingsGateway.Foundation;
using ThingsGateway.Gateway.Application.Extensions;
{_using}
public class Script:ReadWriteExpressions
{{
public object GetNewValue(object raw)
{{
{source};
{_body};
}}
}}
");

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;</TargetFrameworks>
<Version>8.8.0</Version>
<Version>8.8.7</Version>
</PropertyGroup>
<ItemGroup>

View File

@@ -11,7 +11,7 @@
<div class="flex-fill">
</div>
<Button Color="Color.None" style="color: var(--bs-card-title-color);" Icon=@(IsPause?"fa fa-play":"fa fa-pause") OnClick="Pause" />
<Button IsAsync Color="Color.None" style="color: var(--bs-card-title-color);" Icon=@("fa fa-sign-out") OnClick="HandleOnExportClick" />
<Button IsAsync Color="Color.None" style="color: var(--bs-card-title-color);" Icon=@("fa fa-sign-out") OnClick="HandleOnExportClick" />
<Button IsAsync Color="Color.None" style="color: var(--bs-card-title-color);" Icon=@("far fa-trash-alt") OnClick="Delete" />
</HeaderTemplate>
@@ -19,14 +19,15 @@
<div style=@($"height:{HeightText};overflow-y:scroll")>
<Virtualize Items="CurrentMessages??new List<LogMessage>()" Context="itemMessage" ItemSize="60" OverscanCount=2>
<ItemContent>
<div title=@itemMessage.Message.Substring(0, Math.Min(itemMessage.Message.Length, 500))
class=@(itemMessage.Level<(byte)Microsoft.Extensions.Logging.LogLevel.Information?"":
itemMessage.Level>=(byte)Microsoft.Extensions.Logging.LogLevel.Warning? " red--text ":"green--text ")
style="white-space: nowrap !important;overflow: hidden !important; text-overflow: ellipsis !important;">
<Tooltip Placement="Placement.Bottom" Title=@itemMessage.Message.Substring(0, Math.Min(itemMessage.Message.Length, 500))>
<div class=@(itemMessage.Level<(byte)Microsoft.Extensions.Logging.LogLevel.Information?"":
itemMessage.Level>=(byte)Microsoft.Extensions.Logging.LogLevel.Warning? " red--text ":"green--text ")
style="white-space: nowrap !important;overflow: hidden !important; text-overflow: ellipsis !important;">
@itemMessage.Message.Substring(0, Math.Min(itemMessage.Message.Length, 150))
@itemMessage.Message.Substring(0, Math.Min(itemMessage.Message.Length, 150))
</div>
</div>
</Tooltip>
</ItemContent>
</Virtualize>
</div>

View File

@@ -1,6 +1,6 @@
@inherits BootstrapComponentBase
@namespace ThingsGateway.Razor
<div class="d-none d-xl-flex flex-xl-fill flex-xl-grow-0 justify-content-xl-end px-2">
<div class="flex-xl-fill flex-xl-grow-0 justify-content-xl-end px-2">
<Select Value="@SelectedCulture" OnSelectedItemChanged="@SetCulture" IsPopover>
<Options>
@foreach (var kv in BootstrapOptions.CurrentValue.GetSupportedCultures())

View File

@@ -27,7 +27,7 @@ public class SeedDataUtil
{
var seedData = new List<T>();//种子数据结果
var basePath = AppContext.BaseDirectory;//获取项目目录
var json = basePath.CombinePathWithOs("SeedData", "Json", jsonName);//获取文件路径
var json = basePath.CombinePathWithOs(jsonName);//获取文件路径
var dataString = FileUtil.ReadFile(json);//读取文件
if (!string.IsNullOrEmpty(dataString))//如果有内容
{

View File

@@ -46,9 +46,9 @@ public static class StartupWithoutWebExtensions
/// <summary>
/// 非web应用 反射获取所有AppStartup的继承类
/// </summary>
public static void ConfigureServicesWithoutWeb(this IServiceCollection services)
public static void ConfigureServicesWithoutWeb(this IServiceCollection services, Stream? jsonConfigStream = default)
{
AddStartups(services);
AddStartups(services, jsonConfigStream);
}
/// <summary>
@@ -124,14 +124,23 @@ public static class StartupWithoutWebExtensions
/// <summary>
/// 非web应用 添加 Startup 自动扫描
/// </summary>
private static void AddStartups(IServiceCollection services)
private static void AddStartups(IServiceCollection services, Stream? jsonConfigStream)
{
// 创建配置生成器并读取appsettings.json
var configBuilder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false);
var configBuilder = new ConfigurationBuilder();
if (jsonConfigStream == null)
{
// 创建配置生成器并读取appsettings.json
configBuilder.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false);
}
AddJsonFiles(configBuilder, default);
if (jsonConfigStream != null)
{
configBuilder.AddJsonStream(jsonConfigStream);
}
// 构建配置
var configuration = configBuilder.Build();
NetCoreApp.Configuration = configuration;

View File

@@ -15,7 +15,6 @@ using Microsoft.Extensions.Localization;
using System.Diagnostics;
using System.Reflection;
using System.Security.Claims;
using ThingsGateway.Core;
@@ -118,8 +117,6 @@ public class NetCoreApp
return Environment.CurrentManagedThreadId;
}
/// <summary>
/// 获取应用有效程序集
/// </summary>
@@ -136,7 +133,7 @@ public class NetCoreApp
var entryAssembly = Assembly.GetEntryAssembly();
// 非独立发布/非单文件发布
if (!string.IsNullOrWhiteSpace(entryAssembly.Location))
if (!string.IsNullOrWhiteSpace(entryAssembly?.Location))
{
var dependencyContext = DependencyContext.Default;
@@ -151,34 +148,72 @@ public class NetCoreApp
}
else
{
IEnumerable<Assembly> fixedSingleFileAssemblies = new[] { entryAssembly };
// 扫描实现 ISingleFilePublish 接口的类型
var singleFilePublishType = entryAssembly.GetTypes()
.FirstOrDefault(u => u.IsClass && !u.IsInterface && !u.IsAbstract && typeof(ISingleFilePublish).IsAssignableFrom(u));
if (singleFilePublishType != null)
if (entryAssembly != null)
{
var singleFilePublish = Activator.CreateInstance(singleFilePublishType) as ISingleFilePublish;
// 加载用户自定义配置单文件所需程序集
var nativeAssemblies = singleFilePublish.IncludeAssemblies();
var loadAssemblies = singleFilePublish.IncludeAssemblyNames()
.Select(u => Reflect.GetAssembly(u));
IEnumerable<Assembly> fixedSingleFileAssemblies = new[] { entryAssembly };
fixedSingleFileAssemblies = fixedSingleFileAssemblies.Concat(nativeAssemblies)
.Concat(loadAssemblies);
// 扫描实现 ISingleFilePublish 接口的类型
var singleFilePublishType = entryAssembly.GetTypes()
.FirstOrDefault(u => u.IsClass && !u.IsInterface && !u.IsAbstract && typeof(ISingleFilePublish).IsAssignableFrom(u));
if (singleFilePublishType != null)
{
var singleFilePublish = Activator.CreateInstance(singleFilePublishType) as ISingleFilePublish;
// 加载用户自定义配置单文件所需程序集
var nativeAssemblies = singleFilePublish.IncludeAssemblies();
var loadAssemblies = singleFilePublish.IncludeAssemblyNames()
.Select(u => Reflect.GetAssembly(u));
fixedSingleFileAssemblies = fixedSingleFileAssemblies.Concat(nativeAssemblies)
.Concat(loadAssemblies);
}
// 通过 AppDomain.CurrentDomain 扫描,默认为延迟加载,正常只能扫描到入口程序集(启动层)
scanAssemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(ass =>
// 排除 SystemMicrosoftnetstandard 开头的程序集
!ass.FullName.StartsWith(nameof(System))
&& !ass.FullName.StartsWith(nameof(Microsoft))
&& !ass.FullName.StartsWith("netstandard"))
.Concat(fixedSingleFileAssemblies)
.Distinct();
return scanAssemblies;
}
else
{
//maui
// 通过 AppDomain.CurrentDomain 扫描,默认为延迟加载,正常只能扫描到 Furion 和 入口程序集(启动层)
scanAssemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(ass =>
// 排除 SystemMicrosoftnetstandard 开头的程序集
!ass.FullName.StartsWith(nameof(System))
&& !ass.FullName.StartsWith(nameof(Microsoft))
&& !ass.FullName.StartsWith("netstandard"))
.Concat(fixedSingleFileAssemblies)
.Distinct();
return scanAssemblies;
scanAssemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(ass =>
// 排除 SystemMicrosoftnetstandard 开头的程序集
!ass.FullName.StartsWith(nameof(System))
&& !ass.FullName.StartsWith(nameof(Microsoft))
&& !ass.FullName.StartsWith("netstandard"));
// 扫描实现 ISingleFilePublish 接口的类型
IEnumerable<Assembly> fixedSingleFileAssemblies = new List<Assembly>();
var singleFilePublishType = scanAssemblies.SelectMany(a=>a.GetTypes())
.FirstOrDefault(u => u.IsClass && !u.IsInterface && !u.IsAbstract && typeof(ISingleFilePublish).IsAssignableFrom(u));
if (singleFilePublishType != null)
{
var singleFilePublish = Activator.CreateInstance(singleFilePublishType) as ISingleFilePublish;
// 加载用户自定义配置单文件所需程序集
var nativeAssemblies = singleFilePublish.IncludeAssemblies();
var loadAssemblies = singleFilePublish.IncludeAssemblyNames()
.Select(u => Reflect.GetAssembly(u));
fixedSingleFileAssemblies = fixedSingleFileAssemblies.Concat(nativeAssemblies)
.Concat(loadAssemblies);
}
// 通过 AppDomain.CurrentDomain 扫描,默认为延迟加载,正常只能扫描到入口程序集(启动层)
scanAssemblies= scanAssemblies.Concat(fixedSingleFileAssemblies)
.Distinct().ToList();
return scanAssemblies;
}
}
}
}