Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev/debug sdk #3

Merged
merged 6 commits into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,5 @@ __pycache__/
*.odx.cs
*.xsd.cs

# Custom rules
# Custom rules
*.zip
20 changes: 19 additions & 1 deletion Documents/如何开发模块.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ public IEnumerable<NavigationItem> GetNavigationItems()

2. **依赖管理**
- 在 `OnAllLoadedAsync` 中检查依赖模块
- 使用 `modules.GetModule()` 获取依赖模块

3. **服务注册**
- 使用依赖注入注册模块服务
Expand All @@ -103,6 +102,25 @@ public IEnumerable<NavigationItem> GetNavigationItems()
- 如需要,可以通过 `IJSRuntime` 实现JS互操作
- JS文件放在模块的 `wwwroot` 目录下

## 调试建议

### Attach调试

使用 Electron.NET CLI 命令启动你的 Electron.NET 应用程序。在 Visual Studio 中附加到正在运行的应用程序实例:转到调试菜单,点击"附加到进程..."。在右侧按项目名称排序并从列表中选择它。

### 手动加载模块

在开发过程中,建议在 `Program.cs` 中手动加载需要调试的模块:

```csharp
#region MODULE_DEBUG
// 在这里手动加载模块,方便调试
// moduleManager.LoadModule(typeof(IModule).Assembly);
#endregion
```

这样可以更方便地进行断点调试和问题排查。

## 示例代码结构

