【问题标题】:ASP.NET vNext global config accessASP.NET vNext 全局配置访问
【发布时间】:2015-08-17 19:30:48
【问题描述】:

在 ASP.NET vNext 中访问 config.json 文件(或存储配置的其他位置)的正确/推荐方式是什么?

Startup 类中,我这样设置配置:

public class Startup
{
    public IConfiguration Configuration { get; set; }

public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
    var configurationBuilder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
        .AddJsonFile("config.json")
        .AddEnvironmentVariables();

    Configuration = configurationBuilder.Build();
}

但是如果我需要在其他地方访问连接字符串,我该怎么做呢?比如在一个EF上下文的OnConfiguring中,如何获取连接字符串:

protected override void OnConfiguring(EntityOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer( ??? );

我听说你可以使用这个:

var config = Startup.Configuration
    ?? new Configuration()
        .AddJsonFile("config.json")
        .AddEnvironmentVariables();

但是 (a) 启动不是静态的,并且 (b) 您肯定不想在每次需要时都重新构建配置设置 - 这是在使用它的任何地方复制代码。

我还读到您应该使用Dependency Injection,但该链接并未完全向您展示如何操作。如果我的 DbContext 构造函数有一个注入参数,那么如何将它注入到无参数的 BaseApiController 中?

这看起来确实是一个常见/简单的要求:在 Startup 中进行配置之后,如何在其他地方访问该配置?这应该在任何地方的文档/示例中。

【问题讨论】:

    标签: asp.net asp.net-core


    【解决方案1】:

    这是我的工作:

    启动

    public class Startup
    {
        public IConfiguration Configuration { get; set; }
    
        public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
        {
            // create & store the configuration once
            var configurationBuilder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
                .AddJsonFile("config.json")
                .AddEnvironmentVariables();
    
            Configuration = configurationBuilder.Build();
        }
    
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddEntityFramework()
                .AddSqlServer()
                .AddDbContext<Context>(options => options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
    
            services.AddIdentity<User, IdentityRole>()
                    .AddEntityFrameworkStores<Context>()
                    .AddDefaultTokenProviders();
    
            services.AddMvc();
    
            // adding/registering the dbContext for dependency injection as a singleton
            services.AddSingleton(s => new Context(Configuration));
        }
    
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseIdentity();
    
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                      name: "default",
                      template: "{controller}/{action}/{id?}",
                      defaults: new { controller = "Home", action = "Index" });
            });
        }
    }
    

    数据库上下文

    public sealed class Context : IdentityDbContext<IdentityUser>
    {
        private readonly IConfiguration _config;
        public DbSet<Client> Clients { get; set; }
    
        public Context(IConfiguration config)
        {
            // store the injected config
            _config = config;
        }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ForSqlServer().UseIdentity();
            base.OnModelCreating(modelBuilder);
        }
    
        protected override void OnConfiguring(EntityOptionsBuilder optionsBuilder)
        {
            // use the injected config
            optionsBuilder.UseSqlServer(_config.Get("Data:DefaultConnection:ConnectionString"));
    
            base.OnConfiguring(optionsBuilder);
        }
    }
    

    控制器

    [Route("api/[controller]")]
    public class TestController : BaseController
    {
        private readonly Context _context;
    
        // have the context injected
        public TestController(Context context)
        {
            _context = context;
        }
    
        [HttpGet]
        public ActionResult Get()
        {
            return new ObjectResult(_context.Clients.ToList());
        }
    }
    

    【讨论】:

      【解决方案2】:

      首先,您应该避免将数据库上下文注册为单例。传递原始的IConfiguration 接口也不是一个好习惯。

      相反,可以创建一个 POCO 选项类:

      public class DbOptions
      {
          public string ConnectionString { get; set }
      }
      

      并使用 config.json 中的部分将其填充到 ConfigureServices 方法中:

      services.Configure<DbOptions>(Configuration.GetConfigurationSection("Data:DefaultConnection"));
      

      然后您可以将其注入您的DbContext(以及控制器等):

      public sealed class Context : IdentityDbContext<IdentityUser>
      {
          private readonly DbOptions _options;
      
          public DbSet<Client> Clients { get; set; }
      
          public Context(IOptions<DbOptions> optionsAccessor)
          {
              // store the injected options
              _options = optionsAccessor.Options;
          }
      
          // other code..
      }
      

      【讨论】:

      • 谢谢。这是我刚刚发现的一篇非常好的文章:weblog.west-wind.com/posts/2015/Jun/03/…
      • 一个缺点:我使用的是 BaseApiController 实例化和处理上下文,并且所有控制器都继承自该上下文。现在我不能使用那个模式,因为 BaseApiController 需要一个无参数的构造函数。你知道如何解决这个问题吗?
      • 这基本上是我解释的。不过,该帖子中使用的Configuration 类有点过时了。您现在必须使用ConfigurationBuilder 并致电Build
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-16
      • 1970-01-01
      • 2015-07-27
      • 2016-02-17
      • 1970-01-01
      相关资源
      最近更新 更多