为了账号安全,请及时绑定邮箱和手机立即绑定

ASP.NET Core 2.0 入门教程

标签:
.NET

创建ASP.NET Core 工程

ASP.NET Core 工程可以通过Visual Studio模板或.NET Core 命令行接口(.NET CLI)创建。Visual Studio 2017有极好的 .NET Core 开发体验(包括顶级的代码调试、Docker集成以及其他功能),但是在这里,我将使用.NET Core命令行和Visual Studio Code,以防有些读者使用Mac或Linux的开发机。

dotnet new 命令用来创建新的.NET Core工程。当运行 dotnet new 而不加参数,命令行会列出可以使用的工程模板,如图1所示。如果你熟悉2.0版本之前的.NET CLI,你将会注意到2.0加入了一些新的工程模板。

webp

图1 新工程模板

Angular和React.js SPA模板: 将创建一个ASP.NET Core 的应用程序,为前端的SPA程序(使用Angular 4 或 React.js)提供服务。这些模板包括前端和后端的程序,以及用于构建前端的Webpack的配置。

ASP.NET Core Web App (Razor Pages): Razor页面是ASP.NET Core 2.0的一个新特性,它能够创建直接处理请求的页面,而不需要Controller。它非常适合基于页面的程序模板。

让我们用 dotnet new razor 命令创建一个Razor页面的工程。当这个工程被创建后,你可以执行 dotnet run 命令运行它。在.NET Core 之前的版本,需要执行先 dotnet restore 命令来安装必须的NuGet包。但是从.NET Core 2.0 开始,使用CLI命令时,restore命令会自动执行。运行这个站点并输入app的URL地址(如: http://localhost:5000 ),你将看到这个web app(图2)。

webp

图2 一个简单的ASP.NET Core App

恭喜你完成了第一个ASP.NET Core 2.0 的一个App!现在你运行了一个简单的web app,让我们看一看这个工程的内容,以便你更了解ASP.NET Core是怎样工作的。

依赖,源文件和资源

第一个要看的是工程文件本身----.csproj文件。这个文件告诉MSBuild怎样构建这个工程,依赖的包,.NET Core 的目标版本等等。如果你看过以前版本的.csproj文件,你会发现2.0版本的这个文件非常小。社区做了很多的努力,使得.csproj文件简短且已读。一个显著的改变是,源文件不在显示的被列在工程文件中。取而代之的是.NET Core 会自动编译所有.cs文件。同样,任何.resx文件都作为资源而被包含。如果你不希望所有的.cs文件都被编译,您可以从Compile ItemGroup中删除它们,也可以通过将EnableDefaultCompileItems属性设置为false来完全禁用默认编译项。

app运行的 .NET 版本由 <TargetFramework> 元素指定。这里为了使用ASP.NET Core 2.0的新特性,设置为了netcoreapp2.0。

.csproj文件中的 <PackageReference> 元素表示工程中依赖的NuGet包。在ASP.NET Core 2.0 中,你会注意到它默认只包含了一个数据(Microsoft.AspNetCore.All)。这个package包含了所有其它的Microsoft.AspNetCore的包,这样使得ASP.NET Core 2.0 的工程文件比起之前的短小了很多。其它的NuGet依赖包可以通过Visual Studio NuGet Package插件的管理界面或者.NET CLI 中 dotnet add 命令添加<PackageReference>元素。

如果你使用了SPA模板(angular,react或reactredux),还会在.csproj文件中定义标签以确保在构建工程的时候同时运行Webpack。

创建和运行Web Host

Program.cs 是整个程序的入口点。ASP.NET Core 的应用是一个console application,像所有的控制台应用一样,当app运行时,会运行Main方法。

在ASP.NET Core 2.0模板中,Main方法相当简单,就是创建了一个IWebHost对象,然后调用了Run方法。

public class Program{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

如果你以前使用过1.0版本,你会注意到现在这个文件更简单了。原因是WebHost.CreateDefaultBuilder这个新方法。以前,ASP.NET Core 应用程序的Main方法为了创建IWebHost的实例需要配置 WebHostBuilder,这个配置包含了一些步骤,像指定web server,设置content root路径,以及运行IIS集成等。

CreateDefaultBuilder创建了一个默认配置的IWebHost,以简化以上的步骤。除了前面指定的项,CreateDefaultBuilder还做了一些在以前版本中Startup.cs类中设置的事(设置配置信息,注册默认的logging providers)。因为ASP.NET Core是开源的,如果你感兴趣,你可以在GitHub WebHost.cs上看到CreateDefaultBuilder做的所有细节。

让我们简要的看一看在CreateDefaultBuilder中重要的调用以及其目的。虽然CreateDefaultBuilder已经为你做了所有的工作,但是理解幕后发生了什么总是好的。

public static IWebHostBuilder CreateDefaultBuilder(string[] args)
{    var builder = new WebHostBuilder()
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .ConfigureAppConfiguration((hostingContext, config) =>
        {            var env = hostingContext.HostingEnvironment;
            config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                  .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional:true, reloadOnChange: true);            if (env.IsDevelopment())
            {                var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));                if (appAssembly != null)
                {
                    config.AddUserSecrets(appAssembly, optional: true);
                }
            }
            config.AddEnvironmentVariables();            if (args != null)
            {
                config.AddCommandLine(args);
            }
        })
        .ConfigureLogging((hostingContext, logging) =>
        {
            logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
            logging.AddConsole();
            logging.AddDebug();
        })
        .UseIISIntegration()
        .UseDefaultServiceProvider((context, options) =>
        {
            options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
        });    return builder;
}

