IHostingEnvironment VS IHostEnvironment - .NET Core 3.0中的废弃类型

原文: https://andrewlock.net/ihostingenvironment-vs-ihost-environment-obsolete-types-in-net-core-3/
做者: Andrew Lock
译者: Lamond Luhtml

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

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


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中使用一套抽象,通用主机使用另外一套抽象)获得了根本解决。app

固然,这还不是所有。当你从ASP.NET Core 2.x升级到3.0, ASP.NET Core 3.0并不强迫你当即使用新的通用主机。若是你愿意,你能够继续使用旧的WebHostBuilder,而不使用新的HostBuilder。虽然在ASP.NET Core 3.0的官方文档中一直暗示这是必须的,可是在当前的阶段,这是一个可选配置,若是你须要,能够继续使用Web主机,而不使用通用主机。asp.net

PS: 不过我仍是建议你将可能将HostBuilder做为你将来的升级计划。我可是在将来的某个时间点WebHostBuilder将被移除,即便如今它尚未被标记为[Obsolete]ide

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

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两个属性。ui

出于向后兼容的缘由,这里须要一个单独的抽象。可是,这种作法真正使人讨厌的后果之一是没法编写用于通用主机和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, 你并不须要立刻替换它们,由于他们如今的行为依然相同,可是在未来的版本中会被替换掉,所以若是能够的话,最好对其进行更新。在某些场景中,它还使你的应用之间共享代码更加容易,所以值得研究一下。

相关文章
相关标签/搜索