ASP.NET Core应用基本编程模式[3]:配置多种使用形式

前面演示了针对Startup类型的构造函数注入,表示配置的IConfiguration对象是能够注入Startup类型构造函数中的两个服务对象之一。接下来我们采用Options模式来消费以环境变量形式提供的配置,如下所示的FoobarOptions是我们定义的Options类型。在注册的Startup类型中,可以直接在构造函数中注入IConfiguration服务,并在ConfigureServices方法中将其映射为FoobarOptions类型。在Configure方法中,可以通过注入的IOptions<FoobarOptions>服务得到通过配置绑定的FoobarOptions对象,并将其序列化成JSON字符串。在通过调用IApplicationBuilder的Run方法注册的中间件中,这个JSON字符串直接作为请求的响应内容。

class Program

{

    static void Main()

    {

        Environment.SetEnvironmentVariable("ASPNETCORE_FOOBAR:FOO", "Foo");

        Environment.SetEnvironmentVariable("ASPNETCORE_FOOBAR:BAR", "Bar");

        Environment.SetEnvironmentVariable("ASPNETCORE_Baz", "Baz");

        Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder => builder.UseStartup<Startup>())

            .Build()

            .Run();

    }

    public class Startup

    {

        private readonly IConfiguration _configuration; 

        public Startup(IConfiguration configuration)  => _configuration = configuration;

        public void ConfigureServices(IServiceCollection services) => services.Configure<FoobarOptions>(_configuration);

        public void Configure(IApplicationBuilder app, IOptions<FoobarOptions> optionsAccessor)

        {

            var options = optionsAccessor.Value;

            var json = JsonConvert.SerializeObject(options, Formatting.Indented);

            app.Run(async context =>

            {

                context.Response.ContentType = "text/html";               

                await context.Response.WriteAsync($"<pre>{json}</pre>");

            });

        }

    }

    public class FoobarOptions

    {

        public Foobar Foobar { get; set; }

        public string Baz { get; set; }

    }

    public class Foobar

    {

        public string Foo { get; set; }

        public string Bar { get; set; }

    }

}

为了能够提供绑定为FoobarOptions对象的原始配置,我们在Main方法中设置了3个对应的环境变量,这些环境变量具有相同的前缀“ASPNETCORE_”。应用程序启动之后,如果利用浏览器访问该应用,得到的输出结果如下图所示。

12

二、以键值对形式读取和修改配置

《配置[3]:配置模型总体设计》对配置模型进行了深入分析,由此可知,IConfiguration对象是以字典的结构来存储配置数据的,该接口定义的索引可供我们以键值对的形式来读取和修改配置数据。在ASP.NET Core应用中,我们可以通过调用定义在IWebHostBuilder接口的GetSetting方法和UseSetting方法达到相同的目的。

public interface IWebHostBuilder

{

    string GetSetting(string key);

    IWebHostBuilder UseSetting(string key, string value);

    ...

}

上面演示的实例采用环境变量来提供最终绑定为FoobarOptions对象的原始配置,这样的配置数据也可以通过如下所示的方式调用IWebHostBuilder接口的UseSetting方法来提供。修改后的应用程序启动之后,如果利用浏览器访问该应用,同样可以得到上图所示的输出结果。

class Program

{

    static void Main()

    {

        Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder => builder

            .UseSetting("Foobar:Foo", "Foo")

            .UseSetting("Foobar:Bar", "Bar")

            .UseSetting("Baz", "Baz")

            .UseStartup<Startup>())

        .Build()

        .Run();

    }

}

配置不仅仅供应用程序来使用,ASP.NET Core框架自身的很多特性也都可以通过配置进行定制。如果希望通过修改配置来控制ASP.NET Core框架的某些行为,就需要先知道对应的配置项的名称是什么。例如,ASP.NET Core应用的服务器默认使用launchSettings.json文件定义的监听地址,但是我们可以通过修改配置采用其他的监听地址。包括端口在内的监听地址是通过名称为urls的配置项来控制的,如果记不住这个配置项的名称,也可以直接使用定义在WebHostDefaults中对应的只读属性ServerUrlsKey,该静态类型中还提供了其他一些预定义的配置项名称,所以这也是一个比较重要的类型。

public static class WebHostDefaults

{

    public static readonly string ServerUrlsKey = "urls";

    ...

}

针对上面演示的这个实例,如果希望为服务器设置不同的监听地址,直接调用IWebHostBuilder接口的UseSetting方法将新的地址作为urls配置项的内容即可。既然配置项被命名为urls,就意味着服务器的监听地址不仅限于一个,如果希望设置多个监听地址,我们可以采用分号作为分隔符。

class Program

{

    static void Main()