UserKestrel() 方法指定你的程序将使用Kestrel作为web server(基于libuv,跨平台),在web server上还有其他选项,如HttpSys(UseHttpSys),HttpSys只支持windows,但是有允许Windows身份认证的优点,可以安全的直接暴露在Internet上。而Kestrel需要放在像IIS,Nginx或Apache这些反向代理后面接收请求。

UseContentRoot()方法指定了应用程序的根目录,ASP.NET Core 能够找到整个站点的内容,比如config文件。需要注意的是这个根目录不是Web root(静态文件存放的地方),虽然默认的Web root 是基于内容根目录的([ContentRoot]/wwwroot)。

ConfigureAppConfiguration方法创建了configuration对象,应用程序在运行时通过它来读取配置。在CreateDefaultBuilder方法中,它将读取appsetting.json,appsetting.[environment].json,环境变量以及命令行参数中的配置,如果是开发环境,它还将使用user secrets。这个方法在ASP.NET Core 2.0 是新增的,我们将在后续讨论更多的细节。

ConfigureLogging 设置应用程序的日志。在CreateDefaultBuilder中,添加了控制台日志和debug日志。像ConfigureAppConfiguration一样,这个方法也是ASP.NET Core 2.0中新加的,我们将稍后讨论。

UseIISIntegration 配置了应用程序运行在IIS中。注意,UseKestrel依然是需要的。IIS作为反向代理而Kestrel作为宿主。如果app没有运行在IIS后,UseIISIntegration方法也不会产生负面影响,所以即使app运行在非IIS的场景下,这个调用也是安全的。

多数情况下,CreateDefaultBuilder提供的默认配置是足够的。如果需要默认配置以外的配置,可以在app的启动类中指定。调用UseStartup<T>方法时,T就是启动类。

如果CreateDefaultBuilder没有满足你的场景的需求,你可以自定义的创建IWebHost。如果你只需要小的改动,你可以修改调用CreateDefaultBuilder方法返回的WebHostBuilder(如,再次调用ConfigureAppConfiguration,添加更多的配置源)。如果你需要做大量的修改,你可以跳过CreateDefaultBuilder方法,像ASP.NET Core 1.0 或 1.1那样,构造你自己的WebHostBuilder。即使你这样做,你仍然可以使用ConfigureAppConfiguration和ConfigurLogging方法的优点。Web Host配置更多的细节可以在这里获取Web 主机

ASP.NET Core 环境

CreateDefaultBuilder的几个操作依赖于ASP.NET Core运行的环境,环境(Environment)在2.0中不是新的概念,但是还是值得简要的回顾一下,因为它会频繁的出现。

在ASP.NET Core中,app运行的环境被指定为ASPNETCORE_ENVIRONMENT变量。你可以设置任何你喜欢的值,但是Development,Staging和Production是典型的值。所以,在调用 dotnet run 命令之前设置了 ASPNETCORE_ENVIRONMENT变量的值为Development(或者,你在launchSettings.json文件中设置了environment变量值),你的app将运行在Development模式下(如果用Production代替了Development,默认将没有变量集)。有多个ASP.NET Core的功能通过使用这个变量来修改运行时的行为(比如Configuration和Logging),你也可以在你自己的代码中通过IHostingEnvironment服务来访问这个值。更多的信息可以在ASP.NET Core 文档中获取。

ASP.NET Core 配置

