luoqian c5f741e6a4 feat: 将数据库模型和迁移集中到 EFCore 项目
- 将 AppDataContext、实体模型、Migrations 从 Avalonia-Services 移动到 Avalonia-EFCore
- 更新 API、PC、Services 中的数据库上下文和实体引用命名空间
- 在实体上显式绑定表名、字段名和数据库注释
- 更新 InitialCreate、Designer、Snapshot,使用新的表名、字段名和注释
- 新增 AppDataContextFactory,支持 dotnet ef 设计时创建 DbContext
- 新增本地 dotnet-ef 工具清单
- 新增一键生成迁移脚本 add-migration.ps1 / .cmd / .bat
- 启动时自动检测并执行未应用迁移
- 从 appsettings.json 读取数据库配置
2026-05-15 15:26:46 +08:00

141 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Avalonia_Common.Core;
using Avalonia_EFCore.Database;
using Avalonia_EFCore.Models;
using Avalonia_Services.Core;
using Avalonia_Services.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Avalonia_Services.Endpoints
{
/// <summary>
/// 统一端点配置 —— 所有业务端点在此定义一次。
/// 这是 Avalonia-API 和 Avalonia-PC 的唯一入口。
/// </summary>
public static class AppEndpoints
{
/// <summary>
/// 配置所有业务端点。调用方传入 builder按需叠加鉴权、过滤器等。
/// </summary>
/// <param name="builder">端点构建器</param>
/// <param name="includeDetails">是否在错误响应中包含异常详情(开发环境 true</param>
public static ServiceEndpointBuilder Configure(ServiceEndpointBuilder builder, bool includeDetails = false)
{
// ---- 全局异常拦截(自动捕获所有端点中未处理的异常) ----
builder.Endpoints.AddGlobalFilter(new GlobalExceptionFilter(includeDetails));
builder.ConfigureEndpoints(endpoints =>
{
// ---- 全局日志过滤器(记录每个请求) ----
endpoints.AddGlobalFilter(async (ctx, next) =>
{
Serilog.Log.Debug("→ {Method} {Path}", ctx.Method, ctx.Path);
await next(ctx);
Serilog.Log.Debug("← {Method} {Path} | {StatusCode}", ctx.Method, ctx.Path, ctx.StatusCode);
});
// ---- 业务端点注册 ----
// 天气预报(从数据库读取)
endpoints.MapGet("api/wData", GetWeatherForecastsAsync)
.WithName("GetWeatherForecast");
// 获取用户(演示从数据库查询)
endpoints.MapGet("api/getUser", GetUserFromDatabaseAsync)
.WithName("GetUser");
// 处理数据POST — 演示参数处理)
endpoints.MapPost("api/processData", ProcessDataAsync)
.WithName("ProcessData");
// ---- 需要鉴权的端点示例 ----
// endpoints.MapGet("api/admin/dashboard", AdminDashboardAsync)
// .WithName("AdminDashboard")
// .RequireAuthorization = true
// .Policy = "AdminOnly";
});
return builder;
}
#region
/// <summary>
/// 从数据库查询天气预报(优先数据库,回退到内存生成)。
/// </summary>
private static async Task<object?> GetWeatherForecastsAsync(ServiceEndpointContext ctx)
{
var sp = ctx.Items["ServiceProvider"] as IServiceProvider;
// 尝试从数据库读取
if (sp?.GetService(typeof(AppDataContext)) is AppDataContext db)
{
var dbForecasts = await db.WeatherForecasts
.OrderByDescending(f => f.Date)
.Take(5)
.ToListAsync();
if (dbForecasts.Count > 0)
{
return ResponseHelper.Ok(dbForecasts, "获取天气预报成功(来自数据库)");
}
}
// 回退:内存生成(数据库为空时)
var service = sp?.GetService(typeof(WeatherForecastService)) as WeatherForecastService
?? new WeatherForecastService();
var forecasts = service.GetWeatherForecasts();
return ResponseHelper.Ok(forecasts, "获取天气预报成功(内存生成)");
}
private static async Task<object?> GetUserFromDatabaseAsync(ServiceEndpointContext ctx)
{
var sp = ctx.Items["ServiceProvider"] as IServiceProvider;
// 尝试从数据库读取用户
if (sp?.GetService(typeof(AppDataContext)) is AppDataContext db)
{
var users = await db.Set<UserEntity>().Take(1).ToListAsync();
if (users.Count > 0)
{
return ResponseHelper.Ok(users[0], "获取用户成功(来自数据库)");
}
}
// 回退:演示数据
await Task.Delay(100);
var user = new { id = 1, name = "张三", email = "zhangsan@example.com" };
return ResponseHelper.Ok(user);
}
private static async Task<object?> ProcessDataAsync(ServiceEndpointContext ctx)
{
var sp = ctx.Items["ServiceProvider"] as IServiceProvider;
// 演示:将收到的数据存入数据库
var input = ctx.Body ?? string.Empty;
if (sp?.GetService(typeof(AppDataContext)) is AppDataContext db && !string.IsNullOrWhiteSpace(input))
{
var forecast = new WeatherForecastEntity
{
Date = DateOnly.FromDateTime(DateTime.Now),
TemperatureC = 20,
Summary = input,
};
db.WeatherForecasts.Add(forecast);
await db.SaveChangesAsync();
return ResponseHelper.Ok(forecast, "数据已存入数据库");
}
await Task.Delay(200);
return ResponseHelper.Ok(new { input, processed = input.ToUpperInvariant() });
}
#endregion
}
}