    {

        Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder => builder

            .UseSetting("Foobar:Foo", "Foo")

            .UseSetting("Foobar:Bar", "Bar")

            .UseSetting("Baz", "Baz")

            .UseSetting("urls", "http://0.0.0.0:8888;http://0.0.0.0:9999")

            .UseStartup<Startup>())

        .Build()

        .Run();

    }

}

为了使实例程序采用不同的监听地址,可以采用如上所示的方式调用IWebHostBuilder接口的UseSetting方法设置两个针对8888和9999端口号的监听地址。由图11-13所示的程序启动后的输出结果可以看出,服务器确实采用我们指定的两个地址监听请求,通过浏览器针对这两个地址发送的请求能够得到相同的结果。

13

除了调用UseSetting方法设置urls配置项来修改服务器的监听地址,直接调用IWebHostBuilder接口的UseUrls扩展方法也可以达到相同的目的。另外,我们提供的监听地址只能包含主机名称/IP地址(Host/IP)和端口号,不能包含基础路径(PathBase)。如果我们提供“http://0.0.0.0/3721/foobar”这样一个URL,系统会抛出一个InvalidOperationException类型的异常。基础路径可以通过注册中间件的方式进行设置。

public static class HostingAbstractionsWebHostBuilderExtensions

{

    public static IWebHostBuilder UseUrls(this IWebHostBuilder hostBuilder, params string[] urls);

}

三、合并配置

在启动一个ASP.NET Core应用时,我们可以自行创建一个承载配置的IConfiguration对象,并通过调用IWebHostBuilder接口的UseConfiguration扩展方法将它与应用自身的配置进行合并。如果应用自身存在重复的配置项,那么该配置项的值会被指定的IConfiguration对象覆盖。

public static class HostingAbstractionsWebHostBuilderExtensions

{

  public static IWebHostBuilder UseConfiguration(this IWebHostBuilder hostBuilder, IConfiguration configuration);

}

如果前面演示的实例需要采用这种方式来提供配置,我们可以对程序代码做如下修改。如下面的代码片段所示,我们创建了一个ConfigurationBuilder对象,并通过调用AddInMemory

Collection扩展方法注册了一个MemoryConfigurationSource对象,它提供了绑定FoobarOptions对象所需的所有配置数据。我们最终利用ConfigurationBuilder创建出一个IConfiguration对象,并通过调用上述UseConfiguration方法将提供的配置数据合并到当前应用中。修改后的应用程序启动之后,如果利用浏览器访问该应用,同样会得到图11-12所示的输出结果。(S1115)

class Program

{

    static void Main()

    {

        var configuration = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string>

            {

                ["Foobar:Foo"] = "Foo",

                ["Foobar:Bar"] = "Bar",

                ["Baz"]    = "Baz"

            })

            .Build();

        Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder => builder

            .UseConfiguration(configuration)

            .UseStartup<Startup>())

        .Build()

        .Run();

    }

}

四、注册IConfigurationSource

配置系统最大的特点是可以注册不同的配置源。借助IWebHostBuilder接口的UseConfiguration扩展方法,虽然可以将利用配置系统提供的IConfiguration对象应用到ASP.NET Core程序中,但是这样的整合方式总显得不够彻底,更加理想的方式应该是可以直接在ASP.NET Core应用中注册IConfigurationSource对象。

针对IConfigurationSource的注册可以调用IWebHostBuilder接口的ConfigureAppConfiguration方法来完成,该方法与在IHostBuilder接口上定义的同名方法基本上是等效的。如下面的代码片段所示,这个方法的参数是一个类型为Action<WebHostBuilderContext, IConfigurationBuilder>的委托对象,这意味着我们可以就承载上下文对配置做针对性设置。如果设置与当前承载上下文无关,我们还可以调用ConfigureAppConfiguration方法重载,该方法的参数类型为Action<IConfigurationBuilder>。

public interface IWebHostBuilder

{

    IWebHostBuilder ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate);

}

public static class WebHostBuilderExtensions

{

    public static IWebHostBuilder ConfigureAppConfiguration(this IWebHostBuilder hostBuilder, Action<IConfigurationBuilder> configureDelegate);

}

对于上面演示的这个程序来说,如果将针对IWebHostBuilder接口的UseConfiguration方法的调用替换成如下所示的针对ConfigureAppConfiguration方法的调用,依然可以达到相同的目的。修改后的应用程序启动之后,如果利用浏览器访问该应用,同样会得到上图所示的输出结果。

class Program

{

    static void Main()

    {     

        Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder => builder.ConfigureAppConfiguration(config => config

                .AddInMemoryCollection(new Dictionary<string, string>

                {

                    ["Foobar:Foo"] = "Foo",

                    ["Foobar:Bar"] = "Bar",

                    ["Baz"] = "Baz"

                }))

            .UseStartup<Startup>())

        .Build()

        .Run();

    }

}

龙华大道1号 http://www.kinghill.cn/Dynamics/2106.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容