魔方插件系统完成

This commit is contained in:
大石头 2022-04-23 09:40:50 +08:00
parent a2b48ffc70
commit fd53d52db9
15 changed files with 217 additions and 182 deletions

View File

@ -11,7 +11,7 @@
<Deterministic>false</Deterministic>
<OutputPath>..\Bin</OutputPath>
<InvariantGlobalization>true</InvariantGlobalization>
<UserSecretsId>1396351c-62fe-4836-9e51-9d77859955ad</UserSecretsId>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='net5.0'">
<DefineConstants>$(DefineConstants);__CORE__;NET50</DefineConstants>

View File

@ -1,14 +1,13 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using NewLife.Cube;
using NewLife.Cube;
using NewLife.Cube.AdminLTE;
using NewLife.Cube.ElementUI;
using NewLife.Cube.Metronic;
using NewLife.Cube.Metronic8;
using NewLife.Cube.Tabler;
using NewLife.Cube.WebMiddleware;
using NewLife.Log;
using NewLife.Threading;
using Stardust;
using Stardust.Monitors;
using Setting = NewLife.Cube.Setting;
namespace CubeDemoNC
@ -21,15 +20,10 @@ namespace CubeDemoNC
public void ConfigureServices(IServiceCollection services)
{
// APM跟踪器
var tracer = new StarTracer("http://star.newlifex.com:6600") { Log = XTrace.Log };
DefaultTracer.Instance = tracer;
//ApiHelper.Tracer = tracer;
//DAL.GlobalTracer = tracer;
//OAuthClient.Tracer = tracer;
TracerMiddleware.Tracer = tracer;
var star = new StarFactory(null, null, null);
TracerMiddleware.Tracer = star.Tracer;
services.AddSingleton<ITracer>(tracer);
services.AddSingleton<ITracer>(star.Tracer);
services.AddControllersWithViews();
services.AddCube();
@ -96,11 +90,11 @@ namespace CubeDemoNC
//app.UseMiddleware<TracerMiddleware>();
app.UseCube(env);
app.UseAdminLTE(env);
app.UseTabler(env);
app.UseMetronic(env);
app.UseElementUI(env);
app.UseMetronic8(env);
//app.UseAdminLTE(env);
//app.UseTabler(env);
//app.UseMetronic(env);
//app.UseElementUI(env);
//app.UseMetronic8(env);
#if NET50
app.UseBlazor(env);
#endif

View File

@ -1,42 +1,47 @@
using System.IO;
using System.ComponentModel;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using NewLife.Cube.Extensions;
using NewLife.Cube.Modules;
using NewLife.Cube.Services;
using NewLife.Model;
namespace NewLife.Cube
namespace NewLife.Cube.AdminLTE;
/// <summary>AdminLTE服务</summary>
public static class AdminLTEService
{
/// <summary>AdminLTE服务</summary>
public static class AdminLTEService
/// <summary>使用魔方UI</summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseAdminLTE(this IApplicationBuilder app, IWebHostEnvironment env)
{
/// <summary>使用魔方UI</summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseAdminLTE(this IApplicationBuilder app, IWebHostEnvironment env)
// 独立静态文件设置,魔方自己的静态资源内嵌在程序集里面
var options = new StaticFileOptions();
{
// 独立静态文件设置,魔方自己的静态资源内嵌在程序集里面
var options = new StaticFileOptions();
{
var embeddedProvider = new CubeEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "NewLife.Cube.AdminLTE.wwwroot");
if (!env.WebRootPath.IsNullOrEmpty() && Directory.Exists(env.WebRootPath))
options.FileProvider = new CompositeFileProvider(new PhysicalFileProvider(env.WebRootPath), embeddedProvider);
else
options.FileProvider = embeddedProvider;
}
app.UseStaticFiles(options);
var ui = ModelExtension.GetService<UIService>(app.ApplicationServices);
if (ui != null)
{
ui.AddTheme("AdminLTE");
ui.AddSkin("AdminLTE");
}
return app;
var embeddedProvider = new CubeEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "NewLife.Cube.AdminLTE.wwwroot");
if (!env.WebRootPath.IsNullOrEmpty() && Directory.Exists(env.WebRootPath))
options.FileProvider = new CompositeFileProvider(new PhysicalFileProvider(env.WebRootPath), embeddedProvider);
else
options.FileProvider = embeddedProvider;
}
app.UseStaticFiles(options);
var ui = ModelExtension.GetService<UIService>(app.ApplicationServices);
if (ui != null)
{
ui.AddTheme("AdminLTE");
ui.AddSkin("AdminLTE");
}
return app;
}
}
[DisplayName("AdminLTE皮肤")]
internal class AdminLTEModule : IModule
{
public void Add(IServiceCollection services) { }
public void Use(IApplicationBuilder app, IWebHostEnvironment env) => app.UseAdminLTE(env);
}

