campus-errand/server/Program.cs
18631081161 2d0c71721d
All checks were successful
continuous-integration/drone/push Build is passing
改bug
2026-03-29 21:13:50 +08:00

159 lines
4.4 KiB
C#
Raw Permalink 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 System.Text;
using CampusErrand.Data;
using CampusErrand.Models;
using CampusErrand.Services;
using CampusErrand.Endpoints;
using CampusErrand.Helpers;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
var builder = WebApplication.CreateBuilder(args);
// 数据库配置
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")!;
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(connectionString));
// Redis 分布式缓存配置
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration["Redis:Configuration"];
options.InstanceName = "CampusErrand:";
});
// JWT 认证配置
var jwtConfig = builder.Configuration.GetSection("Jwt");
var secretKey = Encoding.UTF8.GetBytes(jwtConfig["Secret"]!);
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtConfig["Issuer"],
ValidAudience = jwtConfig["Audience"],
IssuerSigningKey = new SymmetricSecurityKey(secretKey),
ClockSkew = TimeSpan.Zero
};
});
// 角色授权策略
builder.Services.AddAuthorizationBuilder()
.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"))
.AddPolicy("UserOrAdmin", policy => policy.RequireRole("User", "Runner", "Admin"));
// CORS 配置
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
// 注册 JWT 服务
builder.Services.AddSingleton<JwtService>();
// 注册微信服务
builder.Services.AddHttpClient<IWeChatService, WeChatService>();
// 注册腾讯 IM 服务
builder.Services.AddHttpClient();
builder.Services.AddSingleton<TencentIMService>();
// 注册微信支付服务
builder.Services.AddHttpClient<WxPayService>();
// OpenAPI 文档(.NET 10 内置)
builder.Services.AddOpenApi();
var app = builder.Build();
// 中间件管道
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
// Swagger UI 用于可视化调试
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/openapi/v1.json", "校园跑腿 API v1");
});
}
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
// 注册各模块端点
app.MapAuthEndpoints();
app.MapIMEndpoints();
app.MapBannerEndpoints();
app.MapServiceEntryEndpoints();
app.MapOrderEndpoints();
app.MapShopEndpoints();
app.MapEarningEndpoints();
app.MapMessageEndpoints();
app.MapAdminEndpoints();
app.MapConfigEndpoints();
app.MapRunnerEndpoints();
// 自动执行数据库迁移(仅关系型数据库,跳过 InMemory 测试环境)
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
if (db.Database.IsRelational() && !(db.Database.ProviderName?.Contains("InMemory") ?? false))
{
db.Database.Migrate();
}
// 初始化默认佣金规则(如果为空)
if (!db.CommissionRules.Any())
{
db.CommissionRules.Add(new CommissionRule
{
MinAmount = 0m,
MaxAmount = null,
RateType = CommissionRateType.Percentage,
Rate = 10m // 默认抽成 10%
});
db.SaveChanges();
Console.WriteLine("[初始化] 已创建默认佣金规则10% 抽成");
}
}
// 注册后台定时任务每10分钟执行一次自动确认和解冻
_ = Task.Run(async () =>
{
while (true)
{
await Task.Delay(TimeSpan.FromMinutes(10));
try
{
using var scope = app.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await BusinessHelpers.AutoConfirmExpiredOrders(db);
await BusinessHelpers.UnfreezeEarnings(db);
}
catch (Exception ex)
{
Console.WriteLine($"[定时任务] 执行失败: {ex.Message}");
}
}
});
app.Run();
// 用于集成测试访问
public partial class Program { }