原文:https://andrewlock.net/ihostingenvironment-vs-ihost-environment-obsolete-types-in-net-core-3/

作者:Andrew Lock

译者:Lamond Lu

本篇是如何升级到ASP.NET Core 3.0系列文章的第二篇。

  • Part 1 - 将.NET Standard 2.0 类库转换为.NET Core 3.0 类库

  • Part 2 - IHostingEnvironment VS IHostEnvironment - .NET Core 3.0 中的废弃类型(本篇)[1]

  • Part 3 - 避免在 ASP.NET Core 3.0 启动时注入服务

  • Part 4 - 将终端中间件转换为 ASP.NET Core 3.0 中的节点路由

  • Part 5 - 将集成测试的转换为 NET Core 3.0

在本篇博客中,我将描述与之前版本相比,ASP.NET Core 3.0 中已经被标记为废弃的类型。我将解释一下为什么这些类型被废弃了,它们的替换类型是什么,以及你应该什么时候使用它们。


ASP.NET Core 与通用主机(Generic Host)合并

在 ASP.NET Core 2.1 中引入了新的通用主机(Generic Host), 它是借助Microsoft.Extension.*程序集来进行程序配置,依赖注入,以及日志记录来构建非 HTTP 应用的一种方式。虽然这是一个相当不错的点子,但是引入主机抽象在基础上与 ASP.NET Core 使用的 HTTP 主机不兼容。这导致了多种命名空间的冲突与不兼容,所以在 ASP.NET Core 2.x 版本中,我一直尽量不使用通用主机。

在 ASP.NET Core 3.0 中,开发人员作出了巨大的努力,将 Web 主机与通用主机兼容起来。ASP.NET Core 的 Web 主机现在可以作为IHostedService运行在通用主机中,重复抽象的问题(ASP.NET Core 中使用一套抽象,通用主机使用另一套抽象)得到了根本解决。

当然,这还不是全部。当你从 ASP.NET Core 2.x 升级到 3.0, ASP.NET Core 3.0 并不强迫你立即使用新的通用主机。如果你愿意,你可以继续使用旧的WebHostBuilder,而不使用新的HostBuilder。虽然在 ASP.NET Core 3.0 的官方文档[2]中一直暗示这是必须的,但是在当前的阶段,这是一个可选配置,如果你需要,可以继续使用 Web 主机,而不使用通用主机。

PS: 不过我还是建议你将可能将HostBuilder作为你未来的升级计划。我但是在未来的某个时间点WebHostBuilder将被移除,即使现在它还没有被标记为[Obsolete]

作为重构的通用主机的一部分,一些在之前版本中重复的类型被标记为废弃了,一些新的类型被引入了。在这些类型中,最好的例子就是IHostingEnvironment

IHostingEnvironment VS IHostEnvironment VS IWebHostEnviornment

IHostingEnvironment是.NET Core 2.x 中最让人讨厌的一个接口,因为它存在于两个命名空间中, Microsoft.AspNetCore.HostingMicrosoft.Extensions.Hosting.这两个接口有少许不同,且不兼容。

namespace Microsoft.AspNetCore.Hosting
{public interface IHostingEnvironment{string EnvironmentName { get; set; }string ApplicationName { get; set; }string WebRootPath { get; set; }IFileProvider WebRootFileProvider { get; set; }string ContentRootPath { get; set; }IFileProvider ContentRootFileProvider { get; set; }}
}namespace Microsoft.Extensions.Hosting
{public interface IHostingEnvironment{string EnvironmentName { get; set; }string ApplicationName { get; set; }string ContentRootPath { get; set; }IFileProvider ContentRootFileProvider { get; set; }}
}

之所以有两个同名接口是有历史原因的。AspNetCore版本的接口已经存在了很长时间了,在 ASP.NET Core 2.1 版本中,通用主机引入了Extensions版本。Extensions版本没有提供用于服务静态文件的wwwroot目录的概念(因为它承载的是非 HTTP 服务)。所以你可能已经注意到Extensions缺少了WebRootFileProviderWebRootPath两个属性。

出于向后兼容的原因,这里需要一个单独的抽象。但是,这种做法真正令人讨厌的后果之一是无法编写用于通用主机和 ASP.NET Core 的扩展方法。

在 ASP.NET Core 3.0 中,上述的两个接口都已经被标记为废弃了。你依然可以使用它们,但是在编译的时候,你会得到一些警告。相对的,两个新的接口被引入进来: IHostEnvironmentIWebHostEnvironment。虽然他们出现在不同的命名空间中,但是现在它们有了不同的名字,而且使用了继承关系。

