【问题标题】:An attempt to attach an auto-named database failed尝试附加自动命名的数据库失败
【发布时间】:2020-11-11 02:50:25
【问题描述】:

目标
我正在尝试在 ASP.NET Core Web 应用程序和其他项目/解决方案之间共享一个类库,并且该类应该能够与调用进程/环境正在使用的任何数据库进行交互。

问题
我有一个类库在我的 ASP.NET Core 3.1 Web 应用程序中使用时抛出了一个奇怪的错误。类库实际上在前端(网站)和后端应用程序之间共享,负责处理一些重复的、重负载的过程。我在前端和后端都使用 EF Core,并且数据库在 Azure 上,不是我的本地计算机。然而,当网络应用程序尝试做一些工作时,我收到以下错误:

尝试为文件 C:...\bin\Debug\netcoreapp3.1\aspnetdb.mdf 附加自动命名数据库失败。存在同名数据库,或指定文件无法打开,或位于 UNC 共享上。

这对我来说根本没有意义,因为数据库位于 Azure 上。此外,使用后端应用程序在库中调用相同的方法不会引发此错误。连接字符串存储在网站的appsettings.json 和后端的app.config 中。

这是引发错误的代码块,但这仅在 ASP.NET Core 项目上的SaveChanges() 调用中发生:

public static void AddLogEvent(int Severity, DateTime EventTime, string EventType, string User, string Message)
{
        DBEntities context = new DBEntities();
        DbSet<LogEvent> dbSet = context.Set<LogEvent>();
        LogEvent NewRecord = new LogEvent();
        NewRecord.Id = Guid.NewGuid();
        NewRecord.Severity = Severity;
        NewRecord.EventTime = EventTime;
        NewRecord.EventType = EventType;
        NewRecord.User = User;
        NewRecord.Message = Message;

        dbSet.Add(NewRecord);

        context.SaveChanges();
}

DBEntities 中,我将覆盖OnConfiguring() 方法,以确保在任何环境下都能正确连接:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
        if (!optionsBuilder.IsConfigured)
        {
            bool FoundValidConnection = false;

            if (ConfigurationManager.ConnectionStrings.Count > 0)
            {
                foreach (ConnectionStringSettings connstr in ConfigurationManager.ConnectionStrings)
                {
                    if (FoundValidConnection == false)
                    {
                        if (string.Compare(connstr.Name.Trim().ToUpper(), "DefaultConnection".ToUpper()) == 0)
                        {
                            optionsBuilder.UseSqlServer(connstr.ConnectionString);
                            FoundValidConnection = true;
                            break;
                        }
                    }
                }

                foreach (ConnectionStringSettings connstr in ConfigurationManager.ConnectionStrings)
                {
                    if (FoundValidConnection == false)
                    {
                        if (string.Compare(connstr.Name.Trim().ToUpper(), "DBEntities".ToUpper()) == 0)
                        {
                            optionsBuilder.UseSqlServer(connstr.ConnectionString);
                            FoundValidConnection = true;
                            break;
                        }
                    }
                }

                if (FoundValidConnection == false)
                {
                    //if still haven't found one of the expected connection string names, then take whatever the first one is.
                    optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings[0].ConnectionString);
                    FoundValidConnection = true;
                }
            }
            else
            {
                //nothing to do.  there are no connection strings in the ConfigurationManager
            }
        }
}

最后,当我在网站上单步调试时,我可以看到位于ConfigurationManager.ConnectionStrings 的唯一连接字符串是 1,名称为LocalSqlServer,连接字符串设置为:

data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true

这似乎是我的本地测试 SQLExpress 实例,但未在网络应用程序的任何地方使用。 SQLExpress 中本地测试数据库的所有引用或连接字符串都已被删除,所以我很困惑这是如何显示的,而 appsettings.json 中的那个被忽略了。我也不明白 optionsBuilder.IsConfigured 如何在 Web 应用程序上返回 FALSE。我希望已经配置了该上下文。

【问题讨论】:

  • 我希望已经配置了该上下文 - 当您使用无参数构造函数 (= new DBEntities();) 时,它从未配置过。当你使用 DI 或有一个带有 DbContextOptions 参数的构造函数时,它将被配置,该参数是外部配置的。
  • 好的,感谢您提供的信息。这有点帮助,但我不确定这与网络应用程序抛出的错误有何关系,这似乎与它甚至不应该知道存在的完全不同的数据库有关。我不确定为什么 Web 应用程序的 ConfigurationManager.ConnectionStrings 集合只包含我什至没有在 appsettings.json 中设置的那个集合。我不知道它是从哪里来的,也不知道它为什么要使用它。
  • 这与 EF Core 无关,是您必须弄清楚的事情。首先,ConfigurationManager 变量是什么,它来自哪里以及如何初始化。
  • 您似乎正在使用来自System.ConfigurationConfigurationManager,它仅适用于app.config 文件。对于 .Net Core 应用程序 (appsettings.json),您需要一种不同的方法。见stackoverflow.com/questions/39083372/…
  • 感谢您为我指明了正确的方向。当我弄清楚时,我会跟进并提交答案与他人分享。似乎依赖注入可能是要走的路。

标签: c# asp.net-core entity-framework-core


【解决方案1】:

我最终将最后一个 if 语句更改为以下内容:

                if (FoundValidConnection == false)
                {
                    try
                    {
                        //read from appsettings.json directly instead
                        string connString = new ConfigurationBuilder().SetBasePath(System.IO.Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build().GetSection("ConnectionStrings").GetSection("DefaultConnection").Value;
                        optionsBuilder.UseSqlServer(connString);
                        FoundValidConnection = true;
                    }
                    catch (System.Exception ex)
                    {

                    }
                }

正如 Ivan 在上面的 cmets 中指出的,来自 System.ConfigurationConfigurationManager 仅适用于基于 XML 的 app.config。 ASP.NET Core 使用appsettings.json,这显然是基于 JSON 的。所以解决方案是修改最后一个检查,如果app.config 检查失败并且什么也没产生,那么我们假设代码被使用appsettings.json 的东西调用,并且一行使用ConfigurationBuilder 来获取应用程序的目录,基于该文件构建配置,并通过其部分和名称获得预期的连接。

SetBasePath()AddJsonFile() 需要分别引用 Microsoft.Extensions.Configuration.FileExtensionsMicrosoft.Extensions.Configuration.Json

如果出现一些不可预见的错误并且 appsettings/json 不包含预期的部分/名称,则需要 try/catch 块。但是,如果没有设置任何内容,在尝试与数据库交互时最终会在某处抛出错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    • 1970-01-01
    • 2012-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多