我正在查看github上的.net核心2.0代码,以便在文章中对某些代码进行取消混淆并遇到this:
public static IMvcBuilder AddRazorPagesOptions(
this IMvcBuilder builder,
Action<RazorPagesOptions> setupAction)
{ }
经过审核,似乎没有明确地实例化RazorPagesOptions
类型的对象。我遇到的问题是RazorPageOptions
类型的对象是如何实例化的?
答案 0 :(得分:3)
这与依赖注入模式的ASP.NET Core实现有关。 Daisy在评论中指出的确切表明:
builder.Services.Configure(setupAction)
builder
是IMvcBuilder
。 builder.Services
是IServiceCollection
,也就是说,设置为在asp-net应用程序中可用的所有服务的主列表。在Startup.cs中设置了FoobarService?然后,IFoobarService的定义可能会位于ServiceCollection中。等
ServiceCollection附加了大量扩展方法,可以更轻松地添加新服务。它还有.BuildServiceProvider()
,它接受所有已注册的定义,并创建一个服务工厂/提供者/缓存/解析器/事物,您/ asp以后可以使用它来获取这些服务的实际实例。
然后,除了服务注册和建立工厂之外,由于“每个人都习惯”在Startup.cs中设置ServiceCollection成为焦点的东西这一事实,还有一个自定义配置进一步的细节,通过ServiceCollection或姐妹对象上的更多扩展方法,可能需要在Startup.cs中提供服务。
现在,ASP.NET Core MVC有一个用于处理应用程序配置的模块。它的设计是这样的,你定义一个类,通常称为WhateverOptions,它将包含与Whatever相关的配置的某些部分,并且可以通过任何服务稍后通过要求注入来检索它。但是,由于我们将配置拆分为许多或多或少的上下文对象,如果我们将它们全部实例化(在一个地方?)并填充它们(在一个地方?!),那将是一个巨大的混乱。为方便起见,所有这些都将由框架创建。剩下的问题是,谁将填写实际设置。
..这与你找到的很接近。这一行:
builder.Services.Configure(setupAction)
采取Action(带有1个参数的仿函数:Razor-Options)并将其注册到任何服务的大包中。它被注册为RazorPagesOptions的设置源。作为副作用,IoC容器还了解到某些服务可能需要RazorPagesOptions
。
稍后,在运行时,当有人要求提供服务实例时,如果服务需要RazorPagesOptions
,则容器会检查它是否已准备好。如果没有,则创建那些RazorPagesOptions
的实例(可能是单例模式),但当然它最初是空的。然后,它将通过所有已注册的设置源。依次调用每个这样的源,每个源都获取RazorPagesOptions实例,并且每个源都有机会用它们的部分设置填充它。最后,当所有的都运行时,RazorPagesOptions的实例(可能是缓存然后......)被传递给需要它的服务。
我还没有说过的一件事是Action<RazorPagesOptions>
的实例来自哪里。它可能来自Startup.cs。在那里你有一条类似于:
services
.AddMvc() // registers MVC services in IoCC and gets you the IMvcBuilder
.AddRazorPagesOptions(options =>
{
options.RootDirectory = "....";
options.Conventions.Add(new FooConvention....);
...
});
此options => {..}
是Action<RazorPagesOptions>
,将传递给AddRazorPagesOptions,然后传递给serviceCollection.Configure
,并将其注册为RazorPagesOptions的实际设置源。< / p>
外卖:
new RazorPagesOptions()