View File

@ -16,6 +16,7 @@
<OutputPath>..\..\Bin</OutputPath>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>

View File

@ -1,42 +1,47 @@
using System.IO;
using System.ComponentModel;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using NewLife.Cube.Extensions;
using NewLife.Cube.Modules;
using NewLife.Cube.Services;
using NewLife.Model;
namespace NewLife.Cube
namespace NewLife.Cube.ElementUI;
/// <summary>ElementUI服务</summary>
public static class ElementUIService
{
/// <summary>ElementUI服务</summary>
public static class ElementUIService
/// <summary>使用魔方UI</summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseElementUI(this IApplicationBuilder app, IWebHostEnvironment env)
{
/// <summary>使用魔方UI</summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseElementUI(this IApplicationBuilder app, IWebHostEnvironment env)
// 独立静态文件设置,魔方自己的静态资源内嵌在程序集里面
var options = new StaticFileOptions();
{
// 独立静态文件设置,魔方自己的静态资源内嵌在程序集里面
var options = new StaticFileOptions();
{
var embeddedProvider = new CubeEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "NewLife.Cube.ElementUI.wwwroot");
if (!env.WebRootPath.IsNullOrEmpty() && Directory.Exists(env.WebRootPath))
options.FileProvider = new CompositeFileProvider(new PhysicalFileProvider(env.WebRootPath), embeddedProvider);
else
options.FileProvider = embeddedProvider;
}
app.UseStaticFiles(options);
var ui = ModelExtension.GetService<UIService>(app.ApplicationServices);
if (ui != null)
{
ui.AddTheme("ElementUI");
ui.AddSkin("ElementUI");
}
return app;
var embeddedProvider = new CubeEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "NewLife.Cube.ElementUI.wwwroot");
if (!env.WebRootPath.IsNullOrEmpty() && Directory.Exists(env.WebRootPath))
options.FileProvider = new CompositeFileProvider(new PhysicalFileProvider(env.WebRootPath), embeddedProvider);
else
options.FileProvider = embeddedProvider;
}
app.UseStaticFiles(options);
var ui = ModelExtension.GetService<UIService>(app.ApplicationServices);
if (ui != null)
{
ui.AddTheme("ElementUI");
ui.AddSkin("ElementUI");
}
return app;
}
}
[DisplayName("Element皮肤")]
internal class ElementUIModule : IModule
{
public void Add(IServiceCollection services) { }
public void Use(IApplicationBuilder app, IWebHostEnvironment env) => app.UseElementUI(env);
}

View File

@ -16,6 +16,7 @@
<OutputPath>..\..\Bin</OutputPath>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>

View File

@ -1,42 +1,47 @@
using System.IO;
using System.ComponentModel;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using NewLife.Cube.Extensions;
using NewLife.Cube.Modules;
using NewLife.Cube.Services;
using NewLife.Model;
namespace NewLife.Cube
namespace NewLife.Cube.Metronic;
/// <summary>Metronic服务</summary>
public static class MetronicService
{
/// <summary>Metronic服务</summary>
public static class MetronicService
/// <summary>使用魔方UI</summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseMetronic(this IApplicationBuilder app, IWebHostEnvironment env)
{
/// <summary>使用魔方UI</summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseMetronic(this IApplicationBuilder app, IWebHostEnvironment env)
// 独立静态文件设置,魔方自己的静态资源内嵌在程序集里面
var options = new StaticFileOptions();
{
// 独立静态文件设置,魔方自己的静态资源内嵌在程序集里面
var options = new StaticFileOptions();
{
var embeddedProvider = new CubeEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "NewLife.Cube.Metronic.wwwroot");
if (!env.WebRootPath.IsNullOrEmpty() && Directory.Exists(env.WebRootPath))
options.FileProvider = new CompositeFileProvider(new PhysicalFileProvider(env.WebRootPath), embeddedProvider);
else
options.FileProvider = embeddedProvider;
}
app.UseStaticFiles(options);
var ui = ModelExtension.GetService<UIService>(app.ApplicationServices);
if (ui != null)
{
ui.AddTheme("Metronic3");
ui.AddSkin("Metronic3");
}
return app;
var embeddedProvider = new CubeEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "NewLife.Cube.Metronic.wwwroot");
if (!env.WebRootPath.IsNullOrEmpty() && Directory.Exists(env.WebRootPath))
options.FileProvider = new CompositeFileProvider(new PhysicalFileProvider(env.WebRootPath), embeddedProvider);
else
options.FileProvider = embeddedProvider;
}
app.UseStaticFiles(options);
var ui = ModelExtension.GetService<UIService>(app.ApplicationServices);
if (ui != null)
{
ui.AddTheme("Metronic3");
ui.AddSkin("Metronic3");
}
return app;
}
}
[DisplayName("Metronic皮肤")]
internal class MetronicModule : IModule
{
public void Add(IServiceCollection services) { }
public void Use(IApplicationBuilder app, IWebHostEnvironment env) => app.UseMetronic(env);
}