ASP.NET Core使用Microsoft.Extensions.Configuration包的IConfiguration接口提供运行时的配置。前面已提到,CreateDefaultBuilder将会从.json文件和环境变量中读取设置。配置系统是可扩展的,虽然它能够从各种提供者(json,xml,ini,environment...)中读取配置信息。

当使用IConfiguration和IConfigurationBuilder对象添加配置时,记住配置的顺序很重要。后面的配置的设置会覆盖前面的,所以你要先添加公共基础的配置,然后在添加特定环境的配置,这样后者才可能覆盖前者。

配置设置在ASP.NET Core 中是分层级的。当你创建新项目时,比如,appsetting.json包含了顶层的Logging元素,其下有子设置项。这些设置表示消息日志的最低优先级(LoggingLevel项),以及当消息来时是否在app的逻辑范围从而被记录(变量IncludeScopes)。要获取这些嵌套设置,你可以使用IConfiguration.GetSection()方法获取单个的配置节,或者指定特定配置的使用冒号做分隔符的全路径。所以,IncludeScopes在项目中的值可以这样获取:Configuration["Logging:IncludeScopes"]

//ASP.NET Core 的配置文件appsetting.json
{  "Logging": {    "IncludeScopes": false,    "Debug": {      "LogLevel": {        "Default": "Warning"
      }
    },    "Console": {      "LogLevel": {        "Default": "Warning"
      }
    }
  }
}

使用环境变量定义配置设置时,环境变量的名字需要包含所有层级,可以使用冒号(:)或双下划线(__)来分隔。比如,命名为Logging__IncludeScopes的环境变量将覆盖上面appsetting.json中IncludeScopes的设置,前提是,环境变量在appsetting后添加,CreateDefaultBuilder就是这样设计的,config.AddEnvironmentVariables();config.AddJsonFile()后添加。

因为 WebHost.CreateDefaultBuilder从appsetting.json和app.{environment}.json文件中读取配置,你会注意到当你改变环境时,日志的行为也改变了(appsettings.Development.json覆盖了appsettings.json中LogLevel的配置)。当设置了环境变量为Development,在调用dotnet run 后,你会注意到控制台记录了很多的日志(对调试有好处),而如果你设置了环境为Production,那么除了警告和错误信息,你看不到任何的日志(这样做是因为在生产环境下,应该尽可能少的记录日志)。

如果你有过ASP.NET Core 1.0和1.1的经验。你会注意到ConfigureAppConfiguration方法是2.0新增的。以前,常用的做法是在创建启动类时创建IConfiguration。使用ConfigureAppConfiguration方法来替代以前的做法是非常好的,因为他将IConfiguration对象存储在了app的DI容器中,以方便以后获取,以及在app的生命周期中提前了变量设置。

ASP.NET Core 日志

与装载配置一样,如果你熟悉以前的版本,你会记得日志装载也在Startup中,在2.0中,日志装载在IWebHost的ConfigureLogging方法中完成。

它仍然可以在Startup中装载(在Startup.ConfigureServices方法中使用services.Add-Logging),但是,在Web Host创建时配置日志,简化了Startup类,甚至可以在应用程序启动过程中更早地进行日志记录。

与配置一样,ASP.NET Core日志记录也可以扩展。注册不同的配置以记录到不同的终端。很多配置都及时有效的使用Microsoft.AspNetCore.All库。

从WebHost.CreateDefaultBuilder的源代码可以看出,在ILoggingBuilder上调用指定的提供者扩展方法可以添加日志提供者(如AddDebug或AddConsole)。如果你使用了WebHost.CreateDefaultBuilder,但是还想注册其他的日志提供者,可以在CreateDefaultBuilder返回的IWebHostBuilder上调用ConfigureLogging方法。

一旦提供者已被注册和日志已被配置。ASP.NET Core会自动记录传入的请求消息,你也可以从DI容器中获取ILogger对象,调用ILogger.Log()方法,记录自己的消息。

启动类型

现在你看到了Program.cs 是怎样创建Web host的,现在让我们跳到Startup.cs文件中。app将要使用的startup,是在创建IWebHost时调用StartUp方法是指定的。ASP.NET Core 2.0中Startup.cs没有太多的改变(除了将logging和configuration移动到Program.cs文件中实现),但是我将简要的回顾一下Startup类中两个重要的方法,因为它们对ASP.NET Core应用程序非常重要。