namespace Microsoft.Extensions.Hosting
{public interface IHostEnvironment{string EnvironmentName { get; set; }string ApplicationName { get; set; }string ContentRootPath { get; set; }IFileProvider ContentRootFileProvider { get; set; }}
}namespace Microsoft.AspNetCore.Hosting
{public interface IWebHostEnvironment : IHostEnvironment{string WebRootPath { get; set; }IFileProvider WebRootFileProvider { get; set; }}
}

这个层次关系更容易理解了,避免了重复,并且意味着接收通用主机版本宿主环境抽象(IHostEnvironment)的方法现在也可以接收 web 版本(IWebHostEnvironment)的抽象了。在幕后,IHostEnvironmentIWebHostEnvironment的实现是相同的 - 除了旧接口,他们还实现了新接口。

例如,ASP.NET Core 的实现类如下:

namespace Microsoft.AspNetCore.Hosting
{internal class HostingEnvironment : IHostingEnvironment,Extensions.Hosting.IHostingEnvironment,IWebHostEnvironment{public string EnvironmentName { get; set; }= Extensions.Hosting.Environments.Production;public string ApplicationName { get; set; }public string WebRootPath { get; set; }public IFileProvider WebRootFileProvider { get; set; }public string ContentRootPath { get; set; }public IFileProvider ContentRootFileProvider { get; set; }}
}

那么你到底应该使用哪个接口呢?最简单的答案是"尽可能使用IHostEnvironment接口"。

但是详细来说,情况有很多。。。

如果你正在编写的 ASP.NET Core 3.0 的应用

尽可能是使用IHostEnviornment接口,但你需要访问WebRootPathWebRootFileProvider两个属性的时候,请使用IWebHostEnvironment接口。

如果你正在编写一个在通用主机和.NET Core 3.0 项目中使用的类库

使用IHostEnvironment接口。你的类库依然可以在 ASP.NET Core 3.0 应用中可用。

如果你正在编写一个在 ASP.NET Core 3.0 应用中使用的类库

和之前一样,尽量使用IHostEnvironment接口,因为你的类库可能不仅使用在 ASP.NET Core 应用中,还有可能使用在其他通用主机应用中。然而,如果你需要访问IWebHostEnvironment接口中的额外属性,那么你可能不得不更新你的类库,让它面向netcoreapp3.0,而不是netstandard2.0, 并且添加<FreameworkReference>元素配置。

如果你正在编写一个在 ASP.NET Core 2.x 和 3.0 中使用的类库

这种场景比较难处理,基本上你有两种可选的方案:

  • 你可以继续使用Microsoft.AspNetCore版本的IHostingEnvironment。它在 2.x 和 3.0 应用中都可以正常工作,你只需要在后续版本中停止使用即可。

  • 使用#ifdef条件编译指令,针对 ASP.NET Core 3.0 使用IHostEnvironment接口,针对 ASP.NET Core 2.x 使用IHostingEnviornment接口。

IApplicationLifetime VS IHostApplicationLifetime

IHostingEnvironment接口相似,IApplicationLifetime接口也有命名空间的冲突问题。和之前的例子相同,这两个接口分别存在于Microsoft.Extensions.HostingMicrosoft.AspNetCore.Hosting中。但是在这个例子中,这两个接口是完全一致的。

// 与Microsoft.AspNetCore.Hosting中的定义完全一致
namespace Microsoft.Extensions.Hosting
{public interface IApplicationLifetime{CancellationToken ApplicationStarted { get; }CancellationToken ApplicationStopped { get; }CancellationToken ApplicationStopping { get; }void StopApplication();}
}

如你所料,这种重复是向后兼容的征兆。在.NET Core 3.0 中新的接口IHostApplicationLifetime被引入,该接口仅在Microsoft.Extensions.Hosting命名空间中定义,但是在通用主机和 ASP.NET Core 应用中都可以使用。

namespace Microsoft.Extensions.Hosting
{public interface IHostApplicationLifetime{CancellationToken ApplicationStarted { get; }CancellationToken ApplicationStopping { get; }CancellationToken ApplicationStopped { get; }void StopApplication();}
}

同样的,这个接口和之前版本是完全一致的。ApplicationLifetime类型在通用主机项目的启动和关闭中扮演了非常重要的角色。非常有趣的是,在Microsoft.AspNetCore.Hosting中没有一个真正等价的类型,Extensions版本的接口处理了两种不同的实现。AspNetCore命名空间中唯一的实现是一个简单的封装类,类型将实现委托给了一个作为通用主机部分被添加的ApplicationLifetime对象中。

