AppDbContextFactory.cs 3.96 KB
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;

namespace Rcs.Infrastructure.DB.MsSql
{
    public class AppDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
    {
        public AppDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();

            // 尝试从环境变量读取连接字符串(优先)
            var connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING");

            // 如果环境变量不存在,则从配置文件读取
            if (string.IsNullOrEmpty(connectionString))
            {
                // 查找 appsettings.json 文件
                var currentDir = Directory.GetCurrentDirectory();

                // 尝试多个可能的路径(从当前目录、解决方案根目录等)
                var possiblePaths = new List<string>
                {
                    currentDir, // 当前目录(可能是 WebApi 项目目录)
                    Path.Combine(currentDir, "src", "HaH.RCS.WebApi"), // 从解决方案根目录
                    Path.Combine(currentDir, "HaH.RCS.WebApi"), // 从 src 目录
                    Path.Combine(currentDir, "..", "HaH.RCS.WebApi"), // 从 Infrastructure 目录
                    Path.Combine(currentDir, "..", "..", "HaH.RCS.WebApi"), // 从 Infrastructure 子目录
                    Path.Combine(currentDir, "..", "..", "..", "HaH.RCS.WebApi"), // 从 Infrastructure 更深层
                    Path.Combine(currentDir, "..", "..", "..", "..", "HaH.RCS.WebApi") // 从 Infrastructure 更深层
                };

                // 添加完整路径版本
                var fullPaths = possiblePaths
                    .Select(p => Path.GetFullPath(p))
                    .Where(p => !possiblePaths.Contains(p))
                    .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)}\n" +
                        "请确保在 WebApi 项目目录中运行迁移命令,或设置环境变量 DB_CONNECTION_STRING。");
                }

                var configuration = new ConfigurationBuilder()
                    .SetBasePath(configPath)
                    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                    .AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
                    .AddEnvironmentVariables()
                    .Build();

                connectionString = configuration.GetSection("AppSettings:ConnSql:ConnectionString").Value;
            }

            if (string.IsNullOrEmpty(connectionString))
            {
                throw new InvalidOperationException(
                    "无法找到数据库连接字符串。请确保 appsettings.json 中存在 AppSettings:ConnSql:ConnectionString 配置," +
                    "或设置环境变量 DB_CONNECTION_STRING。");
            }

            optionsBuilder.UseNpgsql(connectionString);

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