创建新的 ASP.NET Core 2.0项目时,Program
类中的样板Main
方法如下所示:
public static void Main(string[] args)
{
BuildWebHost(args).Run(); // BuildWebHost returns an IWebHost
}
但从 C# 7.1 开始,Main
方法可以是返回Task
而不是void
的异步方法。这意味着在Main
中调用异步方法要容易得多。
因此,可以在Main
内部调用IWebHost
上的RunAsync()
,而不是Run()
方法。像这样:
public static async Task Main(string[] args)
{
await BuildWebHost(args).RunAsync().ConfigureAwait(false);
}
根据文档,Run
方法:
运行 Web 应用程序并阻止调用线程,直到主机关闭。
而RunAsync
方法:
运行 Web 应用程序并返回仅在触发令牌或触发关闭时完成的任务。
我想知道什么时候应该使用RunAsync
方法而不是常规Run
方法?这有什么实际意义?最终用户会注意到任何差异吗?
默认 ASP.NET 核心模板包含以下Main
方法:
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
Run
方法,WebHostExtensions.Run
扩展方法,其实现方式如下:
public static void Run(this IWebHost host)
{
host.RunAsync().GetAwaiter().GetResult();
}
所以这实际上调用了WebHostExtensions.RunAsync
,并且只是阻止它。
现在,让我们看一下如何指定 C# 7.1 的异步Main
方法:
当其中一个[这些基于任务的方法]被标识为入口点时,编译器将合成一个实际的入口点方法,该方法调用以下编码方法之一:
static Task Main()
将导致编译器发出等效的private static void $GeneratedMain() => Main().GetAwaiter().GetResult();
static Task Main(string[])
将导致编译器发出等效的private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();
所以基本上,有一个异步Main
方法,如下所示:
public static async Task Main(string[] args)
{
await BuildWebHost(args).RunAsync();
}
将导致编译器还发出以下内容:
private static void $GeneratedMain(string[] args)
{
Main(args).GetAwaiter().GetResult();
}
如果你仔细观察那里返回的任务会发生什么,这几乎与WebHostExtensions.Run
方法完全相同。
这是什么意思呢?您可以使用这些解决方案中的任何一种,效果将是相同的。应用程序将正确阻止,直到异步任务得到解决。解决方案之间没有实际区别。使用异步 main 方法的唯一真正好处是,如果您在Main
方法中有其他异步工作要做;尽管这种情况可能非常罕见,因为对于 Web 应用程序,您更有可能在 ASP.NET Core 应用程序的生命周期内(即在Startup
中而不是在它之外)进行设置工作。
实际意义?最终用户会注意到吗 有什么区别吗?
运行时级别行为没有区别。
由于此功能不对应于 CLR 代码更改,因此异步 主要方法只是一个语法糖。此设计允许后端 与该语言的先前版本的兼容性。阅读更多 有关详细信息,请参阅 Roslyn Git 存储库中的异步主。
- C# 7 系列,第 2 部分:异步主