```
Expand Down
18 changes: 18 additions & 0 deletions Quantum.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quantum.Runtime", "Runtime\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quantum.BundleTool", "SDK\Quantum.BundleTool\Quantum.BundleTool.csproj", "{87CED238-4C37-4461-B52F-4C0052140BEC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemplateModule", "Samples\TemplateModule\TemplateModule.csproj", "{B70BB02D-4064-4588-AB0D-460267B89D50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemplateUiModule", "Samples\TemplateUiModule\TemplateUiModule.csproj", "{96B420E5-DB52-4BD2-943C-0F9A315F7DB8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{C8CEA4FD-E427-4419-9600-F99B32427B31}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -27,8 +33,20 @@ Global
{87CED238-4C37-4461-B52F-4C0052140BEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87CED238-4C37-4461-B52F-4C0052140BEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87CED238-4C37-4461-B52F-4C0052140BEC}.Release|Any CPU.Build.0 = Release|Any CPU
{B70BB02D-4064-4588-AB0D-460267B89D50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B70BB02D-4064-4588-AB0D-460267B89D50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B70BB02D-4064-4588-AB0D-460267B89D50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B70BB02D-4064-4588-AB0D-460267B89D50}.Release|Any CPU.Build.0 = Release|Any CPU
{96B420E5-DB52-4BD2-943C-0F9A315F7DB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96B420E5-DB52-4BD2-943C-0F9A315F7DB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96B420E5-DB52-4BD2-943C-0F9A315F7DB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96B420E5-DB52-4BD2-943C-0F9A315F7DB8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{B70BB02D-4064-4588-AB0D-460267B89D50} = {C8CEA4FD-E427-4419-9600-F99B32427B31}
{96B420E5-DB52-4BD2-943C-0F9A315F7DB8} = {C8CEA4FD-E427-4419-9600-F99B32427B31}
EndGlobalSection
EndGlobal
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

[![.NET 9](https://img.shields.io/badge/.NET-9-512BD4)](https://dotnet.microsoft.com/)
[![Blazor](https://img.shields.io/badge/Blazor-WebAssembly-blue)](https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor)
[![Build Test Status](https://github.com/XmmShp/Quantum/actions/workflows/build-test.yml/badge.svg)](https://github.com/XmmShp/Quantum/actions/workflows/build-test.yml)
[![Api Deployment Status](https://github.com/XmmShp/Quantum/actions/workflows/deploy-api-document.yml/badge.svg)](https://xmmshp.github.io/Quantum/)
[![Publish Status](https://github.com/XmmShp/Quantum/actions/workflows/publish.yml/badge.svg)](https://github.com/XmmShp/Quantum/releases/latest)

## 🌟 项目简介

一个基于.NET 9和Blazor构建的现代化桌面应用框架,采用模块化架构设计。通过内置的模块管理器,用户可以轻松安装/卸载功能模块,开发者可以快速创建可扩展的桌面应用程序。

**核心特性**
**核心特性:**
- 🧩 模块化架构 - 功能按模块动态加载
- 📦 内置模块管理器 - 支持模块的安装/卸载/更新
- 🚀 跨平台 - 支持Windows/macOS/Linux
Expand All @@ -27,9 +30,9 @@
# 克隆仓库
git clone https://github.com/XmmShp/Quantum.git

# 进入Quantum.Shell运行目录
# 进入Quantum.Runtime运行目录
cd Quantum
cd Quantum.Shell
cd Quantum.Runtime

# 启动项目

Expand Down
Binary file removed Runtime/Modules/ZdbkService/HtmlAgilityPack.dll
Binary file not shown.
75 changes: 0 additions & 75 deletions Runtime/Modules/ZdbkService/ZdbkService.deps.json

This file was deleted.

Binary file removed Runtime/Modules/ZdbkService/ZdbkService.dll
Binary file not shown.
27 changes: 16 additions & 11 deletions Runtime/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,30 @@
var moduleManager = new ModuleManager(logger) { Activator = sp, HostServices = builder.Services };
return moduleManager;
})
.AddSingleton(sp =>
.AddSingleton<IQuantum>(sp =>
{
var serviceManager = new ServiceManager(builder.Services);
return serviceManager;
})
.AddSingleton<Quantum.Runtime.Services.Quantum>();
var moduleManager = sp.GetRequiredService<ModuleManager>();
var codeManager = sp.GetRequiredService<InjectedCodeManager>();
var quantum = new Quantum.Runtime.Services.Quantum { HostServices = builder.Services, ModuleManager = moduleManager, InjectedCodeManager = codeManager };
return quantum;
});

#pragma warning disable ASP0000 // Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'
var preloadProvider = preloadServices.BuildServiceProvider();
#pragma warning restore ASP0000 // Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices'

var quantum = preloadProvider.GetRequiredService<Quantum.Runtime.Services.Quantum>();
var quantum = (Quantum.Runtime.Services.Quantum)preloadProvider.GetRequiredService<IQuantum>();
var injectedCodeManager = preloadProvider.GetRequiredService<InjectedCodeManager>();
var moduleManager = preloadProvider.GetRequiredService<ModuleManager>();

#region MODULE_DEBUG
#if DEBUG
// 在这里手动加载模块,方便调试
//moduleManager.LoadModule(typeof(TemplateModule.TemplateModule).Assembly);
//moduleManager.LoadModule(typeof(TemplateUiModule.TemplateUiModule).Assembly);
#endif
#endregion

await moduleManager.LoadModulesAsync();

// Add services to the container.
Expand All @@ -78,11 +88,6 @@
.AddSingleton<IQuantum>(quantum)
.AddSingleton(injectedCodeManager);

#region MODULE_DEBUG
// 在这里手动加载模块,方便调试
// loader.LoadModule(typeof(IModule).Assembly);
#endregion

var app = builder.Build();

// Configure the HTTP request pipeline.
Expand Down
35 changes: 22 additions & 13 deletions Runtime/Services/ModuleManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,24 @@ namespace Quantum.Runtime.Services;
internal class ModuleManager(ILogger<ModuleManager> logger) : IModuleManager
{
private readonly List<IModule> _loadedModules = [];
private readonly List<Assembly> _loadedAssemblies = [];
public required IServiceCollection HostServices { get; init; }
public required IServiceProvider Activator { get; init; }
public IReadOnlyList<Assembly> LoadedAssemblies => _loadedAssemblies.AsReadOnly();
public List<Assembly> LoadedAssemblies { get; } = [];

public async Task LoadModulesAsync()
{
LoadModules();

// 调用所有模块的 OnAllLoaded 方法
var initTasks = _loadedModules.Select(module =>
module.OnAllLoadedAsync()).ToList();

await Task.WhenAll(initTasks);

logger.LogInformation("All modules loaded successfully. Total modules: {Count}", _loadedModules.Count);
}

private void LoadModules()
{
// 扫描模块目录
var modulesPath = Path.Combine(AppContext.BaseDirectory, "Modules");
Expand All @@ -36,23 +48,15 @@ public async Task LoadModulesAsync()
}

var assembly = Assembly.LoadFrom(dllPath);
_loadedAssemblies.Add(assembly);
LoadedAssemblies.Add(assembly);
}

_loadedAssemblies.ForEach(RegisterModule);

// 调用所有模块的 OnAllLoaded 方法
var initTasks = _loadedModules.Select(module =>
module.OnAllLoadedAsync()).ToList();

await Task.WhenAll(initTasks);

logger.LogInformation("All modules loaded successfully. Total modules: {Count}", _loadedModules.Count);
LoadedAssemblies.ForEach(RegisterModule);
}

public void LoadModule(Assembly assembly)
{
_loadedAssemblies.Add(assembly);
LoadedAssemblies.Add(assembly);
RegisterModule(assembly);
}

Expand Down Expand Up @@ -80,6 +84,11 @@ private void RegisterModule(Assembly assembly)
// 注册为 IModule
HostServices.AddSingleton(module);

if (module is IUiModule uiModule)
{
HostServices.AddSingleton(uiModule);
}

logger.LogInformation("Registered module {ModuleId} of type {ModuleType}", module.ModuleId, moduleType.FullName);
}

Expand Down
8 changes: 4 additions & 4 deletions Runtime/Services/Quantum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

namespace Quantum.Runtime.Services;

internal class Quantum(ModuleManager moduleManager, InjectedCodeManager injectedCodeManager, ServiceManager serviceManager) : IQuantum
internal class Quantum : IQuantum
{
public BrowserWindow? Window { get; set; }
public IServiceManager ServiceManager => serviceManager;
public IModuleManager ModuleManager => moduleManager;
public IInjectedCodeManager InjectedCodeManager => injectedCodeManager;
public required IServiceCollection HostServices { get; init; }
public required IModuleManager ModuleManager { get; init; }
public required IInjectedCodeManager InjectedCodeManager { get; init; }
}
13 changes: 0 additions & 13 deletions Runtime/Services/ServiceManager.cs

This file was deleted.

4 changes: 2 additions & 2 deletions SDK/Quantum.BundleTool/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@
"Microsoft.Win32.SystemEvents.dll",
"Newtonsoft.Json.dll",
"OneOf.dll",
"Quantum.Infrastructure.*",
"Quantum.Sdk.*",
"Serilog.AspNetCore.dll",
"Serilog.dll",
"Serilog.Extensions.Hosting.dll",
Expand Down Expand Up @@ -218,4 +218,4 @@ static bool WildcardMatch(string text, string pattern)
pattern = $"^{pattern}$";

return Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase);
}
}
16 changes: 16 additions & 0 deletions SDK/Quantum.Sdk/Extensions/ServiceCollectionExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Microsoft.Extensions.DependencyInjection;
using Quantum.Sdk.Abstractions;

namespace Quantum.Sdk.Extensions;

public static class ServiceCollectionExtension
{
public static IServiceCollection AddEagerInitializeService<TService, TImplement>(this IServiceCollection services)
where TService : class, IInitializableService
where TImplement : class, TService
{
services.AddSingleton<TService, TImplement>();
services.AddSingleton<IInitializableService>(sp => sp.GetRequiredService<TService>());
return services;
}
}
5 changes: 3 additions & 2 deletions SDK/Quantum.Sdk/IQuantum.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using ElectronNET.API;
using Microsoft.Extensions.DependencyInjection;
using Quantum.Sdk.Services;

namespace Quantum.Sdk;
Expand All @@ -14,9 +15,9 @@ public interface IQuantum
BrowserWindow? Window { get; }

/// <summary>
/// 获取服务管理器实例
/// 获取运行时服务集合
/// </summary>
IServiceManager ServiceManager { get; }
IServiceCollection HostServices { get; }

/// <summary>
/// 获取模块管理器实例
Expand Down
16 changes: 0 additions & 16 deletions SDK/Quantum.Sdk/Services/IServiceManager.cs

This file was deleted.

Loading