Files
EmailBill/WebApi/Program.cs
SunCheng 9e14849014
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 24s
Docker Build & Deploy / Deploy to Production (push) Successful in 6s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 2s
Docker Build & Deploy / WeChat Notification (push) Successful in 2s
feat: 添加预算统计服务增强和日志系统改进
1. 新增 BudgetStatsService:将预算统计逻辑从 BudgetService 中提取为独立服务,支持月度和年度统计,包含归档数据支持和硬性预算调整算法
2. 日志系统增强:添加请求ID追踪功能,支持通过请求ID查询关联日志,新增类名筛选功能
3. 日志解析优化:修复类名解析逻辑,正确提取 SourceContext 中的类名信息
4. 代码清理:移除不需要的方法名相关代码,简化日志筛选逻辑
2026-01-22 19:07:10 +08:00

162 lines
4.6 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 FreeSql;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.IdentityModel.Tokens;
using Scalar.AspNetCore;
using Serilog;
using Service.AppSettingModel;
using WebApi;
using WebApi.Middleware;
using Yitter.IdGenerator;
// 初始化雪花算法ID生成器
var options = new IdGeneratorOptions(1); // WorkerId 为 1可根据实际部署情况调整
YitIdHelper.SetIdGenerator(options);
var builder = WebApplication.CreateBuilder(args);
// 配置 Serilog
builder.Host.UseSerilog((context, loggerConfig) =>
{
loggerConfig.ReadFrom.Configuration(context.Configuration);
});
// Add services to the container.
builder.Services.AddControllers(mvcOptions =>
{
var policy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
mvcOptions.Filters.Add(new AuthorizeFilter(policy));
});
builder.Services.AddOpenApi();
builder.Services.AddHttpClient();
// 配置 CORS
builder.Services.AddCors(corsOptions =>
{
corsOptions.AddDefaultPolicy(policy =>
{
policy.WithOrigins("http://localhost:5173")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
// 绑定配置
builder.Services.Configure<EmailSettings>(builder.Configuration.GetSection("EmailSettings"));
builder.Services.Configure<AiSettings>(builder.Configuration.GetSection("OpenAI"));
builder.Services.Configure<JwtSettings>(builder.Configuration.GetSection("JwtSettings"));
builder.Services.Configure<AuthSettings>(builder.Configuration.GetSection("AuthSettings"));
// 配置JWT认证
var jwtSettings = builder.Configuration.GetSection("JwtSettings");
var secretKey = jwtSettings["SecretKey"]!;
var key = Encoding.UTF8.GetBytes(secretKey);
builder.Services.AddAuthentication(authenticationOptions =>
{
authenticationOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
authenticationOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwtBearerOptions =>
{
jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings["Issuer"],
ValidAudience = jwtSettings["Audience"],
IssuerSigningKey = new SymmetricSecurityKey(key),
ClockSkew = TimeSpan.Zero
};
jwtBearerOptions.Events = new JwtBearerEvents
{
OnChallenge = async context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
context.Response.ContentType = "application/json";
await context.Response.WriteAsJsonAsync(BaseResponse.Fail("未登录"));
},
OnForbidden = async context =>
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
context.Response.ContentType = "application/json";
await context.Response.WriteAsJsonAsync(BaseResponse.Fail("权限不足"));
}
};
});
builder.Services.AddAuthorization();
// 配置 FreeSql + SQLite
var dbPath = Path.Combine(AppContext.BaseDirectory, "database");
if (!Directory.Exists(dbPath))
{
Directory.CreateDirectory(dbPath);
}
// 使用绝对路径作为数据库文件路径
var dbFilePath = Path.Combine(dbPath, "EmailBill.db");
var connectionString = $"Data Source={dbFilePath}";
Log.Information("数据库路径: {DbPath}", dbFilePath);
var fsql = new FreeSqlBuilder()
.UseConnectionString(DataType.Sqlite, connectionString)
.UseAutoSyncStructure(true)
.UseLazyLoading(true)
.UseMonitorCommand(
cmd =>
{
Log.Verbose("执行SQL: {Sql}", cmd.CommandText);
}
)
.Build();
fsql.UseJsonMap();
builder.Services.AddSingleton(fsql);
// 自动扫描注册服务和仓储
builder.Services.AddServices();
// 注册日志清理后台服务
builder.Services.AddHostedService<LogCleanupService>();
// 配置 Quartz.NET 定时任务
builder.AddScheduler();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
app.MapScalarApiReference();
}
// 启用静态文件服务
app.UseDefaultFiles();
app.UseStaticFiles();
// 启用 CORS
app.UseCors();
// 启用请求ID跟踪
app.UseRequestId();
// 启用认证和授权
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
// 添加 SPA 回退路由(用于前端路由)
app.MapFallbackToFile("index.html");
app.Run();