ASP.NET Core跨平台 技术内幕

  ASP.NET Core设计初衷是开源跨平台、高性能Web服务器,其中跨平台特性较早期ASP.NET是一个显著的飞跃,.NET现可以理直气壮与JAVA同台竞技,而ASP.NET Core的高性能特性更是成为致胜法宝。

ASP.NET Core 2.1+为IIS托管新增In-Process模型并作为默认选项(使用IISHttpServer替代了Kestrel,dotnet程序由IIS网站进程w3wp.exe内部托管)。

为了展示ASP.NET Core跨平台特性,本文还是重点着墨 经典的Out-Process托管模型。

宏观模型

为解耦平台差异,程序内置Http服务组件Kestrel,由平台web服务器转发请求到Kestrel。

  • 老牌web服务器定位成反向代理服务器,转发请求到ASP.Net Core程序(分别由IIS AspNetCore Module 和Nginx配置参数完成)

常规代理服务器,只用于代理内部主机对外网的连接需求,一般不支持外部对内部网络的访问请求;

当一个代理服务器能够代理外部网络的主机,访问内部网络,这种代理服务器被称为反向代理服务器 。

  •  平台web代理服务器、ASP.NET Core程序(dotnet.exe) 均为独立进程,平台自行决定互动细节,只需确保平台web服务器与Kestrel形成Http通信。

Kestrel 

与老牌web服务器解耦,实现跨平台部署,要注意

  • 进程内Http服务器,ASP.NET Core具备了基本web服务器的能力,在内网部署和开发环境完全可使用dotnet.exe自宿模式运行。
  • Kestrel定位是Http服务组件,实力还比不上老牌web服务器,在timeout机制、web缓存、响应压缩等不占优势,在安全性等方面还有缺陷。

因此在生产环境中必须使用老牌web服务器反向代理请求。

 

不同平台管控应用、转发请求

要实现企业级稳定部署:

*nix平台

将ASP.NET Core程序以dotnet.exe自宿模式运行,并配置为系统守护进程(管控应用),再由Nginx转发请求

以下使用systemd创建进程服务文件 /etc/systemd/system/kestrel-eqidproxyserver.service 

[Unit]
Description=EqidProxyServer deploy on centos

[Service]
WorkingDirectory=/var/www/eqidproxyserver/eqidproxyServer
ExecStart=/usr/bin/dotnet /var/www/eqidproxyserver/eqidproxyServer/EqidProxyServer.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
TimeoutStopSec=90
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=root
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target
sudo systemctl enable kestrel-eqidproxyserver.service       // 启用服务

安装Nginx,并配置Nginx转发请求;

server {
        listen       80;
        server_name  default_website;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        proxy_pass         http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        }
    }

Windows平台

[ 管控应用、转发请求] 由ASP.NET Core Module(插入在IIS Pipeline中的原生组件,下面简称ACM)一手操办。

w3wp.exe、dotnet.exe的互动关系是通过父子进程维系的。下图脚本力证dotnet.exe进程是w3wp.exe创建出来的子进程:

正因为如此,ACM在创建子进程时能指定子进程环境变量,约定donet.exe接收(IIS转发的请求)的侦听端口。

实际上从源码看ACM为子进程设定三个重要的环境变量:

  • ASPNETCORE_PORT   约定 Kestrel将会在此端口上监听
  • ASPNETCORE_APPL_PATH
  • ASPNETCORE_TOKEN   约定 携带该Token的请求为合法的转发请求

与ACM夫唱妇随的是UseIISIntegration()扩展方法,完成如下工作:

① 启动Kestrel服务在http://localhost:{ASPNETCORE_PORT}上监听

② 根据 {ASPNETCORE_TOKEN} 检查请求是否来自ACM转发

ACM转发的请求,会携带名为MS-ASPNETCORE-TOKEN:******的Request Header,以便dotnet.exe对比研判。

③ 利用ForwardedHeaderMiddleware中间件保存原始请求信息

linux平台部署需要手动启用ForwardedHeader middleware

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-3.1

源码快速验证:
namespace Microsoft.AspNetCore.Hosting
{
    public static class WebHostBuilderIISExtensions
    {
        // These are defined as ASPNETCORE_ environment variables by IIS's AspNetCoreModule.
        private static readonly string ServerPort = "PORT";
        private static readonly string ServerPath = "APPL_PATH";
        private static readonly string PairingToken = "TOKEN";
        private static readonly string IISAuth = "IIS_HTTPAUTH";
        private static readonly string IISWebSockets = "IIS_WEBSOCKETS_SUPPORTED";

