diff --git a/.gitignore b/.gitignore
index 4918c6c..aa66bfa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,4 +17,8 @@
/avalonia-web-react/obj
/avalonia-web-react/obj
/avalonia-web-react/node_modules
-/avalonia-web-react/dist
\ No newline at end of file
+/avalonia-web-react/dist
+/Avalonia-EFCore/bin
+/Avalonia-EFCore/obj
+/Avalonia-Common/bin
+/Avalonia-Common/obj
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..1cb80bb
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,6 @@
+{
+ "chat.tools.terminal.autoApprove": {
+ "ForEach-Object": true,
+ "dotnet list": true
+ }
+}
\ No newline at end of file
diff --git a/Avalonia-API/Avalonia-API.csproj b/Avalonia-API/Avalonia-API.csproj
index 3b60685..56c79b6 100644
--- a/Avalonia-API/Avalonia-API.csproj
+++ b/Avalonia-API/Avalonia-API.csproj
@@ -9,10 +9,17 @@
+
+
+
+
+
+
+
diff --git a/Avalonia-API/Avalonia-API.csproj.user b/Avalonia-API/Avalonia-API.csproj.user
index 9ff5820..983ecfc 100644
--- a/Avalonia-API/Avalonia-API.csproj.user
+++ b/Avalonia-API/Avalonia-API.csproj.user
@@ -1,6 +1,9 @@
- https
+ http
+
+
+ ProjectDebugger
\ No newline at end of file
diff --git a/Avalonia-API/Configuration/ServicesConfiguration.cs b/Avalonia-API/Configuration/ServicesConfiguration.cs
index 823bc0f..6d3a6a0 100644
--- a/Avalonia-API/Configuration/ServicesConfiguration.cs
+++ b/Avalonia-API/Configuration/ServicesConfiguration.cs
@@ -1,15 +1,38 @@
-using Avalonia_Services.Services;
+using Avalonia_EFCore.Database;
+using Avalonia_Services.Core;
+using Avalonia_Services.Database;
+using Avalonia_Services.Endpoints;
+using Avalonia_Services.Services;
+using Microsoft.Extensions.DependencyInjection;
namespace Avalonia_API.Configuration
{
public static class ServicesConfiguration
{
- public static void ConfigureServices(this IServiceCollection services)
+ ///
+ /// 注册统一端点及其依赖的服务(含数据库)。
+ /// 所有业务端点定义在 Avalonia-Services/Endpoints/AppEndpoints.cs。
+ ///
+ public static IServiceCollection AddUnifiedApiServices(this IServiceCollection services)
{
- // Register your services here
- // For example:
- // services.AddSingleton();
+ // ---- 数据库 ----
+ // 从 appsettings.json 读取 DatabaseConfiguration 节
+ // 注册默认数据库提供程序(SQLite / MySQL / PostgreSQL / SqlServer)
+ DatabaseProviderRegistry.RegisterDefaults();
+
+ // 注册 AppDataContext(共享数据上下文)
+ services.AddAppDatabase(DatabaseConfiguration.ForSQLite("app.db"));
+
+ // ---- 业务服务 ----
services.AddScoped();
+
+ // ---- 统一端点 ----
+ var endpointBuilder = new ServiceEndpointBuilder();
+ AppEndpoints.Configure(endpointBuilder);
+ var endpoints = endpointBuilder.Build();
+ services.AddSingleton(endpoints);
+
+ return services;
}
}
}
diff --git a/Avalonia-API/Controllers/WeatherForecastController.cs b/Avalonia-API/Controllers/WeatherForecastController.cs
deleted file mode 100644
index 7b83edf..0000000
--- a/Avalonia-API/Controllers/WeatherForecastController.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Avalonia_Services.Models;
-using Avalonia_Services.Services;
-using Microsoft.AspNetCore.Mvc;
-
-namespace Avalonia_API.Controllers
-{
- [ApiController]
- [Route("[controller]")]
- public class WeatherForecastController(WeatherForecastService weatherForecastService) : ControllerBase
- {
-
- private readonly WeatherForecastService _weatherForecastService = weatherForecastService;
-
- [HttpGet(Name = "GetWeatherForecast")]
- public IEnumerable Get()
- {
- return _weatherForecastService.GetWeatherForecasts();
- }
- }
-}
diff --git a/Avalonia-API/Extensions/UnifiedEndpointExtensions.cs b/Avalonia-API/Extensions/UnifiedEndpointExtensions.cs
new file mode 100644
index 0000000..f43482f
--- /dev/null
+++ b/Avalonia-API/Extensions/UnifiedEndpointExtensions.cs
@@ -0,0 +1,163 @@
+using Avalonia_Services.Core;
+using AspNetCoreFilterContext = Microsoft.AspNetCore.Http.EndpointFilterInvocationContext;
+using AspNetCoreFilterDelegate = Microsoft.AspNetCore.Http.EndpointFilterDelegate;
+// 解决与 ASP.NET Core 同名类型的冲突
+using UnifiedFilter = Avalonia_Services.Core.IEndpointFilter;
+
+namespace Avalonia_API.Extensions
+{
+ ///
+ /// 将 Avalonia-Services 的统一端点映射到 ASP.NET Core Minimal API。
+ /// 支持鉴权、过滤器、中间件的完整 ASP.NET Core 管道。
+ ///
+ public static class UnifiedEndpointExtensions
+ {
+ ///
+ /// 将 ServiceEndpointCollection 中的所有端点注册到 ASP.NET Core 路由。
+ ///
+ public static IEndpointRouteBuilder MapUnifiedEndpoints(
+ this IEndpointRouteBuilder routeBuilder,
+ ServiceEndpointCollection endpoints,
+ IServiceProvider serviceProvider)
+ {
+ var apiGroup = routeBuilder.MapGroup("/");
+
+ foreach (var endpoint in endpoints.Endpoints)
+ {
+ var routeHandlerBuilder = MapEndpoint(apiGroup, endpoint, serviceProvider);
+
+ // 全局过滤器 → ASP.NET Core Endpoint Filters
+ foreach (var globalFilter in endpoints.GlobalFilters)
+ {
+ routeHandlerBuilder.AddEndpointFilter(
+ async (context, next) => await ConvertFilterAsync(globalFilter, context, next));
+ }
+
+ // 端点专属过滤器
+ foreach (var filter in endpoint.Filters)
+ {
+ routeHandlerBuilder.AddEndpointFilter(
+ async (context, next) => await ConvertFilterAsync(filter, context, next));
+ }
+
+ // 鉴权(使用 ASP.NET Core 原生鉴权机制)
+ if (endpoint.RequireAuthorization)
+ {
+ if (!string.IsNullOrEmpty(endpoint.Policy))
+ {
+ routeHandlerBuilder.RequireAuthorization(endpoint.Policy);
+ }
+ else
+ {
+ routeHandlerBuilder.RequireAuthorization();
+ }
+ }
+
+ if (!string.IsNullOrEmpty(endpoint.Name))
+ {
+ routeHandlerBuilder.WithName(endpoint.Name);
+ }
+ }
+
+ return routeBuilder;
+ }
+
+ private static RouteHandlerBuilder MapEndpoint(
+ IEndpointRouteBuilder group,
+ ServiceEndpoint endpoint,
+ IServiceProvider serviceProvider)
+ {
+ var handler = CreateAspNetCoreHandler(endpoint.Handler, serviceProvider);
+
+ return endpoint.HttpMethod.ToUpperInvariant() switch
+ {
+ "GET" => group.MapGet(endpoint.Pattern, handler),
+ "POST" => group.MapPost(endpoint.Pattern, handler),
+ "PUT" => group.MapPut(endpoint.Pattern, handler),
+ "DELETE" => group.MapDelete(endpoint.Pattern, handler),
+ _ => group.MapGet(endpoint.Pattern, handler),
+ };
+ }
+
+ private static Delegate CreateAspNetCoreHandler(
+ Func> unifiedHandler,
+ IServiceProvider serviceProvider)
+ {
+ return async (HttpContext httpContext) =>
+ {
+ var ctx = await BuildContextFromHttpContext(httpContext);
+ ctx.Items["ServiceProvider"] = serviceProvider;
+
+ var result = await unifiedHandler(ctx);
+
+ // 同步响应状态
+ httpContext.Response.StatusCode = ctx.StatusCode;
+ foreach (var kvp in ctx.ResponseHeaders)
+ {
+ httpContext.Response.Headers[kvp.Key] = kvp.Value;
+ }
+
+ return result is not null ? Results.Json(result) : Results.Ok();
+ };
+ }
+
+ private static async Task BuildContextFromHttpContext(HttpContext httpContext)
+ {
+ var ctx = new ServiceEndpointContext
+ {
+ Path = httpContext.Request.Path.Value ?? "/",
+ Method = httpContext.Request.Method,
+ StatusCode = 200,
+ };
+
+ foreach (var header in httpContext.Request.Headers)
+ {
+ ctx.Headers[header.Key] = header.Value.ToString();
+ }
+
+ foreach (var query in httpContext.Request.Query)
+ {
+ ctx.Query[query.Key] = query.Value.ToString();
+ }
+
+ if (httpContext.Request.ContentLength > 0)
+ {
+ using var reader = new StreamReader(httpContext.Request.Body);
+ ctx.Body = await reader.ReadToEndAsync();
+ }
+
+ ctx.Items["HttpContext"] = httpContext;
+
+ return ctx;
+ }
+
+ private static async ValueTask