读《ASP.NET Core3框架揭秘》之1~全新的开发体验
参考:https://www.cnblogs.com/artech/p/inside-asp-net-core-3.html
一、全新的开发体验
1、Win平台
1.1、dotnet.exe是.NET Core SDK为我们提供的一个重要的命令行工具;
1.2、项目文件:
对于传统的.NET Framework应用来说,即使是一个空的C#项目,定义该项目的.csproj文件在内容和结构上都是很复杂的。但是对于一个.NET Core应用来说,这个.csproj文件的结构变得相对简单并清晰了一些,以至于作为开发人员的我们经常会直接编辑它;
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.0</TargetFramework> </PropertyGroup> </Project>
1.3、helloworld.exe是一个可以直接运行的可执行文件,而helloworld.dll仅仅是一个单纯的动态链接库,需要借助命令行dotnet.exe才能执行。
1.4、ASP.NET Core
一个ASP.NET Core应用本质上就是一个用来监听、接收和处理HTTP请求的后台服务,所以它被定义成一个GenericWebHostService(实现了IHostedService接口),我们将它注册到承载系统中进而实现了针对ASP.NET Core应用的承载。
一个运行的ASP.NET Core应用本质上体现为由一个服务器和若干中间件构成的消息处理管道,服务器解决针对HTTP请求的监听、接收和最终的响应,具体针对请求的处理则由它递交给后续的中间件来完成。这个管道是由前面提到的GenericWebHostService服务构建出来的。
ASP.NET Core提供了几种原生的服务类型,比较常用的是KestrelServer和HTTP.sys。KestrelServer是一款跨平台的Web服务器,可以在Windows、Mac OS和Linux上使用。它不仅可以作为独立的Web服务器直接对外提供服务,也可以结合传统的Web服务器(比如IIS、Apache和NGinx)并将它们作为反向代理来使用。HTTP.sys则是一种只能在Windows平台使用的Web服务器。
class Program { static void Main() { Host.CreateDefaultBuilder() .ConfigureWebHost(webHostBuilder => webHostBuilder .UseKestrel() .Configure(app => app.Run( context => context.Response.WriteAsync("Hello World.")))) .Build() .Run(); } }
我们调用IWebHostBuilder接口的UseKestrel扩展方法将KestrelServer注册为服务器,调用Configure扩展方法注册了用来处理请求的中间件。
注册的KestrelServer服务器会绑定到http//localhost:5000和https//localhost:5001这两个地址监听请求。
1.5、SDK类型
通过dotnet new命令工具创建出来的控制台应用,它默认采用的SDK类型为“Microsoft.NET.Sdk”。对于一个ASP.NET Core应用,我们一般会采用另一种名为“Microsoft.NET.Sdk.Web”的SDK类型。
1.6、launchSettings.json
一个名为“launchSettings.json”的配置文件将自动生成并被保存在“\Properties”目录下。顾名思义,launchSettings.json是一个在应用启动的时候自动加载的配置文件,该配置文件使我们可以在不同的设置下执行我们的应用程序。
该配置文件默认添加了两个节点,其中“iisSettings”用于设置IIS相关的选项,而“profiles”节点定义了一系列用于表示应用启动场景的Profile【一个IIS Express、一个使用当前项目名称来命名】。
{ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:51127/", "sslPort": 0 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "helloworld": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "http://localhost:51128/" } } }
launchSettings.json文件中的所有设置仅仅针对开发环境,产品环境下是不需要这个文件的,应用发布后生成的文件列表中也不包含该文件。该文件不需要手工进行编辑,当前项目属性对话框(通过在解决方案对话框中右击选择“属性(Properties)”选项)中“调试(Debug)”选项卡下的所有设置最终都会体现在该文件上。
1.7、ASP.NET Core MVC
整个ASP.NET MVC框架是建立在 用来实现路由的EndpointRoutingMiddleware中间件 和 EndpointMiddleware中间件 上的。
对于ASP.NET Core MVC框架来说,它在处理HTTP请求的过程中所需的一系列服务同样需要预先注册。
由于注册的中间件具有对其他服务的依赖,我们需要预先将这些服务注册到依赖注入框架中。依赖服务的注册通过调用IWebHostBuilder的ConfigureServices方法来完成,该方法的参数类型为Action<IServiceCollection>,添加的服务注册就保存在IServiceCollection接口表示的集合中。
1.8、使用Startup类型
真实的开发场景中我们一般会将中间件以及依赖服务的注册定义在一个单独的类型中。按照约定,我们通常会将这个类型命名为Startup,针对服务和中间件的注册就可以放在如下定义的这个Startup类中。
public class Startup { public void ConfigureServices(IServiceCollection services) => services .AddRouting() .AddControllersWithViews(); public void Configure(IApplicationBuilder app) => app .UseRouting() .UseEndpoints(endpoints => endpoints.MapControllers()); }
随着对ASP.NET Core框架认识的加深,我们会发现这种“约定优于配置”的设计广泛地应用在整个框架之中。
StartUp中主要有两个方法:
1、ConfigureServices方法是用来把services(各种服务, 例如identity, ef, mvc等等包括第三方的, 或者自己写的)加入(register)到container(asp.net core的容器)中去, 并配置这些services. 这个container是用来进行dependency injection的(依赖注入). 所有注入的services(此外还包括一些框架已经注册好的services)
2、Configure方法是asp.net core程序用来具体指定如何处理每个http请求的, 例如我们可以让这个程序知道我使用mvc来处理http请求, 那就调用app.UseMvc()这个方法就行,还有异常处理程序、重定向、使用静态文件等
1.9 调试
.net core 调试的两种方法
1、IIS,通过IIS调试
2、项目名称,项目自带的Kestrel web应用调式
运行时相应的配置在launchSettings.json 文件中定义。
2、Docker
2.1 Dockfile
vs中对项目添加docker支持,选Linux,自动生成Dockerfile文件:
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base WORKDIR /app EXPOSE 80 EXPOSE 443 FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build WORKDIR /src COPY ["ASP.NETCore/HelloWorld/HelloWorld.csproj", "ASP.NETCore/HelloWorld/"] RUN dotnet restore "ASP.NETCore/HelloWorld/HelloWorld.csproj" COPY . . WORKDIR "/src/ASP.NETCore/HelloWorld" RUN dotnet build "HelloWorld.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "HelloWorld.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "HelloWorld.dll"]
使用Dockerfile来构建项目的步骤:【How Visual Studio builds containerized apps】
当Visual Studio生成不使用Docker容器的项目时,它将在本地计算机上调用MSBuild并在本地解决方案文件夹下的文件夹(通常为bin)中生成输出文件。 但是,对于容器化项目,构建过程会考虑Dockerfile的有关构建容器化应用程序的指令。 Visual Studio使用的Dockerfile分为多个阶段。 该过程依赖于Docker的多阶段构建功能。
多阶段构建功能允许容器仅包含应用程序在运行时所需的位,从而使容器的构建过程更高效,并使容器更小。 多阶段构建用于.NET Core项目,而不是.NET Framework项目。
1、base
多阶段构建允许在生成中间镜像的阶段中创建容器图像。 例如,考虑由Visual Studio生成的典型Dockerfile-第一阶段是base:
Dockerfile中的行以Microsoft容器注册表(mcr.microsoft.com)中的Debian映像开头,并创建一个中间映像库,该库公开了端口80和443,并将工作目录设置为/ app。
2、build
下一阶段是build:
您会看到构建阶段从注册表中的其他原始镜像(sdk而不是aspnet)开始,而不是从base继续。 sdk镜像具有所有构建工具,因此,它比仅包含运行时组件的aspnet镜像大得多。 当您查看Dockerfile的其余部分时,使用单独镜像的原因就很清楚了:
3、final
最后的阶段再次从基础开始,并包括COPY --from = publish以将已发布的输出复制到最终镜像。 由于不需要包含sdk映像中的所有构建工具,因此此过程可以使最终映像小得多。
FROM build AS publish RUN dotnet publish "WebApplication43.csproj" -c Release -o /app FROM base AS final WORKDIR /app COPY --from=publish /app . ENTRYPOINT ["dotnet", "WebApplication43.dll"]
总结:
这个Dockerfile采用了一个中间层(build)来暂存ASP.NET Core MVC应用发布后的资源,其工作目录为“/app”。
具体来说,这个层采用“microsoft/aspnetcore-build:2”作为基础镜像,我们先将定义项目的.csproj文件(helloworld.csproj)拷贝到当前工作目录,然后运行“dotnet restore”命令恢复所有注册在这个项目文件中的NuGet包。
接下来我们将当前项目的所有文件拷贝到当前工作目录,并执行dotnet publish对整个项目进行编译发布(针对Release模式),发布后的资源被保存到目录“/app/out”中。
在真正将编译生成Docker镜像的时候,我们采用“mcr.microsoft.com/dotnet/core/aspnet:3.0”作为基础镜像,由于应用在上面进行了预先发布,所以我们只需要将发布后的所有文件拷贝到当前工作目录就可以了。接下来我们通过环境变量设置了ASP.NET Core应用的监听地址(http://0.0.0.0:3721)。针对ENTRYPOINT的定义(ENTRYPOINT ["dotnet", "helloworld.dll"]),我们知道当容器被启动的时候,“dotnet helloworld.dll”命令会被执行以启动这个ASP.NET Core应用。
2.2 Linux上实战
1、把项目所有文件(不用发布) 拷贝到linux上。Dockerfile文件要移动出来到上一级目录
{因为构建动作在上层也就是docker-firstcore目录当中,去执行这样的话,上下文中就包括了整个项目}参考:.Net Core 用自动生成Dockerfile的坑
Docker 中暴露80端口最好不要修改
2、根据dockerfile生成镜像(需要先编译和发布)
在当前项目的目录内执行
dotnet build "RmAspNetCoreDocker.csproj" -c Release -o /home/huydocker
dotnet publish "RmAspNetCoreDocker.csproj" -c Release -o /home/huydocker
3、在外层dockerfile的同一级目录下执行:创建镜像(注意镜像名字 小写),开启一个容器
docker build -t myim .
docker run -d --name=myim_v2.0 -p 5003:80 myim [外网5003去访问]
或者不指定端口:docker run -d -P myim
4、构建镜像:docker build -t firstcore .
(. 代表去找dockerfile,-t是镜像名称)【注意-t是英文的-】 一共有17步
5、然后查看镜像 docker images
查看镜像详情 Docker image inspect firstcore
{主要看GraphDriver,目录,镜像编号}
6、实例化一个容器,运行我们的程序:docker run –d –P 镜像id
{-P 是为了暴露一个端口(查看容器时就能看到);-d是为了后台运行 deamon}
可以指定端口号:-p 32770:80 [外网端口:内网映射端口]
然后查看容器列表 Docker ps –a
7、访问网站
通过此端口去访问站点【外网访问 注意开启安全组】
注:如果网站修改后,可以把之前的容器停止掉。然后直接重新发布一遍,