        /// <summary>
        /// Configures the port and base path the server should listen on when running behind AspNetCoreModule.
        /// The app will also be configured to capture startup errors.
        public static IWebHostBuilder UseIISIntegration(this IWebHostBuilder hostBuilder)
        {
            var port = hostBuilder.GetSetting(ServerPort) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{ServerPort}");
            var path = hostBuilder.GetSetting(ServerPath) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{ServerPath}");
            var pairingToken = hostBuilder.GetSetting(PairingToken) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{PairingToken}");
            var iisAuth = hostBuilder.GetSetting(IISAuth) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{IISAuth}");
            var websocketsSupported = hostBuilder.GetSetting(IISWebSockets) ?? Environment.GetEnvironmentVariable($"ASPNETCORE_{IISWebSockets}");

            bool isWebSocketsSupported;
            if (!bool.TryParse(websocketsSupported, out isWebSocketsSupported))
            {
                // If the websocket support variable is not set, we will always fallback to assuming websockets are enabled.
                isWebSocketsSupported = (Environment.OSVersion.Version >= new Version(6, 2));
            }

            if (!string.IsNullOrEmpty(port) && !string.IsNullOrEmpty(path) && !string.IsNullOrEmpty(pairingToken))
            {
                // Set flag to prevent double service configuration
                hostBuilder.UseSetting(nameof(UseIISIntegration), true.ToString());

                var enableAuth = false;
                if (string.IsNullOrEmpty(iisAuth))
                {
                    // back compat with older ANCM versions
                    enableAuth = true;
                }
                else
                {
                    // Lightup a new ANCM variable that tells us if auth is enabled.
                    foreach (var authType in iisAuth.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        if (!string.Equals(authType, "anonymous", StringComparison.OrdinalIgnoreCase))
                        {
                            enableAuth = true;
                            break;
                        }
                    }
                }

                var address = "http://127.0.0.1:" + port;
                hostBuilder.CaptureStartupErrors(true);
                hostBuilder.ConfigureServices(services =>
                {
                    // Delay register the url so users don't accidentally overwrite it.
                    hostBuilder.UseSetting(WebHostDefaults.ServerUrlsKey, address);
                    hostBuilder.PreferHostingUrls(true);
                    services.AddSingleton<IServerIntegratedAuth>(_ => new ServerIntegratedAuth()
                    {
                        IsEnabled = enableAuth,
                        AuthenticationScheme = IISDefaults.AuthenticationScheme
                    });
                    services.AddSingleton<IStartupFilter>(new IISSetupFilter(pairingToken, new PathString(path), isWebSocketsSupported));
                    services.Configure<ForwardedHeadersOptions>(options =>
                    {
                        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
                    });
                    services.Configure<IISOptions>(options =>
                    {
                        options.ForwardWindowsAuthentication = enableAuth;
                    });
                    services.AddAuthenticationCore();
                });
            }
            return hostBuilder;
        }
    }
}

总结, ASP.NET Core跨平台的核心在于 程序内置Kestrel HTTP通信组件解耦了差异, 各平台建立Http通信的细节各不相同。

 

That's All.  本文旨在从框架设计初衷、进程模型、组件交互原理给大家剖析出ASP.NET Core跨平台技术内幕,关键内容均给出源码链接。

 

+ 完整版本CentOS部署ASP.NET Core程序,请参考https://www.cnblogs.com/JulianHuang/p/10455644.html

原文地址:https://www.cnblogs.com/JulianHuang/p/10334506.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


