ChatGPT解决这个技术问题 Extra ChatGPT

从 appsettings.json 获取 ConnectionString,而不是在 .NET Core 2.0 App 中硬编码

我在 NET Core2.0 App 中有以下课程。

// required when local database does not exist or was deleted
public class ToDoContextFactory : IDesignTimeDbContextFactory<AppContext>
{
    public AppContext CreateDbContext(string[] args)
    {
        var builder = new DbContextOptionsBuilder<AppContext>();
        builder.UseSqlServer("Server=localhost;Database=DbName;Trusted_Connection=True;MultipleActiveResultSets=true");
        return new AppContext(builder.Options);
    }
}

当数据库不存在并且必须在运行 update-database 时创建时,这在 Core 2.0 中是必需的。
Unable to create migrations after upgrading to ASP.NET Core 2.0

我不想在 2 个地方(这里和 appsettings.json)有 ConnectionString,但只在 .json 中,所以我试图替换

"Server=localhost;Database=DbName;Trusted_Connection=True;MultipleActiveResultSets=true"

ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString

但它不工作,我得到空值。

更新 1:
请注意,在 Core 2 中不需要显式添加 .json,因此问题不在于文件。
https://andrewlock.net/exploring-program-and-startup-in-asp-net-core-2-preview1-2/

更新 2:
我也是已经使用配置将 ConnectionString 从 .json 发送到上下文:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<AppContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    }
}

但是我不能将它用于 ToDoContextFactory,因为它没有配置,并且 ToDoContextFactory 被迁移使用,所以应用程序根本没有运行。

解决方案:根据@JRB的回答,我让它像这样工作:

public AppContext CreateDbContext(string[] args)
{
    string projectPath = AppDomain.CurrentDomain.BaseDirectory.Split(new String[] { @"bin\" }, StringSplitOptions.None)[0];
    IConfigurationRoot configuration = new ConfigurationBuilder()
        .SetBasePath(projectPath)
        .AddJsonFile("appsettings.json")
        .Build();
    string connectionString = configuration.GetConnectionString("DefaultConnection");

    var builder = new DbContextOptionsBuilder<AppContext>();
    builder.UseSqlServer(connectionString);

    return new AppContext(builder.Options);
}
不知道最新版本,但在早期版本中,您仍然必须将 .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 添加到 ConfigurationBuilder。你做过吗? “正常”应用程序设置是否正常工作?
在 Core2.0 中,这是自动完成的:andrewlock.net/…
在 Core2.0 中,您可以使用 System.AppContext.BaseDirectory 获取基本路径,以防您在启动时无法做到这一点,如提及@borisdj:github.com/aspnet/Announcements/issues/237
对于那些想知道 SetBasePath 来自哪里的人:stackoverflow.com/questions/46843367/… 以及 AddJsonFile 来自哪里:stackoverflow.com/questions/27382481/…
谢谢!我认为您应该在解决方案中发布单独的答案,而不是将其嵌入到您的问题中。

J
JRB

第 1 步:在 OnConfiguring() 中包含以下内容

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
            .AddJsonFile("appsettings.json")
            .Build();
        optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
    }

第 2 步:创建 appsettings.json:

  {
    "ConnectionStrings": {       
      "DefaultConnection": "Server=YOURSERVERNAME; Database=YOURDATABASENAME; Trusted_Connection=True; MultipleActiveResultSets=true"        
    } 
  }

第 3 步:将 appsettings.json 硬拷贝到正确的目录

  Hard copy appsettings.json.config to the directory specified in the AppDomain.CurrentDomain.BaseDirectory directory. 
  Use your debugger to find out which directory that is.        

假设:您已经在项目中包含了包 Microsoft.Extensions.Configuration.Json(从 Nuget 获取)。


我不同意!里面有连接字符串的“复制appsettings.json”就像在2个地方声明连接字符串一样糟糕!谁将负责保持同步?
我和 borisdj 遇到的问题的背景是 .NET Core 2.0 System.Configuration 不再存在,需要更换。为了让其他人更容易理解答案,我在步骤 3 中选择了硬拷贝方法。但是您当然是正确的,在现实世界的场景中,您将添加“appsetting.json”到您的项目中,并将“属性页面”中“常规-高级”选项卡中的“复制到输出目录”设置为“始终复制” ",之后不再需要手动复制操作。
如果您想从 appsettings.json 的自定义部分获取连接字符串,请选中此 stackoverflow.com/a/53924899/804385
我在哪里可以找到 OnConfiguring ?
@MC9000 在 OnModelCreating 旁边的 DbContext 文件中
R
Roman Gudkov

在 ASPNET Core 中,您在 Startup.cs 中执行此操作

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<BloggingContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("BloggingDatabase")));
}

