Program.cs 5.22 KB
using Rcs.Api;
using Rcs.Api.BackgroundServices;
using Rcs.Api.Hubs;
using Rcs.Infrastructure.Installs;
using Rcs.Infrastructure.PathFinding;
using Serilog;

// 配置 Serilog 日志
Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
        .Build())
    .CreateLogger();

try
{
    var builder = WebApplication.CreateBuilder(args);

    // 使用 Serilog 替代默认日志
    builder.Host.UseSerilog();

    // Add services to the container.
    builder.Services.AddControllers();
    // 添加 CORS 策略,允许跨域访问(根据需要修改策略)
    builder.Services.AddCors(options =>
    {
        options.AddPolicy("DefaultCorsPolicy", policy =>
        {
            policy.SetIsOriginAllowed(_ => true)
                  .AllowAnyMethod()
                  .AllowAnyHeader()
                  .AllowCredentials();
        });
    });

    // 添加 SignalR(使用 camelCase JSON 序列化)
    builder.Services.AddSignalR().AddJsonProtocol(options =>
    {
        options.PayloadSerializerOptions.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase;
    });

    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
        {
            Title = "HHRCS API",
            Version = "v1",
            Description = "长沙华恒机器人控制系统 API"
        });
    });

    // 安装应用配置
    builder.InstallApplicationSettings();

    // 安装Entity Framework
    builder.InstallEntityFramework();

    // 安装依赖注入
    builder.InstallDependencyInjection();

    // 安装 AutoMapper
    builder.Services.InstallAutoMapper();

    // 安装 Redis
    builder.InstallRedis();
    // 安装 Mqtt
    builder.InstallMqtt();
    // 安装过滤器
    builder.InstallFilters();

    // 安装消息总线 (MassTransit + RabbitMQ)
    builder.InstallMessageBus();
    // 安装 LanYin 服务
    builder.Services.InstallLanYinService();
    builder.Services.InstallHttpClient();
    // 交通管制服务
    builder.Services.InstallerPathService();

    // 添加机器人状态推送后台服务
    builder.Services.AddHostedService<RobotStatusPushService>();

    var app = builder.Build();

    // 自动运行数据库迁移
    using (var scope = app.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        try
        {
            app.Logger.LogInformation("开始初始化数据库...");
            var dbContext = services.GetRequiredService<Rcs.Infrastructure.DB.MsSql.AppDbContext>();
            EntityFrameworkInstaller.SeedDatabase(dbContext);
            app.Logger.LogInformation("✓ 数据库初始化成功完成");
        }
        catch (Exception ex)
        {
            app.Logger.LogError(ex, "✗ 数据库初始化失败");
            throw;
        }
    }

    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }

    app.UseHttpsRedirection();

    // 使用 CORS 策略
    app.UseCors("DefaultCorsPolicy");

    // 配置静态文件服务,允许访问上传的文件
    app.UseStaticFiles();
    // 配置上传文件的静态访问路径(使用内容根目录确保 Debug 和 Release 模式一致)
    var uploadsPath = Path.Combine(app.Environment.ContentRootPath, "uploads");
    if (!Directory.Exists(uploadsPath))
    {
        Directory.CreateDirectory(uploadsPath);
    }
    app.Logger.LogInformation("静态文件路径: {UploadsPath}", uploadsPath);
    app.UseStaticFiles(new Microsoft.AspNetCore.Builder.StaticFileOptions
    {
        FileProvider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(uploadsPath),
        RequestPath = "/uploads",
        OnPrepareResponse = ctx =>
        {
            // 禁用缓存,确保每次都获取最新文件
            ctx.Context.Response.Headers.Append("Cache-Control", "no-cache, no-store, must-revalidate");
            ctx.Context.Response.Headers.Append("Pragma", "no-cache");
            ctx.Context.Response.Headers.Append("Expires", "0");
            // 添加 CORS 头,允许 SVG 图片跨域访问
            ctx.Context.Response.Headers.Append("Access-Control-Allow-Origin", "*");
            ctx.Context.Response.Headers.Append("Access-Control-Allow-Methods", "GET, OPTIONS");
            ctx.Context.Response.Headers.Append("Access-Control-Allow-Headers", "*");
        }
    });

    app.MapControllers();

    // 映射 SignalR Hub(支持地图隔离)
    app.MapHub<HHRCSHub>("/{mapId}/hubs/HHRCS");

    app.Run();
}
finally
{
    // 确保 Serilog 日志在程序关闭时正确刷新
    Log.CloseAndFlush();
}

namespace Rcs.Api
{
    record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
    {
        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    }
}