深入理解 OWIN 中的 Host 和 Server

The Open Web Interface for .NET (OWIN),注意單詞爲大寫,之前好像都寫成了 Owin,但用於項目的時候,可以寫成:Microsoft.Owin.*。

OWIN 體系結構圖(簡化版):

191453141107768.png

ASP.NET 5 中 Server 和 Host 相關程序包(New/Old):

另外,在 ASP.NET 5 中,還有一個 K 命令,對應原 OWIN 中的 OwinHost.exe。

在 OWIN 的體系結構中,結合 ASP.NET 5 相關程序包,Host 和 Server 的概念,Microsoft.AspNet.Hosting、Microsoft.AspNet.Server.IIS、Microsoft.AspNet.Server.WebListener 等程序包,然後還有 Web Server(IIS、Apache 等),其實它們之間的關係很容易搞混,尤其是在理解 ASP.NET 5 的運行機制或在其項目發佈的時候,如果不能很好的理解它們之間的相互關係,將是一個很大的隱患,下面我們根據 Host 和 Server 來分別理解他們。

Host

Host(主機):運行應用程序的進程,可以是從 IIS 或獨立可執行文件到自己的自定義程序的任何內容。主機負責啓動、加載其他 OWIN 組件和正常關閉,主機一般可以看作是服務器的操作系統提供的進程。

從概念上理解,Host 其實就是一個進程,用於管理 OWIN 組件的一些操作,對於現在的 ASP.NET 5 應用程序部署來說,Host 一般有兩個選擇:Self-Host 和 IIS。

先來看一下采用 Self-Host 的一段 project.json 配置:

{
    "webroot": "wwwroot",
    "dependencies": {
        "Microsoft.AspNet.Hosting": "1.0.0-beta1",
        "Microsoft.AspNet.Server.WebListener": "1.0.0-beta1"
    },
    "commands": {
        /* Change the port number when you are self hosting this application */
        "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
    }
}

這是 ASP.NET 5 項目中採用 Self-Host 方式最簡單的一個配置,因爲有了 K Commands(OwinHost.exe),所以我們不需要在 Startup Configure 進行如下配置:

var baseAddress = new Uri("http://localhost:5000");
var config = new HttpSelfHostConfiguration(baseAddress);

OwinHost.exe 命令說明:

192007422356587.png

咋一看,和 K Commands 非常類似,其實就是從 OwinHost 演化而來的,在上面 project.json 配置中,我們只加載了兩個程序包,其中 Microsoft.AspNet.Server.WebListener 是 OWIN 中 Server 的概念,是創建 ASP.NET 5 項目的默認服務器,這個後面再說,那 Microsoft.AspNet.Hosting 是什麼?官方說明爲:The Hosting repo contains code required to host an ASP.NET vNext application, it is the entry point used when self-hosting an application. 什麼意思呢?我們看一下 Microsoft.AspNet.Hosting/Program.cs 的源碼,就知道了:

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using Microsoft.Framework.Logging;
using Microsoft.Framework.Runtime;

namespace Microsoft.AspNet.Hosting
{
    public class Program
    {
        private const string HostingIniFile = "Microsoft.AspNet.Hosting.ini";
        private readonly IServiceProvider _serviceProvider;

        public Program(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public void Main(string[] args)
        {
            var config = new Configuration();
            if (File.Exists(HostingIniFile))
            {
                config.AddIniFile(HostingIniFile);
            }
            config.AddEnvironmentVariables();
            config.AddCommandLine(args);

            var services = HostingServices.Create(_serviceProvider, config)
                .BuildServiceProvider();
            var appEnv = services.GetRequiredService<IApplicationEnvironment>();
            var hostingEnv = services.GetRequiredService<IHostingEnvironment>();

            var context = new HostingContext()
            {
                Services = services,
                Configuration = config,
                ServerName = config.Get("server"), // TODO: Key names
                ApplicationName = config.Get("app")  // TODO: Key names
                    ?? appEnv.ApplicationName,
                EnvironmentName = hostingEnv.EnvironmentName,
            };

            var engine = services.GetRequiredService<IHostingEngine>();
            var loggerFactory = services.GetRequiredService<ILoggerFactory>();
            var appShutdownService = _serviceProvider.GetRequiredService<IApplicationShutdown>();
            var shutdownHandle = new ManualResetEvent(false);
            var serverShutdown = engine.Start(context);

            appShutdownService.ShutdownRequested.Register(() =>
            {
                try
                {
                    serverShutdown.Dispose();
                }
                catch (Exception ex)
                {
                    var logger = loggerFactory.Create<Program>();
                    logger.WriteError("TODO: Dispose threw an exception", ex);
                }
                shutdownHandle.Set();
            });

            var ignored = Task.Run(() =>
            {
                Console.WriteLine("Started");
                Console.ReadLine();
                appShutdownService.RequestShutdown();
            });

            shutdownHandle.WaitOne();
        }
    }
}

這段代碼就很好的說明了“entry point”的概念,當我們使用 Self-Host 方式,Microsoft.AspNet.Hosting 就是與我們應用程序的一個入口,用來管理 OWIN 所有組件與應用程序的交互,啓動方式使用 K Commands,Host 除了採用 Self-Host 的方式,我們還可以使用 IIS,那他們之間有什麼不懂呢?看段配置代碼就明白了:

{
    "webroot": "wwwroot",
    "dependencies": {
        "Microsoft.AspNet.Server.IIS": "1.0.0-beta1"
    }
}

對,你沒看錯,如果採用 IIS 部署的方式,這就是 project.json 的配置代碼,只需要加載一個 Microsoft.AspNet.Server.IIS 程序包就可以了,那這個東西具體有什麼作用呢?我們來看一段說明:Using the standard HttpModule and HttpHandler types, OWIN pipelines can run on IIS as a part of an ASP.NET request flow. 我們再來看一下它和 Microsoft.AspNet.Server.WebListener 的不同之處:

192056573448857.png

一圖勝千言,Microsoft.AspNet.Server.IIS 依賴項中的 Microsoft.AspNet.Loader.IIS 是什麼東西?其實就是 /wwwroot/bin 目錄下的 AspNet.Loader.dll,這個東西在之前的博文中有提到,你可以把它看成是打開 IIS 與 OWIN 管道的一個“開關”,讓應用程序的請求放在 IIS 模塊進行處理,比如 OWIN 中的某一個 Microsoft.AspNet.StaticFiles Middleware 中間件,對應於 IIS 中的 StaticFilesModule 模塊,在應用程序中,關於靜態文件的一些請求處理,就是 StaticFilesModule 進行處理的,這是 IIS 的工作範疇。

Server

Server: While the host is responsible for starting and maintaining process within which the application runs, the responsibility of the server is to open a network socket, listen for requests, and send them through the pipeline of OWIN components specified by the user (as you may have already noticed, this pipeline is specified in the application developer’s Startup class).

Host 是管理 OWIN 組件的一個進程,而 Server 則是監聽請求,並分發請求給對應的 Middleware 中間件進行處理(Startup 中指定),也就是說 Server 只負責監聽與分發,不負責處理,這個就和 IIS 有很明顯的區別,IIS 是“全套服務”,請求的處理也在 IIS 中進行完成的,而 Microsoft.AspNet.Server.WebListener 只是完成簡單的監聽與分發(也可以稱爲綁定 OWIN 組件)。

目前 OWIN 實現的兩個 Server:

  • Microsoft.AspNet.Server.WebListener

  • Microsoft.AspNet.Server.IIS

說深入理解,其實也只是表面而已,就記錄到這。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章