您的连接在 appsettings.json 中定义

{
  "ConnectionStrings": {
    "BloggingDatabase": "..."
  },
}

MS docs 中的示例


你能检查一下吗?stackoverflow.com/questions/57000395/… 我无法在 appsettings.json 中配置 connectionString
如果我想在不同的项目中使用 DbContext,例如在 DA 层有一个单独的项目时怎么办?
K
Kevon

上面的解决方案和 Microsoft 文档中都缺少一些东西。如果您按照从上述文档链接到 GitHub 存储库的链接,您会找到真正的解决方案。

我认为混淆在于许多人使用的默认模板不包含 Startup 的默认构造函数,因此人们不一定知道注入的 Configuration 来自哪里。

因此,在 Startup.cs 中,添加:

 public IConfiguration Configuration { get; }
 public Startup(IConfiguration configuration) 
 {
     Configuration = configuration;
 }

然后在 ConfigureServices 方法中添加其他人所说的话......

services.AddDbContext<ChromeContext>(options =>                    
    options.UseSqlServer(Configuration.GetConnectionString("DatabaseConnection")));

您还必须确保您已创建 appsettings.json 文件并具有与此类似的连接字符串部分

{
  "ConnectionStrings": {
    "DatabaseConnection": "Server=MyServer;Database=MyDatabase;Persist Security Info=True;User ID=SA;Password=PASSWORD;MultipleActiveResultSets=True;"
  }
}

当然,您必须对其进行编辑以反映您的配置。

要记住的事情。这是在 .Net Standard 2.1 项目中使用 Entity Framework Core 3 测试的。我需要为以下各项添加 nuget 包:Microsoft.EntityFrameworkCore 3.0.0 Microsoft.EntityFrameworkCore.SqlServer 3.0.0,因为这是我正在使用的,也是访问 UseSqlServer 所需的。


这太好了,非常感谢!我已经找了好几个小时了。
什么是 ChromeContext ?
我收到错误,使用 (var context = new pixelleContext()) { return context.Specsheet.ToList(); }
@rahularyansharma 也许开始你自己的问题,并把这个链接?这样你的代码示例可以更彻底一点吗?在上下文中,您上面的代码片段不是很有帮助。在我的示例中,ChromeContext 是数据库上下文的名称
I
Ismail Umar

我知道这已被标记为已回答,但我在处理一个项目时遇到了一些问题,我的 .DLL 项目中的 EF Core 数据访问层与我的项目的其余部分、API、Auth 和Web 和大多数人都会喜欢我的其他项目来引用这个 Data 项目。而且我不想每次都进入 Data 项目来更改连接字符串。

第 1 步:将其包含在 OnConfiguring 方法中

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
      {
           var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
           IConfigurationRoot configuration = new ConfigurationBuilder()
                **.SetBasePath(Path.Combine(Directory.GetCurrentDirectory()))**
                .AddJsonFile("appsettings.json", optional: false)
                .AddJsonFile($"appsettings.{envName}.json", optional: false)
                .Build();
           optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
      }

