ASP.NET 5 - 使用配置设置
ASP.NET 5 - Using a Configuration Setting
我正在玩 ASP.NET 5. 我正在尝试了解新的配置模型。我读过几篇文章。但是,我仍然无法加载配置设置。我的 config.json
文件如下所示:
{
"App" : {
"Info" : {
"Version":"1.0.0",
"ReleaseDate":"03-15-2015"
}
}
}
我的 Startup.cs
文件如下所示:
public class Startup
{
public IConfiguration Configuration { get; private set; }
public Startup()
{
Configuration = new Configuration()
.AddJsonFile("config.json");
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseErrorPage();
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index" });
});
app.UseMvc();
app.UseWelcomePage();
}
}
在我的一个控制器中,我有以下内容
MyController.cs
using System;
using Microsoft.AspNet.Mvc;
namespace MyOrg.MyApp
{
public class MyController : Controller
{
[HttpGet()]
public ActionResult Index()
{
var version = Configuration.Get("App:Info:Version");
return new HttpStatusCodeResult(200);
}
}
}
当我启动应用程序时,我收到一条错误消息:
error CS0103: The name 'Configuration' does not exist in the current context
at Microsoft.Framework.Runtime.Roslyn.RoslynProjectReference.Load(IAssemblyLo
adContext loadContext)
at Microsoft.Framework.Runtime.Loader.ProjectAssemblyLoader.Load(String name,
IAssemblyLoadContext loadContext)
at Microsoft.Framework.Runtime.Loader.ProjectAssemblyLoader.Load(String name)
at kre.host.LoaderContainer.Load(String name)
at kre.hosting.RuntimeBootstrapper.<>c__DisplayClass6_0.<ExecuteAsync>b__4(As
semblyName assemblyName)
at kre.hosting.RuntimeBootstrapper.<>c__DisplayClass6_0.<ExecuteAsync>b__7(Ob
ject sender, ResolveEventArgs a)
at System.AppDomain.OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName)
我做错了什么?我觉得我已经遵循了我所看到的例子。然而,我可以弄清楚我做错了什么。
显然您想在 Startup
class 中访问 Configuration
属性。错误方法说它不知道 Configuration
是什么。所以你需要一个 using
语句或一个完全限定的名称。此外,您应该避免将事物命名为与框架中找到的事物相同的事物。你的 Startup
class 有一个 Configuration
属性,但它也尝试使用 Configuration
class from Microsoft.Framework.ConfigurationModel
。这有多令人困惑?
您在 Startup
中的 Configure()
方法需要 using
语句或完全限定名称,以便它知道 Configuration
class 是什么。
using Microsoft.Framework.ConfigurationModel; //at the top of your class
Configuration = new Configuration(); //later in the code, we can access without fully qualifying name
或
Configuration = new Microsoft.Framework.ConfigurationModel.Configuration();
在您的控制器中,您可能有类似的问题。将下面示例中的 MyOrg.MyApp.Startup
替换为您的 Startup
class.
的命名空间
using MyOrg.MyApp.Startup //at the top of your class
Startup.Configuration.Get("App:Info:Version"); //later in the code, we can access without fully qualifying name
或
MyOrg.MyApp.Startup.Startup.Configuration.Get("App:Info:Version");
更好的做事方式
这应该足以让您入门。但是,访问 Startup
class 来检索您的配置并不理想,因为现在您的控制器的操作方法取决于 Startup class 在那里。这不是非常可单元测试的。理想情况下,您的控制器应该相互隔离。您应该定义某种接口来保存您想要的配置信息,然后让控制器依赖于该接口。当您在您的站点中时,您将使用特定于该站点配置的 class 进行响应。进行单元测试时,您可以通过使用不同的 class.
来严格控制测试值
interface ISiteConfig
{
string Version {get; set;}
DateTime ReleaseDate {get; set;}
}
public class SiteConfig : ISiteConfig
{
public string Version {get; set;}
public DateTime ReleaseDate {get; set;}
public SiteConfig()
{
var c = new Configuration()
.AddJsonFile("config.json");
Version = c.Get("App:Info:Version");
ReleaseDate = c.Get("App:Info:ReleaseDate"); //may need to parse here
}
}
public class TestConfig : ISiteConfig
{
public string Version {get; set;}
public DateTime ReleaseDate {get; set;}
public TestConfig(string version, DateTime releaseDate)
{
Version = version;
ReleaseDate = releaseDate;
}
}
然后您将使用 Dependency Injection 将您的配置实例注入控制器。
public class MyController : Controller
{
private readonly ISiteConfig Config;
public MyController(ISiteConfig config)
{
Config = config;
}
[HttpGet()]
public HttpStatusCodeResult Index()
{
var version = Config.Version;
return new HttpStatusCodeResult(200);
}
}
public class Startup
{
public void Configure(IBuilder app)
{
...
app.UseServices(services =>
{
...
// Set up the dependencies
services.AddTransient<ISiteConfig, SiteConfig>();
...
});
...
}
}
现在您可以更轻松地对您的操作方法进行单元测试,因为您的单元测试可以使用 TestConfig
class,而站点可以使用 SiteConfig
class。而且,如果您想更改配置的完成方式,则不必在一堆不同的地方替换字符串。您将有一个 class 这样做,其余的都是强类型的并且很容易更改而不会破坏您的应用程序。
您的单元测试可能如下所示:
//Arrange
var testConfig = new TestConfig("1.0", DateTime.Now );
var controller = new MyController(testConfig );
//Act
var response = controller.Index();
//Assert
Assert.AreEqual(200, response.StatusCode);
从 Beta 5 开始,接受的答案不再正确。 IConfiguration 上不再有 Get 方法。另外构造配置对象的方式也改变了。
以下代码适用于 Beta 7:
// showing using statements here since this is new from Beta 5
using Microsoft.Dnx.Runtime; // renamed was Microsoft.Framework.Runtime
using Microsoft.Framework.Configuration; // renamed was Microsoft.Framework.ConfigurationModel
// other using statements here
// Startup constructor. Note: now takes IApplicationEnvironment
// this is required in order to get base path
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
// Setup configuration sources.
var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
.AddJsonFile("config.json")
.AddJsonFile("dbconfig.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
// property to hold configuration object created in constructor
public IConfiguration Configuration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
// this will bind to an IOptions<AppSettings> instance
// where AppSettings is a class you define that has a set of
// properties that match your configuration section loaded from the
// json file
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
// here I am loading a connection string from a json file and passing into an
// new EF 6.x DB Context class
services.AddInstance<TalentAgencyContainer>(new TalentAgencyContainer(Configuration["ConnectionStrings:TalentAgencyContainer"]));
// Add MVC services to the services container.
services.AddMvc();
}
我正在玩 ASP.NET 5. 我正在尝试了解新的配置模型。我读过几篇文章。但是,我仍然无法加载配置设置。我的 config.json
文件如下所示:
{
"App" : {
"Info" : {
"Version":"1.0.0",
"ReleaseDate":"03-15-2015"
}
}
}
我的 Startup.cs
文件如下所示:
public class Startup
{
public IConfiguration Configuration { get; private set; }
public Startup()
{
Configuration = new Configuration()
.AddJsonFile("config.json");
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseErrorPage();
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index" });
});
app.UseMvc();
app.UseWelcomePage();
}
}
在我的一个控制器中,我有以下内容
MyController.cs
using System;
using Microsoft.AspNet.Mvc;
namespace MyOrg.MyApp
{
public class MyController : Controller
{
[HttpGet()]
public ActionResult Index()
{
var version = Configuration.Get("App:Info:Version");
return new HttpStatusCodeResult(200);
}
}
}
当我启动应用程序时,我收到一条错误消息:
error CS0103: The name 'Configuration' does not exist in the current context
at Microsoft.Framework.Runtime.Roslyn.RoslynProjectReference.Load(IAssemblyLo
adContext loadContext)
at Microsoft.Framework.Runtime.Loader.ProjectAssemblyLoader.Load(String name,
IAssemblyLoadContext loadContext)
at Microsoft.Framework.Runtime.Loader.ProjectAssemblyLoader.Load(String name)
at kre.host.LoaderContainer.Load(String name)
at kre.hosting.RuntimeBootstrapper.<>c__DisplayClass6_0.<ExecuteAsync>b__4(As
semblyName assemblyName)
at kre.hosting.RuntimeBootstrapper.<>c__DisplayClass6_0.<ExecuteAsync>b__7(Ob
ject sender, ResolveEventArgs a)
at System.AppDomain.OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName)
我做错了什么?我觉得我已经遵循了我所看到的例子。然而,我可以弄清楚我做错了什么。
显然您想在 Startup
class 中访问 Configuration
属性。错误方法说它不知道 Configuration
是什么。所以你需要一个 using
语句或一个完全限定的名称。此外,您应该避免将事物命名为与框架中找到的事物相同的事物。你的 Startup
class 有一个 Configuration
属性,但它也尝试使用 Configuration
class from Microsoft.Framework.ConfigurationModel
。这有多令人困惑?
您在 Startup
中的 Configure()
方法需要 using
语句或完全限定名称,以便它知道 Configuration
class 是什么。
using Microsoft.Framework.ConfigurationModel; //at the top of your class
Configuration = new Configuration(); //later in the code, we can access without fully qualifying name
或
Configuration = new Microsoft.Framework.ConfigurationModel.Configuration();
在您的控制器中,您可能有类似的问题。将下面示例中的 MyOrg.MyApp.Startup
替换为您的 Startup
class.
using MyOrg.MyApp.Startup //at the top of your class
Startup.Configuration.Get("App:Info:Version"); //later in the code, we can access without fully qualifying name
或
MyOrg.MyApp.Startup.Startup.Configuration.Get("App:Info:Version");
更好的做事方式
这应该足以让您入门。但是,访问 Startup
class 来检索您的配置并不理想,因为现在您的控制器的操作方法取决于 Startup class 在那里。这不是非常可单元测试的。理想情况下,您的控制器应该相互隔离。您应该定义某种接口来保存您想要的配置信息,然后让控制器依赖于该接口。当您在您的站点中时,您将使用特定于该站点配置的 class 进行响应。进行单元测试时,您可以通过使用不同的 class.
interface ISiteConfig
{
string Version {get; set;}
DateTime ReleaseDate {get; set;}
}
public class SiteConfig : ISiteConfig
{
public string Version {get; set;}
public DateTime ReleaseDate {get; set;}
public SiteConfig()
{
var c = new Configuration()
.AddJsonFile("config.json");
Version = c.Get("App:Info:Version");
ReleaseDate = c.Get("App:Info:ReleaseDate"); //may need to parse here
}
}
public class TestConfig : ISiteConfig
{
public string Version {get; set;}
public DateTime ReleaseDate {get; set;}
public TestConfig(string version, DateTime releaseDate)
{
Version = version;
ReleaseDate = releaseDate;
}
}
然后您将使用 Dependency Injection 将您的配置实例注入控制器。
public class MyController : Controller
{
private readonly ISiteConfig Config;
public MyController(ISiteConfig config)
{
Config = config;
}
[HttpGet()]
public HttpStatusCodeResult Index()
{
var version = Config.Version;
return new HttpStatusCodeResult(200);
}
}
public class Startup
{
public void Configure(IBuilder app)
{
...
app.UseServices(services =>
{
...
// Set up the dependencies
services.AddTransient<ISiteConfig, SiteConfig>();
...
});
...
}
}
现在您可以更轻松地对您的操作方法进行单元测试,因为您的单元测试可以使用 TestConfig
class,而站点可以使用 SiteConfig
class。而且,如果您想更改配置的完成方式,则不必在一堆不同的地方替换字符串。您将有一个 class 这样做,其余的都是强类型的并且很容易更改而不会破坏您的应用程序。
您的单元测试可能如下所示:
//Arrange
var testConfig = new TestConfig("1.0", DateTime.Now );
var controller = new MyController(testConfig );
//Act
var response = controller.Index();
//Assert
Assert.AreEqual(200, response.StatusCode);
从 Beta 5 开始,接受的答案不再正确。 IConfiguration 上不再有 Get 方法。另外构造配置对象的方式也改变了。
以下代码适用于 Beta 7:
// showing using statements here since this is new from Beta 5
using Microsoft.Dnx.Runtime; // renamed was Microsoft.Framework.Runtime
using Microsoft.Framework.Configuration; // renamed was Microsoft.Framework.ConfigurationModel
// other using statements here
// Startup constructor. Note: now takes IApplicationEnvironment
// this is required in order to get base path
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
// Setup configuration sources.
var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
.AddJsonFile("config.json")
.AddJsonFile("dbconfig.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
// property to hold configuration object created in constructor
public IConfiguration Configuration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
// this will bind to an IOptions<AppSettings> instance
// where AppSettings is a class you define that has a set of
// properties that match your configuration section loaded from the
// json file
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
// here I am loading a connection string from a json file and passing into an
// new EF 6.x DB Context class
services.AddInstance<TalentAgencyContainer>(new TalentAgencyContainer(Configuration["ConnectionStrings:TalentAgencyContainer"]));
// Add MVC services to the services container.
services.AddMvc();
}