View File

@ -16,6 +16,7 @@
<OutputPath>..\..\Bin</OutputPath>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>

View File

@ -1,42 +1,47 @@
using System.IO;
using System.ComponentModel;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using NewLife.Cube.Extensions;
using NewLife.Cube.Modules;
using NewLife.Cube.Services;
using NewLife.Model;
namespace NewLife.Cube
namespace NewLife.Cube.Metronic8;
/// <summary>Metronic服务</summary>
public static class Metronic8Service
{
/// <summary>Metronic服务</summary>
public static class Metronic8Service
/// <summary>使用魔方UI</summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseMetronic8(this IApplicationBuilder app, IWebHostEnvironment env)
{
/// <summary>使用魔方UI</summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseMetronic8(this IApplicationBuilder app, IWebHostEnvironment env)
// 独立静态文件设置,魔方自己的静态资源内嵌在程序集里面
var options = new StaticFileOptions();
{
// 独立静态文件设置,魔方自己的静态资源内嵌在程序集里面
var options = new StaticFileOptions();
{
var embeddedProvider = new CubeEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "NewLife.Cube.Metronic8.wwwroot");
if (!env.WebRootPath.IsNullOrEmpty() && Directory.Exists(env.WebRootPath))
options.FileProvider = new CompositeFileProvider(new PhysicalFileProvider(env.WebRootPath), embeddedProvider);
else
options.FileProvider = embeddedProvider;
}
app.UseStaticFiles(options);
var ui = ModelExtension.GetService<UIService>(app.ApplicationServices);
if (ui != null)
{
ui.AddTheme("Metronic8");
ui.AddSkin("Metronic8");
}
return app;
var embeddedProvider = new CubeEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "NewLife.Cube.Metronic8.wwwroot");
if (!env.WebRootPath.IsNullOrEmpty() && Directory.Exists(env.WebRootPath))
options.FileProvider = new CompositeFileProvider(new PhysicalFileProvider(env.WebRootPath), embeddedProvider);
else
options.FileProvider = embeddedProvider;
}
app.UseStaticFiles(options);
var ui = ModelExtension.GetService<UIService>(app.ApplicationServices);
if (ui != null)
{
ui.AddTheme("Metronic8");
ui.AddSkin("Metronic8");
}
return app;
}
}
[DisplayName("Metronic8皮肤")]
internal class Metronic8Module : IModule
{
public void Add(IServiceCollection services) { }
public void Use(IApplicationBuilder app, IWebHostEnvironment env) => app.UseMetronic8(env);
}

View File

@ -16,6 +16,7 @@
<OutputPath>..\..\Bin</OutputPath>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>

View File

@ -17,6 +17,7 @@
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<DefineConstants>$(DefineConstants);__CORE__</DefineConstants>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>

View File