注意: .SetBasePath(Path.Combine(Directory.GetCurrentDirectory())) 这将否定或无效将文件复制到目录的需要,因为 ASP.NET CORE 足够聪明,可以选择正确的文件。此外,指定的环境将在构建发布或生产时选择正确的文件,假设选择了 Prod 环境文件。

第 2 步:创建 appsettings.json

{
"ConnectionStrings": {       
  "DefaultConnection": "Server=YOURSERVERNAME; Database=YOURDATABASENAME; Trusted_Connection=True; MultipleActiveResultSets=true"        
} 

}

请:参考:Microsoft.Extensions.Configuration


我和你的情况一样,我试过这个。但是,ConfigurationBuilder 没有方法“SetBasePath”。我怀疑这是因为我的 DLL 使用的是 Standard 而不是 Core。
J
Johan Herstad

将它作为 dp 注入传递给该类怎么样?在配置服务中:

services.Configure<MyOptions>(Configuration);

创建类来保存 json 字符串:

public class MyOptions
{
    public MyOptions()
    {

    }
    public string Option1 { get; set; }
    public string Option2 { get; set; }
}    

将字符串添加到 json 文件:

"option1": "somestring",
"option2": "someothersecretstring"

在需要这些字符串的类中,作为构造函数传入:

public class SomeClass
{
 private readonly MyOptions _options;

    public SomeClass(IOptions<MyOptions> options)
    {
        _options = options.Value;           
    }    

 public void UseStrings()
 {
   var option1 = _options.Option1;
    var option2 = _options.Option2;
 //code
 }
}

我看不出这是如何解决问题的。您能否编辑答案并将您的解决方案集成到问题示例中。
@borisdj您怎么看不到它为OP的问题提供了解决方案?
@JohanHerstad 我已经尝试过您的解决方案,这是一个好主意,但我认为是因为 IDesignTimeDbContextFactory<AppContext>在设计时而不是运行时调用,您不能将 IOptions 注入到构造函数中,您可以在此处看到我的问题进一步解释:stackoverflow.com/questions/46085500/…
Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations 中创建 IDesignTimeDbContextFactory 的代码使用 Activator,因此它需要一个无参数构造函数。
是的当然。我知道我已经接触过它,但当时我无法理解,也没有时间真正研究它。我只知道我必须在将来的某个时候也实施它,永远不会忘记这个问题。我很高兴你在第一个问题被问到之后很久才花时间在下面给出答案。
E
Erikest

实际上,您可以使用一种默认模式来实现此结果,而无需实现 IDesignTimeDbContextFactory 并进行任何配置文件复制。

this doc 对此进行了详细说明,其中还讨论了框架在设计时尝试实例化您的 DbContext 的其他方式。

具体来说,您利用了一个新的钩子,在本例中是 public static IWebHost BuildWebHost(string[] args) 形式的静态方法。文档另有暗示,但此方法可以存在于您的入口点 (see src) 所在的任何类中。实现这一点是 1.x to 2.x migration document 中指导的一部分,从代码中看不完全清楚的是,对 WebHost.CreateDefaultBuilder(args) 的调用除其他外,以新项目开始时使用的默认模式连接您的配置。这就是让设计时服务(如迁移)使用的配置所需的全部内容。

这里有更多关于那里发生的事情的详细信息:

在添加迁移时,当框架尝试创建您的 DbContext 时,它 first 会将找到的任何 IDesignTimeDbContextFactory 实现添加到可用于创建上下文的工厂方法集合中,然后通过以下方式获取您配置的服务前面讨论的静态钩子和 looks 用于使用 DbContextOptions 注册的任何上下文类型(当您使用 AddDbContextAddDbContextPool 时会在 Startup.ConfigureServices 中发生)并添加这些工厂。最后,它 looks 通过对任何 DbContext 派生类的程序集创建一个工厂方法,该方法只调用 Activator.CreateInstance 作为最终的 hail mary。