namespace Microsoft.AspNetCore.Hosting
{internal class GenericWebHostApplicationLifetime : IApplicationLifetime{private readonly IHostApplicationLifetime _applicationLifetime;public GenericWebHostApplicationLifetime(IHostApplicationLifetime applicationLifetime){_applicationLifetime = applicationLifetime;}public CancellationToken ApplicationStarted =>_applicationLifetime.ApplicationStarted;public CancellationToken ApplicationStopping =>_applicationLifetime.ApplicationStopping;public CancellationToken ApplicationStopped =>_applicationLifetime.ApplicationStopped;public void StopApplication() =>_applicationLifetime.StopApplication();}
}

幸运的是,选择使用哪一个接口,比选择托管环境(Hosting Environment)要简单的多。

如果你正在编写一个.NET Core 3.0 或者 ASP.NET Core 3.0 应用或者类库

使用IHostApplicationLifetime接口。你只需要引用Microsoft.Extensions.Hosting.Abstractions, 即可以在所有应用中使用。

如果你在编写一个被 ASP.NET Core 2.x 和 3.0 应用共同使用的类库

现在,你可能又会陷入困境:

  • 你可以继续使用Microsoft.Extensions版本的IApplicationLifetime。它在 2.x 和 3.0 应用中都可以正常使用,但是在未来的版本中,你将不得不停止使用它

  • 使用#ifdef条件编译指令,针对 ASP.NET Core 3.0 使用IHostApplicationLifetime接口,针对 ASP.NET Core 2.x 使用IApplicationLifetime接口。

幸运的是,IApplicationLifetime接口通常使用的比IHostingEnvironment接口少的多,所以你可能不会在此遇到过多的困难。

IWebHost VS IHost

这里有一件事情可能让你惊讶,IWebHost接口没有被更新,它没有继承 ASP.NET Core 3.0 中的IHost。相似的,IWebHostBuilder也没有继承自IHostBuilder。它们依然是完全独立的接口, 一个只工作在 ASP.NET Core 中,一个只工作在通用主机中。

幸运的是,这也没有关系。现在 ASP.NET Core 3.0 已经被重构使用通用主机的抽象接口, 你可以编写使用通用主机IHostBuilder抽象的方法,并在 ASP.NET Core 和通用主机应用中共享它们。如果你需要进行 ASP.NET Core 的特定操作,你可以依然使用IWebHostBuilder接口。

例如,你可以编写如下的扩展方法,一个使用IHostBuilder, 一个使用IWebHostBuilder:

public static class ExampleExtensions
{public static IHostBuilder DoSomethingGeneric(this IHostBuilder builder){// 添加通用主机配置return builder;}public static IWebHostBuilder DoSomethingWeb(this IWebHostBuilder builder){// 添加Web托管配置return builder;}
}

其中一个方法在通用主机上进行某些配置(列入,使用依赖注入注册某些服务),在另外一个方法中对IWebHostBuilder进行某种配置,例如你可能会为 Kestrel 服务器设置一些默认值。

如果你在创建了一个全新的 ASP.NET Core 3.0 应用,你的Program.cs文件看起来应该是如下代码:

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>();});
}

你可以添加针对两个扩展方法的调用。一个在通用IHostBuilder上调用,另一个在ConfigWebHostDefaults()方法中,针对IWebHostBuilder调用

public class Program
{public static void Main(string[] args) => CreateHostBuilder(args).Build().Run();public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).DoSomethingGeneric() // IHostBuilder扩展方法.ConfigureWebHostDefaults(webBuilder =>{webBuilder.DoSomethingWeb() // IWebHostBuilder扩展方法.UseStartup<Startup>();});
}

在 ASP.NET Core 3.0 中,你可以对两种构建器类型进行调用,这意味着,你现在可以仅依赖通用主机的抽象,就可以在 ASP.NET Core 应用中复用它们。然后,你可以将 ASP.NET Core 的特性行为放在顶层,而不必像 2.x 中一样重复方法。

总结

在本文中,我们讨论了 ASP.NET Core 3.0 中一些被标记为废弃的类型,它们被移动到哪里去了,以及这么做的原因。如果你正在将一个应用升级到 ASP.NET Core 3.0, 你并不需要马上替换它们,因为他们现在的行为依然相同,但是在将来的版本中会被替换掉,因此如果可以的话,最好对其进行更新。在某些场景中,它还使你的应用之间共享代码更加容易,因此值得研究一下。

参考资料

[1]

IHostingEnvironment VS IHostEnvironment - .NET Core 3.0中的废弃类型(本篇): https://www.cnblogs.com/lwqlun/p/12153935.html

