- 将 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 读取数据库配置
141 lines
5.5 KiB
C#
141 lines
5.5 KiB
C#
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
|
||
}
|
||
}
|