AppDbContextFactory.cs 3.48 KB
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using Npgsql;
using Rcs.Domain.Settings;

namespace Rcs.Infrastructure.DB.MsSql
{
    public class AppDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
    {
        public AppDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
            var currentDir = Directory.GetCurrentDirectory();
            var possiblePaths = new List<string>
            {
                currentDir,
                Path.Combine(currentDir, "src", "Rcs.Api"),
                Path.Combine(currentDir, "Rcs.Api"),
                Path.Combine(currentDir, "..", "Rcs.Api"),
                Path.Combine(currentDir, "..", "..", "Rcs.Api"),
                Path.Combine(currentDir, "src", "HaH.RCS.WebApi"),
                Path.Combine(currentDir, "HaH.RCS.WebApi"),
                Path.Combine(currentDir, "..", "HaH.RCS.WebApi"),
                Path.Combine(currentDir, "..", "..", "HaH.RCS.WebApi"),
                Path.Combine(currentDir, "..", "..", "..", "HaH.RCS.WebApi"),
                Path.Combine(currentDir, "..", "..", "..", "..", "HaH.RCS.WebApi")
            };

            var fullPaths = possiblePaths
                .Select(Path.GetFullPath)
                .Where(path => !possiblePaths.Contains(path))
                .ToList();
            possiblePaths.AddRange(fullPaths);

            string? configPath = null;
            foreach (var path in possiblePaths.Distinct())
            {
                try
                {
                    var appsettingsPath = Path.Combine(path, "appsettings.json");
                    if (File.Exists(appsettingsPath))
                    {
                        configPath = path;
                        break;
                    }
                }
                catch
                {
                    continue;
                }
            }

            if (configPath == null)
            {
                throw new InvalidOperationException(
                    $"无法找到 appsettings.json 文件。已尝试以下路径:\n{string.Join("\n", possiblePaths)}");
            }

            var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development";
            var configuration = new ConfigurationBuilder()
                .SetBasePath(configPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
                .AddJsonFile($"appsettings.{environment}.json", optional: true, reloadOnChange: false)
                .Build();

            var appSettings = configuration.GetSection(nameof(AppSettings)).Get<AppSettings>();
            var connectionString = appSettings?.ConnSql.ConnectionString;

            if (string.IsNullOrWhiteSpace(connectionString))
            {
                throw new InvalidOperationException("无法从 AppSettings.ConnSql.ConnectionString 读取数据库连接字符串。");
            }

            // 创建 NpgsqlDataSource 并启用动态 JSON 序列化
            var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
            dataSourceBuilder.UseNetTopologySuite();
            dataSourceBuilder.EnableDynamicJson();
            var dataSource = dataSourceBuilder.Build();

            optionsBuilder.UseNpgsql(dataSource, o => o.UseNetTopologySuite());

            return new AppDbContext(optionsBuilder.Options);
        }
    }
}