引言

在这篇博客中我将探索一些关于asp.net core 3.0应用的基础功能——.csproj 项目文件和program源文件。我将会描述他们从asp.net core 2.x在默认模版中是怎样改变的,以及探讨aspnetcore3.0使用的api的变化。
***

介绍

.net core 3.0 会在九月23号的 net conf上发布,但现在已经有一个支持的预览版本(preview 8)。最新的预览版本与最终发布版本不可能有太多的变化,所以现在是开始尝试和查看3.0增加的功能的好时机。

net core 3.0主要的更新是把windows桌面应用运行了net core 上,但是asp net core 也增加了很多东西。也许最大的新特性就是服务端blazor(我个人最感兴趣的是客户端的版本,但是现在还不可用),但是也有一些迭代的改变和新特性加入了asp net core。

在这篇博客中,我将探索一些关于非常 “基础” 的更新。

  • microsoft.aspnetcore.app metapackage在nuget已经不再可用
  • asp net core 已经选择 gnerichost 来取代 webhost

如果你打算把asp net core 2.x 软件迁移到3.0 ,一定要查阅

在这篇博客中,当你创建一个新的asp net core应用时,比如 你用dotnet new webapi,我将探索.csproj 文件和program.cs文件。在文章的最后,我将比较startup文件相对于2.x版本是怎样变化的,以及asp net core 中使用中的模版有什么不同(比如 web,webapi,mvc)
***

新项目文件与共享框架的变化

当你创建完一个新的asp net core项目,然后打开.csproj文件,它基本上是如下的样子:

<project sdk="microsoft.net.sdk.web">

  <propertygroup>
    <targetframework>netcoreapp3.0</targetframework>
  </propertygroup>

</project>

如果你与asp net core 2.x的项目文件做比较,主要有如下的相同点和不同点

  • <targetframework> 不再是netcoreapp2.1或者2.2 ,而是netcoreapp3.0了,这是因为我们把目标框架2.1/2.2 替换成了3.0
  • <project> 元素仍然是 microsoft.net.sdk.web,虽然已经更新成了asp.net core 3.0,但是你的项目文件中的语法仍然是没有变化
  • microsoft.aspnetcore.app meta 包已经不存在。

这里的最后一个有意思的变更。在我中提到,在asp net core2.x你引用一个名叫microsoft.aspnetcore.app的共享框架元数据包。这个共享框架提供了大量的好处,比如避免你在你的应用中手动安装所有的独立的程序包以及允许你使用 运行时的向前滚动更新的特性。

在asp net core3.0中,微软已经不再以nuget元数据包的形式发布这个共享框架,也不存在3.0.0版本的microsoft.aspnetcore.app。这个共享框架仍然和以前一样通过net core 安装,但是在3.0中你的使用略有不同。

在asp net core2.x 中,为了引用这个共享框架,你会添加如下代码到你的项目文件中:

<itemgroup>
  <packagereference include="microsoft.aspnetcore.app" />
</itemgroup>

相反,在3.0中你要使用 <frameworkreference> 元素

<itemgroup>
  <frameworkreference include="microsoft.aspnetcore.app" />
</itemgroup>

“但是停一下”,你说:“为什么我的asp net core 项目文件没有这个?”
这是个好问题,答案是 microsoft.net.sdk.web 默认包含了。
***

不再有用于共享框架组件的包

在3.0中另外一个最大的变更是你不再需要独立安装共享框架的其他部分的nuget程序包了。例如,在asp net core 2.x中,你可以用 像 microsoft.aspnetcore.authentication或microsoft.aspnetcore.authentication这样的独立的程序包来替换依赖于整个框架的程序包:

<itemgroup>
  <packagereference include="microsoft.aspnetcore.authentication" version="2.1.0"/>
  <packagereference include="microsoft.aspnetcore.identity" version="2.1.0"/>
</itemgroup>

这通常对库最有用,因为应用程序总是需要依赖于共享框架。然而,在 net core3.0中,这一切都不可能了。这些nuget包不会在发布了。相反,如果你需要在你的项目中引用其中的类库,你必须添加这个 <frameworkreference> 元素到你的项目中

例如ef core和social authentication providers 这些程序包中另外一个需要注意的事情是它们也不再是共享框架的一部分了,如果你需要使用这些程序包,你必须手动从nuget上安装到你的项目中。

对于这些程序包的完整清单,查阅这个github issue
***

program.cs 文件从 2.x到 3.0的变化

asp net core 3.0中的proram.cs文件第一眼看上去与2.x版本的非常相似。但是已经有许多类型发生了改变,这是因为在net core 3.0中,asp net core为了运行在通用host上已经进行了重新构建,使用独立的web host已经被替代。

public class program
{
    public static void main(string[] args)
    {
        createhostbuilder(args).build().run();
    }

    public static ihostbuilder createhostbuilder(string[] args) =>
        host.createdefaultbuilder(args)
            .configurewebhostdefaults(webbuilder =>
            {
                webbuilder.usestartup<startup>();
            });
}

通用host是从2.1版本被发布的,这是个非常好的想法,但是我发现关于它的,主要问题是它,值得庆幸的是,3.0中的这一变化应该可以解决这些问题。

很大程度上,这个变化产生的最终结果是和你过去使用的net core2.x版本基本相似,但是用于配置你的app的全部配置的方法webhost.createdefaultbuilder() 被替换成了两个逻辑步骤,这个两个独立的方法叫做:

  • host.createdefaultbuilder() ,负责配置你的app配置、日志以及依赖注入容器

  • ihostbuilder.configurewebhostdefaults() ,负责为经典的asp net core 应用添加所需要的所有东西,比如:配置kestrel和使用一个 startup.cs用于配置你的di容器和中间件管道