Startup类的ConfigureServices方法通过依赖注入将服务添加到app的DI容器中,所有的ASP.NET Core的应用都有默认的DI容器去存储服务,方面后面使用。DI容器使得服务变得可用,你已经看过了一对例子,ConfigureAppConfiguration和ConfigureLogging将在你的app中添加服务到容器,以方便后续使用。在运行时,如果一个这样的类型的实例被调用,ASP.NET Core 将自动从DI容器中获取对应的对象。

举个例,ASP.NET Core 2.0 程序的Startup类有一个构造函数,他有一个IConfiguration参数,当IWebHost开始运行时,这个构造函数将会自动被调用。这时,ASP.NET Core 将会从DI容器中提供IConfiguration参数给构造函数。

另一个例子,如果你想从Razor页面记录消息,你可以在页面模型的构造函数中将logger对象作为参数向App请求(像Startup请求IConfiguration对象一样),或者在cshtml中使用@inject语法,如下:

@using Microsoft.Extensions.Logging@inject ILogger<Index_Page> logger@functions {  public void OnGet()
    {
      logger.LogInformation("Beginning GET");
    }
}

同样可以来获取IConfiguration对象或任何其他已注册的类型。用DI容器这种方法,可使Startup类,Razor页面,controller等与所依赖的服务解耦。

在这节开始提到,在Startup.ConfigureServices方法中,服务被添加到DI容器。你使用程序模块创建app时,已经有一个服务在ConfigureServices方法中被注册了:services.AddMvc。就像你猜的一样,这个注册的服务需要MVC框架。

另一个常见的服务是Entity Framework Core,尽管他不会再本例中使用,使用Entity Framework Core 的应用程序通常使用services.AddDbContext()方法,注册所需的DBContexts,以保证他们使用Entity Framework模型。

More details on dependency injection in ASP.NET Core are available at bit.ly/2w7XtJI.
你也可以使用services.AddTransient(),services.AddScoped() 或 services.Add­Singleton()方法注册你自己的类型和服务。注册singleton将在每次请求时返回一个单列,注册一个transient将返回在每次请求的时候返回一个新的实例。注册scoped将在一个独立的http请求线程中返回一个单列,有关ASP.NET Core中依赖项注入的更多详细信息,请参见这里

http请求--处理管道和中间件

Startup类中另一个重要的方法是Configure。这是ASP.NET Core应用程序的心脏,http请求管道在这里被装载。在这个方法中不同的中间件被注册,这些中间件将处理http请求,并生成响应。

在Startup.Configure方法中,中间件被添加到IApplicationBuilder中形成处理管道。当请求进入时,第一注册的中间件被调用,这个中间件将执行它的逻辑,然后调用下一个中间件,如果它完成了它的处理逻辑,将返回上一个中间件。在图4中示出了在请求到达之后按顺序调用中间件组件的模式,然后在处理之后以相反的顺序调用中间件组件。

webp

图4 ASP.NET Core 中间件处理管道

举一个具体的例子,图5显示了模板工程的Configure方法,当新请求进来时,它将首先访问DeveloperExceptionPage中间件或ExceptionHandler中间件,这取决你的ASPNETCORE_ENVIRONMENT的环境变量。这些中间件最初不会做过多的操作,但是在后续的中间调用并退出中间件管道后,他们将关注异常的处理。

//图5 ASP.NET Core Startup.Configure 方法装载中间件管道public void Configure(IApplicationBuilder app, IHostingEnvironment env){  if (env.IsDevelopment())
  {
    app.UseDeveloperExceptionPage();
  }  else
  {
    app.UseExceptionHandler("/Error");
  }

  app.UseStaticFiles();

  app.UseMvc(routes =>
  {
    routes.MapRoute(
      name: "default",      template: "{controller=Home}/{action=Index}/{id?}");
  });
}

接下来,StaticFiles中间件将会被调用,它可以为请求提供静态文件(图片或样式等)。如果他执行了,他将停止管道并返回上一个中间件(异常处理中间件)。如果StaticFiles中间件不能提供响应,他将调用下一个中间件--MVC中间件,MVC中间件会尝试路由这个请求到MVC控制器(或者Razor页面)。

中间件组件的注册顺序非常重要。如果UseStaticFiles位于UseMvc之后,应用程序将尝试在检查静态文件之前将所有请求路由到MVC控制器,这可能会导致明显的性能下降。如果异常处理中间件在管道后面出现,它将无法处理先前中间件组件中发生的异常。



作者:书上得来终觉浅
链接:https://www.jianshu.com/p/f61d509a32ff


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消