框架使用的优先顺序与上述相同。因此,如果您实现了 IDesignTimeDbContextFactory,它将覆盖上面提到的钩子。但对于最常见的情况,您不需要 IDesignTimeDbContextFactory


如果我在单独的项目中有 DbContext,它将不起作用。
J
Jonathan Kittell

您也可以在 ASP.NET Core 2 中通过在 appSettings.json 文件中定义连接字符串来执行此操作。然后在您的 Startup.cs 中指定要使用的连接字符串。

appSettings.json

{
    "connectionStrings": {
        "YourDBConnectionString": "Server=(localdb)\\mssqllocaldb;Database=YourDB;Trusted_Connection=True"
    }
}

Startup.cs

public static IConfiguration Configuration { get; private set;}

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}
var connectionString = Configuration["connectionStrings:YourDBConnectionString"];
services.AddDbContext<YourDbContext>(x => x.UseSqlServer(connectionString));

T
TT.

将以下代码添加到 startup.cs 文件中。 public void ConfigureServices(IServiceCollection services) { string con = Configuration.GetConnectionString("DBConnection");服务.AddMvc(); GlobalProperties.DBConnection = con;//DBConnection 是 GlobalProperties 类的一个用户定义的静态属性 } 在 Context 类中使用 GlobalProperties.DBConnection 属性。 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { optionsBuilder.UseSqlServer(GlobalProperties.DBConnection); } }


M
Magus

我知道这并不奇怪,但您可以使用回调类,创建主机构建器并将配置设置为静态属性。

对于 asp 核心 2.2:

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using System;

namespace Project
{
    sealed class Program
    {
        #region Variables
        /// <summary>
        /// Last loaded configuration
        /// </summary>
        private static IConfiguration _Configuration;
        #endregion

        #region Properties
        /// <summary>
        /// Default application configuration
        /// </summary>
        internal static IConfiguration Configuration
        {
            get
            {
                // None configuration yet?
                if (Program._Configuration == null)
                {
                    // Create the builder using a callback class
                    IWebHostBuilder builder = WebHost.CreateDefaultBuilder().UseStartup<CallBackConfiguration>();

                    // Build everything but do not initialize it
                    builder.Build();
                }

                // Current configuration
                return Program._Configuration;
            }

            // Update configuration
            set => Program._Configuration = value;
        }
        #endregion

        #region Public
        /// <summary>
        /// Start the webapp
        /// </summary>
        public static void Main(string[] args)
        {
            // Create the builder using the default Startup class
            IWebHostBuilder builder = WebHost.CreateDefaultBuilder(args).UseStartup<Startup>();

            // Build everything and run it
            using (IWebHost host = builder.Build())
                host.Run();
        }
        #endregion


        #region CallBackConfiguration
        /// <summary>
        /// Aux class to callback configuration
        /// </summary>
        private class CallBackConfiguration
        {
            /// <summary>
            /// Callback with configuration
            /// </summary>
            public CallBackConfiguration(IConfiguration configuration)
            {
                // Update the last configuration
                Program.Configuration = configuration;
            }

            /// <summary>
            /// Do nothing, just for compatibility
            /// </summary>
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                //
            }
        }
        #endregion
    }
}

因此,现在您只需在您需要的任何其他类中使用静态 Program.Configuration 即可。


J
Jnyanendra Sethi

如果您需要不同的图层:

创建一个静态类并公开该层上的所有配置属性,如下所示:

使用 Microsoft.Extensions.Configuration;使用 System.IO;命名空间 Core.DAL { public static class ConfigSettings { public static string conStr1 { get ; } 静态 ConfigSettings() { var configurationBuilder = new ConfigurationBuilder();字符串路径 = Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json"); configurationBuilder.AddJsonFile(path, false); conStr1 = configurationBuilder.Build().GetSection("ConnectionStrings:ConStr1").Value; } } }


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