通用host builder

正如我之前说的那样,通用host为asp net core 3.0的构建提供了基础。它同样也提供了你先前在asp net core应用中使用的基础性的microsoft.extensions.* 元素,比如:日志、配置和依赖注入。

下面的代码是一个简化版本的 host.createdefaultbuilder() 方法。它和2.x版本的 webhost.createdefaultbuilder() 作用一样。但是我会简短说一下值得关注的变化。

public static ihostbuilder createdefaultbuilder(string[] args)
{
    var builder = new hostbuilder();

    builder.usecontentroot(directory.getcurrentdirectory());
    builder.configurehostconfiguration(config =>
    {
        // uses dotnet_ environment variables and command line args
    });

    builder.configureappconfiguration((hostingcontext, config) =>
    {
        // json files, user secrets, environment variables and command line arguments
    })
    .configurelogging((hostingcontext, logging) =>
    {
        // adds loggers for console, debug, event source, and eventlog (windows only)
    })
    .usedefaultserviceprovider((context, options) =>
    {
        // configures di provider validation
    });

    return builder;
}

简而言之,这个方法与2.x版本的不同点如下:

  • hosting配置使用以 dotnet_ 为前缀的环境变量
  • hosting配置使用命令行变量
  • 增加了 eventsourceloggereventloglogger 日志提供者
  • 可以选择使用serviceprovider验证功能
  • 没有关于web hosting 的特定配置

第一个有意思的地方就是host配置是如何设置的。对于web host而言,默认使用以 aspnetcore_ 为前缀的环境变量作为配置。所以设置aspnetcore_environment 环境变量将会设置 environment 配置的值。对于 通用host来说,这个前缀现在是dotnet_ ,和传给应用运行时的任意命令行参数。

这个host配置起的作用好比是决定你的应用运行在什么的主机环境,host配置与你应用配置(与ioptions接口一起使用的配置)是隔离开来的。

配置你的app设置的方法 configureappconfiguration() 与2.x相比是没有变化的,所以它仍然使用appsettings.json文件、appsetting.env.json风格文件、、环境变量以及命令行参数。

通用host的日志部分已经在3.0进行了扩展。它仍旧通过你的app配置来,以及添加控制台和debug日志提供者。然而它同样也添加来日志提供者,事件源日志用于和像windows上的etw、linux上的lttng这样的系统日志进行交互。另外,添加一个event log provider,只能在windows才会把日志信息写入windows event log。

最后,当你的app运行在开发环境时,通用host配置依赖注入容器的目的是它会验证范围(scopes),这个操作和2.x一样。这旨在抓取捕获的依赖关系的实例,在这些实例中,你将一个范围(scopes)的服务注入到单例服务中。在3.0中,通用host通用能启动 validateonbuild 的功能,我将会在下一篇博客中讲到。

通用host一个关键的点是他是通用的,它和asp net core 或者http 工作负载没有任何关联。你可以像经典的asp net core 应用一样把通用host作为你的控制台app或者其他长运行服务的基石。在3.0中你只需要在你的asp net core 层的顶部增加一个 configurewebhostdefaults() 就可以搞定。
***

用configurewebhostdefaults恢复asp net core功能

这篇博客已经很长了,所以在这里我不想深入挖掘太多的细节,但是,对于添加asp net core “层”到 通用host上面而言,configurewebhostdefaults扩展方法是非常有用的。就简单层面而言,调用这个方法会使kestrel web 服务添加到这个host上面,但是这里面也存在了大量的其他的改变。下面是关于这个方法提供,(包含了genericwebhostbuilder提供的特性)

  • 为host 配置添加了 aspnetcore_ 前缀的环境变量(除了 dotnet_ 前缀的变量和命令行参数)
  • 增加了 genericwebhostservice ,这是一个ihostedservice的实现,它通常运行在asp net core服务上,这是一个主要的特性,这个特性为asp net core 复用通用host提供了可能。
  • 增加了一个额外的app配置源,在razorui类库中,这个 staticwebassetsloader 与静态文件(css/js)共同发挥作用。
  • 使用默认kestrel配置(与2.x一样)
  • 增加 hostfilteringstartupfilter (和2.0一样)
  • 增加 forwardedheadersstartupfilter ,如果 forwardedheaders_enabled 配置值是true,例如,如果aspnetcore_forwardedheaders_enabled 环境变量的值是true。
  • 启动windows上的iis集成
  • 增加一个到di容器中

大部分东西是和asp net core2.x相同的,不同的地方是:app作为一个ihostservice运行的基础设施、端点路由和forwardedheadersstartupfilter ,其中端点路由在3.0是全局启用的(不再像2.x局限于mvc/razor页面了)

forwardedheadersstartupfilter 在1.0已经出现了,当你的app运行在代理后面会用到它,是为了确保你的应用能处理ssl-负载和生成正确的url。这么设计的目的是你能仅仅通过设置一个环境变量去配置一个使用 x-forwarded-forx-forwarded-proto 请求头的中间件。
***

总结

在这篇博客中我深挖了从asp net core2.x到3.0中的仅仅两个文件——.csproj文件和program.cs文件的变化。从表面上看,者仅仅是一些细微的变化,所有从2.x移植到3.0应该不会太难。这是天真地掩盖了其中的巨大的变化——共享框架的明显的变化,以及asp net core 已经在通用host上重建了。

我认为大家遇到的最大的问题是nuget 程序包的差异——一些app将要必须移除asp net core 程序包的引用,同时要明确地引用其他的程序包。尽管解决这个问题是不太难,但是它会对不熟悉这个变化的用户带来困惑,所以应该第一时间审查这些变化