@ -1,42 +1,47 @@
using System.IO;
using System.ComponentModel;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using NewLife.Cube.Extensions;
using NewLife.Cube.Modules;
using NewLife.Cube.Services;
using NewLife.Model;
namespace NewLife.Cube
namespace NewLife.Cube.Tabler;
/// <summary>Tabler服务</summary>
public static class TablerService
{
/// <summary>Tabler服务</summary>
public static class TablerService
/// <summary>使用魔方UI</summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseTabler(this IApplicationBuilder app, IWebHostEnvironment env)
{
/// <summary>使用魔方UI</summary>
/// <param name="app"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseTabler(this IApplicationBuilder app, IWebHostEnvironment env)
// 独立静态文件设置,魔方自己的静态资源内嵌在程序集里面
var options = new StaticFileOptions();
{
// 独立静态文件设置,魔方自己的静态资源内嵌在程序集里面
var options = new StaticFileOptions();
{
var embeddedProvider = new CubeEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "NewLife.Cube.Tabler.wwwroot");
if (!env.WebRootPath.IsNullOrEmpty() && Directory.Exists(env.WebRootPath))
options.FileProvider = new CompositeFileProvider(new PhysicalFileProvider(env.WebRootPath), embeddedProvider);
else
options.FileProvider = embeddedProvider;
}
app.UseStaticFiles(options);
var ui = ModelExtension.GetService<UIService>(app.ApplicationServices);
if (ui != null)
{
ui.AddTheme("Tabler");
ui.AddSkin("Tabler");
}
return app;
var embeddedProvider = new CubeEmbeddedFileProvider(Assembly.GetExecutingAssembly(), "NewLife.Cube.Tabler.wwwroot");
if (!env.WebRootPath.IsNullOrEmpty() && Directory.Exists(env.WebRootPath))
options.FileProvider = new CompositeFileProvider(new PhysicalFileProvider(env.WebRootPath), embeddedProvider);
else
options.FileProvider = embeddedProvider;
}
app.UseStaticFiles(options);
var ui = ModelExtension.GetService<UIService>(app.ApplicationServices);
if (ui != null)
{
ui.AddTheme("Tabler");
ui.AddSkin("Tabler");
}
return app;
}
}
[DisplayName("Tabler皮肤")]
internal class TablerModule : IModule
{
public void Add(IServiceCollection services) { }
public void Use(IApplicationBuilder app, IWebHostEnvironment env) => app.UseTabler(env);
}

View File

@ -8,7 +8,7 @@ namespace NewLife.Cube.Cube.Controllers
{
/// <summary>应用插件管理</summary>
[Area("Cube")]
[Menu(20)]
[Menu(36)]
public class AppModuleController : EntityController<AppModule>
{
static AppModuleController()
@ -63,15 +63,16 @@ namespace NewLife.Cube.Cube.Controllers
}
if (drv.Type.IsNullOrEmpty()) drv.Type = ".NET";
if (drv.ClassName.IsNullOrEmpty()) drv.ClassName = item.Value.FullName;
drv.ClassName = item.Value.FullName;
if (drv.FilePath.IsNullOrEmpty()) drv.FilePath = item.Value.Assembly?.Location;
if (!drv.FilePath.IsNullOrEmpty())
var file = item.Value.Assembly?.Location;
if (!file.IsNullOrEmpty())
{
var root = ".".GetFullPath();
if (drv.FilePath.StartsWithIgnoreCase(root))
drv.FilePath = drv.FilePath[root.Length..].TrimStart('/', '\\');
if (file.StartsWithIgnoreCase(root))
file = file[root.Length..].TrimStart('/', '\\');
}
if (!file.IsNullOrEmpty()) drv.FilePath = file;
drv.Save();

View File

@ -125,9 +125,14 @@ namespace NewLife.Cube
// 插件
var moduleManager = new ModuleManager();
services.AddSingleton(moduleManager);
foreach (var item in moduleManager.LoadAll())
var modules = moduleManager.LoadAll();
if (modules.Count > 0)
{
item.Value.Add(services);
XTrace.WriteLine("加载功能插件 [{0}] 个", modules.Count);
foreach (var item in modules)
{
item.Value.Add(services);
}
}
XTrace.WriteLine("{0} End 配置魔方 {0}", new String('=', 32));
@ -297,9 +302,14 @@ namespace NewLife.Cube
// 插件
var moduleManager = app.ApplicationServices.GetRequiredService<ModuleManager>();
foreach (var item in moduleManager.LoadAll())
var modules = moduleManager.LoadAll();
if (modules.Count > 0)
{
item.Value.Use(app, env);
XTrace.WriteLine("启用功能插件 [{0}] 个", modules.Count);
foreach (var item in modules)
{
item.Value.Use(app, env);
}
}
XTrace.WriteLine("{0} End 初始化魔方 {0}", new String('=', 32));

View File

@ -16,5 +16,5 @@ public interface IModule
/// </summary>
/// <param name="app"></param>
/// <param name="env"></param>
void Use(IApplicationBuilder app, IHostEnvironment env);
void Use(IApplicationBuilder app, IWebHostEnvironment env);
}