引言 本文从Linux小白的视角, 在CentOS 7.x服务器上搭建一个Nginx-Powered AspNet Core Web准生产应用。 在开始之前,我们还是重温一下部署原理,正如你所常见的.Net Core 部署图: 在Linux上部署.Net Core App最好的方式是在Linux机器
引言: 多线程编程/异步编程非常复杂,有很多概念和工具需要去学习,贴心的.NET提供Task线程包装类和await/async异步编程语法糖简化了异步编程方式。 相信很多开发者都看到如下异步编程实践原则: 遵守以上冷冰冰的②③条的原则,可保证异步程序按照预期状态正常运作;我们在各大编程论坛常看到违背
一. 宏观概念 ASP.NET Core Middleware是在应用程序处理管道pipeline中用于处理请求和操作响应的组件。 每个组件是pipeline 中的一环。 自行决定是否将请求传递给下一个组件 在处理管道的下个组件执行之前和之后执行业务逻辑 二. 特性和行为 ASP.NET Core处
背景 在.Net和C#中运行异步代码相当简单,因为我们有时候需要取消正在进行的异步操作,通过本文,可以掌握 通过CancellationToken取消任务(包括non-cancellable任务)。 Task&#160;表示无返回值的异步操作, 泛型版本Task&lt;TResult&gt;表示有返
HTTP基本认证 在HTTP中,HTTP基本认证(Basic Authentication)是一种允许网页浏览器或其他客户端程序以(用户名:口令) 请求资源的身份验证方式,不要求cookie,session identifier、login page等标记或载体。 - 所有浏览器据支持HTTP基本认
1.Linq 执行多列排序 OrderBy的意义是按照指定顺序排序,连续两次OrderBy,后面一个有可能会打乱前面一个的排序顺序,可能与预期不符。 要实现sql中的order by word,name类似效果; LINQ 有ThenBy可以紧接使用, ThenBy记住原本排序的值,然后再排其他值,
ASP.NET Core 核心特性:开源、跨平台、高性能是其决战JAVA的必胜法宝,最引人关注的跨平台特性 到底是怎么实现? &#xA; 本文分Unix、Windows剖析跨平台内幕,读完让你大呼过瘾。
前导 Asynchronous programming Model(APM)异步编程模型以BeginMethod(...) 和 EndMethod(...)结对出现。 IAsyncResult BeginGetResponse(AsyncCallback callback, object state
引言 最近在公司开发了一个项目,项目部署架构图如下: 思路 如图中文本所述,公司大数据集群不允许直接访问外网,需要一个网关服务器代理请求,本处服务器A就是边缘代理服务器的作用。 通常技术人员最快捷的思路是在服务器A上部署IISʺpplication Request Routing Module组件
作为一枚后端程序狗,项目实践常遇到定时任务的工作,最容易想到的的思路就是利用Windows计划任务/wndows service程序/Crontab程序等主机方法在主机上部署定时任务程序/脚本。 但是很多时候,若使用的是共享主机或者受控主机,这些主机不允许你私自安装exe程序、Windows服务程序
引言 熟悉TPL Dataflow博文的朋友可能记得这是个单体程序,使用TPL Dataflow 处理工作流任务, 在使用Docker部署的过程中, 有一个问题一直无法回避: 在单体程序部署的瞬间(服务不可用)会有少量流量无法处理;更糟糕的情况下,迭代部署的这个版本有问题,上线后无法运作, 更多的流
合格的web后端程序员,除搬砖技能,还必须会给各种web服务器配置Https,本文结合ASP.NET Core部署模型聊一聊启用Https的方式。 温故知新 目前常见的Http请求明文传输,请求可能被篡改,访问的站点可能被伪造。 HTTPS是HTTP加上TLS/SSL协议构建的可进行加密传输、身份认
长话短说 前文《解剖HttpClientFactory,自由扩展HttpMessageHandler》主要讲如何为HttpClientFactory自定义HttpMessageHandler组件, 现在来完成课后的小作业: 将重点日志字段显示到Nlog的LayoutRenderer上。 本文实现一个
引言问题 作为资深老鸟,有事没事,出去面试;找准差距、定位价值。 面试必谈哈希, Q1:什么是哈希? Q2:哈希为什么快? Q3:你是怎么理解哈希算法利用空间换取时间的? Q4:你是怎么解决哈希冲突的? Q5:你有实际用写过哈希算法吗? 知识储备 哈希(也叫散列)是一种查找算法(可用于插入),哈希算
前言 如题,有感于博客园最近多次翻车,感觉像胡子眉毛一把抓, 定位不了生产环境的问题。 抛开流程问题,思考在生产环境中如何做故障排除,&#160;发现博客园里面这方面的文章比较少。 .Net 本身是提供了sos.dll工具帮助我们在生产中故障排除,通过提供有关内部公共语言运行时(CLR)环境的信息,
.NET程序是基于.NET Framework、.NET Core、Mono、【.NET实现】开发和运行的 ,定义以上【.NET实现】的标准规范称为.NET Standard .NET Standard .NET标准是一组API集合,由上层三种【.NET实现】的Basic Class Library
长话短说 上个月公司上线了一个物联网数据科学项目,我主要负责前端接受物联网事件,并提供 参数下载。 webapp 部署在Azure云上,参数使用Azure SQL Server存储。 最近从灰度测试转向全量部署之后,日志时常收到: SQL Session超限报错。 排查 我在Azure上使用的是 S
临近年关,搜狗,360浏览器出现页面无法成功跳转,同域Cookie丢失? 也许是服务端 SameSite惹的祸。&#xA;本文揭示由于Chrome低版本内核不识别 SameSite= None, 引发的单点登录故障。
本文聊一聊TraceID的作用和一般组成,衍生出ASP. NETCore 单体和分布式程序中 TraceId 的使用方式
通过给 HttpClint请求的日志增加 TraceId,解锁自定义扩展 HttpClientFacroty 的姿势