[2]

官方文档: https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio

IHostingEnvironment VS IHostEnvironment - .NET Core 3.0中的废弃类型相关推荐

  1. 避免在 ASP.NET Core 3.0 中为启动类注入服务

    本篇是如何升级到ASP.NET Core 3.0系列文章的第二篇. Part 1 - 将.NET Standard 2.0 类库转换为.NET Core 3.0 类库 Part 2 - IHostin ...

  2. 在ASP.NET Core 2.0中使用CookieAuthentication

    在ASP.NET Core中关于Security有两个容易混淆的概念一个是Authentication(认证),一个是Authorization(授权).而前者是确定用户是谁的过程,后者是围绕着他们允 ...

  3. 在ASP.NET Core 2.0中创建Web API

    目录 介绍 先决条件 软件 技能 使用代码 第01步 - 创建项目 第02步 - 安装Nuget包 步骤03 - 添加模型 步骤04 - 添加控制器 步骤05 - 设置依赖注入 步骤06 - 运行We ...

  4. ASP.NET Core 3.0中使用动态控制器路由

    原文:Dynamic controller routing in ASP.NET Core 3.0 作者:Filip W 译文:https://www.cnblogs.com/lwqlun/p/114 ...

  5. .NET Core 3.0中的数据库驱动框架System.Data

    虽然没有得到很多关注,但System.Data对于.NET中任何关系型数据库的访问都至关重要.因为其前身是ActiveX Data Objects,所以它也被称为ADO.NET.System.Data ...

  6. .NET Core 3.0 中的新变化

    译者:楚人Leo 译文:http://www.cnblogs.com/leolion/p/10585834.html 原文:https://msdn.microsoft.com/en-us/magaz ...

  7. 在.Net Core 3.0中尝试新的System.Text.Json API

    .NET Core 3.0提供了一个名为System.Text.Json的全新命名空间,它支持reader/writer,文档对象模型(DOM)和序列化程序.在此博客文章中,我将介绍它如何工作以及如何 ...

  8. asp.net core 3.0 中使用 swagger

    asp.net core 3.0 中使用 swagger Intro 上次更新了 asp.net core 3.0 简单的记录了一下 swagger 的使用,那个项目的 api 比较简单,都是匿名接口 ...

  9. .NET Core 3.0 中的数据库驱动框架 System.Data

    虽然没有得到很多关注,但System.Data对于.NET 中任何关系型数据库的访问都至关重要.因为其前身是 ActiveX Data Objects,所以它也被称为 ADO.NET.System.D ...

最新文章

  1. 随机器学习兴起的Julia编程语言
  2. 谷歌表格_如何使用宏自动执行Google表格
  3. JQuery学习四(过滤选择器)
  4. 没有理智的欲望会走向毁灭,没有欲望的理智会永守清贫
  5. .NET下使用DataAdapter保存数据时,如何生成command语句及使用事务
  6. Linux快速复制或删除大量小文件
  7. OCS UCCA 开发笔记(Unified Communications Client API)
  8. WinXP升级IE6至IE8以及WIN7下IE8升级至IE11
  9. [计算机网络]RJ45直通线和交叉线的连接方式和设备类型解析
  10. 联想计算机 屏幕 无法进入,解决方案:联想笔记本如何进入BIOS?联想出现在计算机屏幕上。...
  11. Windows下怎么更改文件扩展名
  12. 云服务器被恶意ddos攻击了怎么办?
  13. 网站seo淘宝客不能做了?我是怎么用网站做淘客月入过万的
  14. 【模式匹配】之 —— Z-BOX算法
  15. SpringCloud(part10)Spring Data 与JPA,MongoDB,Redis
  16. 文明重启战局服务器维护中是什么意思,文明重启为什么改了密码别人还能登?...
  17. 云图科技,长沙VR全景技术解决网上购物问题!
  18. 读书笔记 - 《史蒂夫·乔布斯传》
  19. 【转】Linux那些事儿 之 戏说USB(23)设备的生命线(二)
  20. 设计师常用设计尺寸有哪些

热门文章

  1. 深入浅出Google Android这本书怎么样
  2. asp.net网页上嵌入Flash显示
  3. asp.net控件开发基础(20)
  4. 2019年5月 Teams Community Call (China)
  5. Teams App抽奖机器人 - 基础架构
  6. 【C】C语言结构体指针的语法
  7. 每个程序员都可能犯过的10个错误
  8. github 上微信判断是否被删除的源码 以及使用解惑
  9. 使用原生js写ajax
  10. maven3安装和使用笔记