.NET Core多平臺開發體驗[1]: Windows

来源:http://www.cnblogs.com/artech/archive/2017/09/03/asp-net-core-hello-world-01.html
-Advertisement-
Play Games

微軟在千禧年推出 .NET戰略,併在兩年後推出第一個版本的.NET Framework和IDE(Visual Studio.NET 2002,後來改名為Visual Studio),如果你是一個資深的.NET程式員,相信傳統的.NET應用的開發方式已經深深地烙印在你的腦子裡面。.NET Core打來... ...


微軟在千禧年推出 .NET戰略,併在兩年後推出第一個版本的.NET Framework和IDE(Visual Studio.NET 2002,後來改名為Visual Studio),如果你是一個資深的.NET程式員,相信傳統的.NET應用的開發方式已經深深地烙印在你的腦子裡面。.NET Core打來了全新的開發體驗,但是開發方式的差異根本不足以成為你快速跨入.NET Core 世界的門檻,因為在.NET Core在很多方面比傳統的.NET Framework應用開發要簡單。為了消除很多尚未接觸過.NET Core的讀者對未知世界的恐懼,我們先通過幾個簡單的Hello World應用讓大家感受一下.NET Core全新的開發體驗。

目錄
一、安裝開發環境
二、利用命令行創建.NET Core程式
三、改造成一個ASP.NET Core應用
四、進一步改造成ASP.NET Core MVC應用

不管你是否已經接觸過.NET Core,我們相信你一定知道.NET Core是“跨平臺”的。較之傳統的.NET Framework應用只能運行在微軟自家的Windows平臺上,經過全新設計的.NET Core在誕生的時候就被註入了跨平臺的基因,通過.NET Core應用在無需經過任何更改的情況下就可以直接運行在Windows、Mac OS以及各種Linux Distribution(RHEL、Ubuntu、Debian、Fedora、CentOS和SUSE等)平臺上。除此之外,.NET Core針對Docker也提供了原生的支持,一個.NET Core應用可以同時運行在Windows Container和Linux Container上。我們接下里現在Windows平臺下感受一下.NET Core的開發體驗,不過在這之前先得構建一下開發環境。

一、安裝開發環境

.NET Core的官方站點(https://www.microsoft.com/net/core)提供了在各種平臺下安裝開發環境的介紹。總的來時,我們在不同的平臺下開發.NET Core應用都需要按照相應的SDK和IDE。針對Windows開發平臺來說,.NET Core 2.0.0 SDK可以通過上述這個站點直接下載。成功安裝SDK之後,我們在本地將自動擁有了.NET Core的運行時(CoreCLR)、基礎類庫以及相應的開發工具。

dotnet.exe是.NET Core SDK為我們提供的一個重要的命令行工具,我們在進行.NET Core應用的開發部署的時候將會頻繁地使用它。dotnet.exe提供了很多有用的命令,為了不“節外伸枝”,我們就不對它們作系統介紹了,如果後續章節涉及到相關命令的時候,我們再對它們作針對性的介紹。當.NET Core SDK安裝結束之後,我們可以運行dotnet命令來確認SDK是否安裝成功。如下圖1所示,我們執行dotnet --info命令查看當前安裝的.NET Core SDK的基本信息,其中包含SDK的版本、運行時環境和共用框架宿主的版本信息。

1-1

高效的開發自然離不開一個優秀的IDE,在這方面作為一個.NET程式員是幸福的,因為我們擁有宇宙第一個開發神器Visual Studio。雖然Visual Studio Code也不失為一個優秀的IDE,如果在絕大部分情況下Windows還是主要的開發環境,我個人還是推薦使用Visual Studio。當我們在敲這行文字的時候,Visual Studio的最新版本為2017(15.3)。順便說一下,Visual Studio已經提供了Mac版本。

Visual Studio Code是一個完全免費並且提供全平臺支持(Windows、Mac和Linux)的IDE,我們可以直接在其官網(https://code.visualstudio.com/)上下載。Visual Studio 2017提供了社區版(Community)、專業版(Professional)和企業版(Enterprise),其中社區版是免費的,專業版和企業版需要付費購買。Visual Studio的官網地址為https://www.visualstudio.com/。

除了Visual Studio和Visual Studio Code,我們還可以一款叫做Rider的IDE來開發.NET Core應用。Rider是著名的JetBrains公司開發的一款專門針對.NET的IDE,我們可以利用它來開發ASP.NET、.NET Core、Xmarin以及Unity應用。和Visual Studio Code一樣,Rider同樣也是個跨平臺的IDE,我們可以同時在Windows、Max OS X以及各種桌面版本的Linux Distribution上使用它。不過這不是一款免費的IDE,對它感興趣的朋友可以在官方站點(https://www.jetbrains.com/rider/)下載30天試用版。

二、利用命令行創建.NET Core程式

通過.NET Core SDK在本地安裝的dotnet 工具提供了基於預定義“腳手架(Scaffolding)”創建初始應用的命令(new)。如果需要開發某種類型的.NET Core應用,我們一般不會從第一行代碼寫起,而是利用這個命令幫助我們創建一個具有初始結構的應用。除此之外,在開發過程中如果需要添加某種類型的文件(比如各種類型的配置文件、MVC的視圖文件等),我們也可以利用該命令來完成,通過這種方式添加的文件具有預定義的初始內容。.NET Core SDK在安裝的時候為我們提供了一系列預定義的腳手架模板,我們可以按照如下圖所示的方式執行命令行“dotnet new list”列出當前安裝的腳手架模板。

1-2

上圖列出就是NET Core 2.0.0 SDK安裝後提供的16個預定義的腳手架模板,這些模板大致分為Project TemplateItem Template兩種類,前者為我們創建一個初始項目,後者則在一個現有項目中針對某種項目元素添加一個或者多個對應的文件。對於細心的讀者,可以從上圖中看到dotnet new命令具有一個--type參數,該參數具有三個預定義的選項(project、item和other),其中前兩個分別對應著Project和Item這兩種模板類型。

如果這些預定義的腳手架模板不能滿足我們的需求,我們還可以根據自身的需要創建自定義的Project或者Item模板,至於自定義模板的該如何定義,我們就不在這裡贅言介紹了,有興趣的讀者朋友可以參考.NET Core官方文檔(https://docs.microsoft.com/en-us/dotnet/core/tools/custom-templates)。我們創建的自定義模板最終體現為一個NuGet包,我們可以通過執行dotnet new -i或者dotnet new --install命令對其進行安裝。除此之外,對應已經安裝的模板,我們可以通過執行dotnet new -u或者dotnet new --uninstall命令卸載。

接下來我們利用dotnet new命令(dotnet new console -n helloworld)按照如下圖所示的方式創建一個名為“helloworld”的控制台程式。和傳統的.NET Framework應用,一個針對C#的.NET Core項目依然由一個對應的.csproj文件來定義,下圖所示的helloworld.csproj就是這麼一個文件。

1-3

對於傳統的.NET Framework應用來說,即使是一個空的C#項目,定義該項目的.csproj文件在內容和結構上顯得比較複雜。這個.csproj文件的結構並不是為一般的開發者設計的,我們也不會直接編輯這個文件,而是利用Visual Studio間接地修改它。但是對於一個.NET Core應用來說,這個.csproj文件的結構變得相對簡單並清晰了一些,以至於一般的開發人員可以直接編輯它。對於上面我們執行腳手架命令創建的控制台程式,定義項目的這個helloworld.csproj文件的完整內容如下。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>
</Project>

如上面的代碼片段所示,這個helloworld.csproj是一個根節點為<Project>的XML文件,與項目相關的屬性可以根據分組定義在相應的<PropertyGroup>節點下。對於這個helloworld.csproj文件來說,它實際上只定義了兩個屬性,分別是通過<OutputType>和<TargetFramework>節點表示的編譯輸出類型和目標框架類型。由於我們創建的是一個針對.NET Core 2.0的可執行控制台應用,所以目標框架為“netcoreapp2.0”,編譯輸出為Exe(對於Self Contained發佈模式)。

我們執行的dotnet new命令行除了幫助我們創建一個空的控制台程式之外,還會幫助我們生成一些初始化代碼,這就是項目目錄下的這個Program.cs文件的內容。如下所示的代碼片段給出了定義在這個文件的整個C#代碼的定義,我們可以看到它定義了代表程式入口點的Main方法,併在這個方法中將字元串“Hello World”列印在控制臺上。

using System;    
namespace helloworld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

雖然很簡單,但是我們通過執行腳手架命令行創建出來的是一個完成的.NET Core控制台應用,所以我們可以在無需對其作任何修改的情況下直接對它進行編譯和運行,針對.NET Core應用的編譯和運行同樣是利用這個dotnet.exe命令行來完成的。如下圖所示,在進入當前項目所在目錄之後,我們執行dotnet build命令對這個控制台應用實施編譯,由於預設採用Debug編譯模式,所以編譯生成的程式集(helloworld.dll)會保存在\bin\debug\目錄下。除此之外,針對不同目標框架編譯生成的程式集是不同的,所以最終生成的程式集會採用基於目標框架的目錄結構進行組織,所以最終生成的這個程式集被保存在“\bin\Debug\netcoreapp2.0\”目錄下。

1-4

編譯後的控制台程式可以直接通過執行dotnet run命令運行。如下圖所示,當我們在項目目錄下執行dotnet run命令後,編譯後的程式隨被執行,程式入口Main方法中指定的“Hello World”字元串被直接列印在控制臺上。其實當我們執行dotnet run命令啟動程式之前無需顯示執行dotnet build對源代碼實施便宜,因為該命令會自動觸發編譯操作。

1-5

三、改造成一個ASP.NET Core應用

我們在上面利用dotnet new命令創建了一個簡單的控制台程式,接下來我們將它改造成一個ASP.NET Core應用。一個ASP.NET Core應用構建在ASP.NET Core框架之上,後者利用一個管道式的構建完成了對HTTP請求的監聽、接收、處理和最終的響應,實際上本書的所有內容就是圍繞著管道展開的。ASP.NET Core管道由一個伺服器和若幹中間件構成,當宿主(Host)程式啟動之後,該管道被成功構建出來並利用伺服器開始HTTP請求的監聽。

從編程層面來看,ASP.NET Core管道的構建主要涉及WebHostWebHostBuilder這兩個對象。我們可以根據命名將WebHost理解為Web應用的宿主,WebHost是由WebHostBuilder構建出來的。一般來說,我們會先創建一個WebHostBuilder對象,並將最終管道構建所需的各項設置通過相應的方法(絕大部分是擴展方法)註冊到它上面。註冊完成之後,我們直接利用這個WebHostBuilder創建出對應的WebHost,當後者被啟動的時候,整個管道會根據我們預定義的設置被構建出來。

接下來我們直接利用Visual Studio 2017打開上面這個helloworld.csproj項目文件。為了在程式性中使用到上述這兩個對象,我們自然先得具有對應程式集的引用。對於.NET Core應用來說,所有的程式集都會封裝到相應的NuGet包中進行分發,如果需要消費某個框架或者類庫,我們都需要預先安裝相應的NuGet包。至於NuGet包的安裝,我們有很多的方式可以選擇。

安裝NuGet包

WebHostBuilder所在的程式集包含在Microsoft.AspNetCore.Hosting這個NuGet包中,接下來我們就以它為例介紹若幹中不同的NuGet包的安裝方式。如果使用Visual Studio 2017來開發.NET Core應用,我們最常使用的是由IDE提供的可視化NuGet安裝方式。如果按照這種安裝方式,我們只需要在“解決方案管理器(Solution Explorer)”視窗中右鍵選擇對應的項目或者項目下的“依賴(Dependencies)”節點,併在彈出的上下文菜單中選擇“管理NuGet包(Manage NuGet Packages)”選項就可以打開如下圖所示的“NuGet包管理視窗”。

1-6

如上圖所示,“NuGet包管理視窗”具有三個標簽頁,其中“安裝(Installed)”和“更新(Updates)”會列出當前項目已經安裝和可以升級的NuGet包。如果我們需要按照一個新的NuGet包,我們需要選擇第一個標簽頁,併在左上角的文本框中輸入需要安裝的NuGet包的全名或者全名的部分文字,與之相關的NuGet包將會篩選出來,如果目標NuGet包正好在該列表中,我們只需要選擇它並點擊右側的“安裝(Install)”按鈕即可。

除了採用上述這種完全可視化的方式來安裝NuGet包,Visual Studio還提供了一種命令行的安裝方式。包括安裝在內的NuGet包管理命令是在Visual Studio的“包管理器控制台(Package Manager Console)”視窗中輸入並執行的,我們可以通過菜單“工具(Tools)>選項(Options)>NuGet包管理器(NuGet Package Manager)>包管理器控制台(Package Manager Console)”開啟如下圖所示的這個視窗。如下圖所示,我們通過輸入並執行NuGet包安裝命令“Install-Package Microsoft.AspNetCore.Hosting -Version 2.0.0”安裝版本為2.0.0的NuGet包“Microsoft.AspNetCore.Hosting”。

1-7

除了上面介紹的這兩種在Visual Studio開發環境中提供的NuGet包的安裝放之外,我們已經很熟悉的這個dotnet命令行工具同樣提供了安裝NuGet包的支持。具體來說,我們可以執行dotnet add package命令安裝指定的NuGet包。如下圖所示,在確保當前為目標項目所在目錄的前提下,我們所需的NuGet包同樣可以通過執行“dotnet add package Microsoft.AspNetCore.Hosting --version 2.0.0”命令來完成。

1-8

有的情況下我們往往只知道某個需要使用的類型名稱而忘記了所在NuGet包的名字,如果你使用了Visual Studio 2017,可以藉助它提供的智能提示功能來安裝對應的NuGet包。很多人都體現過Visual Studio針對命名空間的自動補齊特性,當我們在C#編輯視窗直接輸入一個尚未導入命名空間的類型名稱的時候,一旦我們將滑鼠落在該類型上面的時候,Visual Studio會自動出現如下圖所示的“燈泡”圖標,點擊該圖標之後會出現一組候選的命名空間(這組候選命名空間菜單也可以通過快捷鍵Ctrl+Alt+F10開啟)。

1-9

這個特性在Visual Studio 2017上做了進一步改進。如果我們輸入了某個類型的名稱,但是所在的NuGet包尚未被安裝,Visual Studio可以利用這個特性智能地提示這個缺失的NuGet包的名稱。如下圖所示,在尚未安裝“Microsoft.AspNetCore.Hosting”這個NuGet包的情況下,我們在C#編輯視窗中輸入WebHostBuilder這個類型,Visual Studio會利用類似的特性提示我們安裝缺失的NuGet包。

1-10

對於對上述的眾多NuGet包的安裝方式,它們最終的目的實際上就是在描述當前項目的.csproj問文件中添加一個針對指定NuGet包的引用而已。如下所示的代碼片段代表“Microsoft.AspNetCore.Hosting”這個NuGet包被成功安裝後的內容,可以看出針對某個NuGet包的引用總是對應著.csproj文件中的某個< PackageReference>節點。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.0.0" />
  </ItemGroup>
</Project>

既然安裝NuGet包的最終目的就是在所在項目的.csproj文件中添加一條對應的< PackageReference>節點,那麼我們完全可以直接通過修改此文件的方式來完整針對NuGet包的安裝。在過去,如果我們想直接利用Visual Studio編輯某個項目對應的.cspro文件,我們必須先採用如下圖(左圖和中圖)的方式將對應的項目卸載。對於.NET Core應用開發來說,直接編輯項目文件已經變成了意見司空見慣的事情,所以Visual Studio 2017允許我們按照下圖(右圖)所示的方式直接對項目文件進行編輯。

1-11

對於.NET Core來說,提供API的程式集總是通過相應的NuGet包來提供,所以NuGet包的安裝成為了我們最為頻繁的操作之一。除此之外,我們在IDE上也有了更多的選擇,所以微軟提供了眾多NuGet包的管理方式供我們在不同的開發環境中選擇。綜上所述,我們可以通過如下的方式進行NuGet包的安裝:

  • 利用Visual Studio的NuGet包管理器(NuGet Package Manager)進行可視化安裝。
  • 在Visual Studio提供的包管理器控制台(Package Manager Console)以命令行的方式安裝NuGet包。
  • 通過執行dotnet add package以命令行的形式安裝NuGet包。
  • 通過修改定義項目的.csproj文件安裝的方式安裝NuGet包。

在介紹瞭如何安裝NuGet包之後,我們回到本行最初的話題:如何將通過腳手架命令創建的控制台應用轉化成一個ASP.NET Core應用。我們在前面已經提到過,ASP.NET Core應用建立在由一個伺服器和若幹中間件組成的管道上,最初對HTTP請求的監聽以及最終對該請求的響應都由伺服器完成。微軟為我們提供了若幹原生的伺服器供我們選擇,如果對應用具有跨平臺的要求,我們可以選擇一個名為KestrelHttpServer的伺服器。該伺服器類型定義在NuGet包“Microsoft.AspNetCore.Server.Kestrel”中,所以我們還需要安裝這個NuGet包。

註冊伺服器與中間件

在安裝了所需的NuGet包(“Microsoft.AspNetCore.Hosting”和“Microsoft.AspNetCore.Server.Kestrel”),我們對定義在Program.cs中的Main方法做瞭如下的改造,這應該算是一個最為簡單的ASP.NENT Core應用了。我們首先創建了一個WebHostBuilder對象並調用其擴展方法UseKestrel註冊了上述的這個類型為KestrelHttpServer的伺服器。接下來我們調用了WebHostBuilder的Configure方法,該方法接受一個Action<IApplicationBuilder>類型的委托對象作為參數,我們利用這個委托對象調用IApplicationBuilder的Run方法註冊了一個中間件,後者從事的唯一操作就是在響應中寫入了一個內容為“Hello World”的字元串。

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;

namespace helloworld
{
    class Program
    {
        static void Main()
        {
             new WebHostBuilder()                    
                .UseKestrel()
                .Configure(app => app.Run( async context => await context.Response.WriteAsync("Hello World")))
              .Build()
              .Run();
        }
    }
}

在將所需的伺服器和中間件註冊到創建的WebHostBuilder對象之後,我們調用其Build方法創建了對應的WebHost對象, 當我們調用後者的Run方法之後,真正的ASP.NET Core管道被構建出來。由於註冊的KestrelHttpServer伺服器預設採用5000作為監聽埠,所以程式在啟動之後將綁定在這個埠監聽抵達的HTTP請求。如果利用瀏覽器訪問http://localhost:5000,我們會得到由註冊中間件寫入的“Hello World字元串”。

1-12

如果預設使用的5000埠不可用,或者不希望使用這個預設的埠,我們還可以調用WebHostBuilder的擴展方法UseUrls註冊新的監聽地址。值得一提的是,我們可以同時指定多個監聽地址,下麵的代碼片段就為KestrelHttpServer分別註冊了兩個埠號分別為6666和8888的監聽地址。

new WebHostBuilder()    
    .UseUrls("http://localhost:6666", "http://localhost:8888")
    .UseKestrel()
    .Configure(app => app.Run(async context => await context.Response.WriteAsync("Hello World")))
    .Build()
    .Run();

四、進一步改造成ASP.NET Core MVC應用

對於我們在上面一節創建的這個極簡ASP.NET Core應用來說,它對應的管道由一個伺服器和一個中間件組成,前者的類型為KestrelHttpServer,後者則將每個請求的響應內容統一設置為“Hello World”字元串。接下來我們對該應用做進一步地改造,將它轉變成一個ASP.NET Core MVC應用。整個ASP.NET Core MVC框架建立在一個名為RouterMiddleware的中間件上,它利用該中間件提供的路由功能實現了請求URL與目標Controller類型以及Action方法之間的映射,並再此基礎上實現了諸如Controller的激活、Action方法的執行以及View的呈現等操作。

整個ASP.NET Core MVC框架實現在“Microsoft.AspNetCore.Mvc”這個NuGet包中,所以我們先得將它安裝到我們的控制台項目上,然後才能進行針對ASP.NET Core MVC的編程。不過在這之前我們需要瞭解一個關於“依賴註入(Dependency Injection)”。ASP.NET Core框架內置了一個原生的依賴註入框架,後者利用一個DI容器提供管道在構建以及進行HTTP請求處理過程中所需的所有服務,而這些服務需要在應用啟動的時候被預先註冊。對於ASP.NET Core MVC框架來說,它在處理HTTP請求的過程中所需的一系列服務同樣需要預先註冊。對這個概念有了基本的瞭解之後,相信讀者朋友們對如下所示的代碼就容易理解了。

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;

namespace helloworld
{
    class Program
    {
        static void Main(string[] args)
        {
            new WebHostBuilder()
                .UseKestrel()
                .ConfigureServices(svcs => svcs.AddMvc())
                .Configure(app => app.UseMvc())
                .Build()
                .Run();
        }
    }

    public class HelloController
    {
        [HttpGet("/hello")]
        public string SayHello()
        {
            return "Hello World";
        }
    }
}

如果說上面一節創建的屬於最簡單的ASP.NET Core應用的話,那麼通過上面這段代碼創建的恐怕就是一個簡單的ASP.NET Core MVC應用了。我們在這個程式中調用了WebHostBuilder的方法ConfigureServices(這是一個擴展方法,其參數類型為Action<IServiceCollection>)註冊ASP.NET Core MVC框架所需的服務,具體來說這些服務是通過調用IServiceCollection介面的擴展方法AddMvc來完成的。在針對Configure方法的調用中,我們調用IApplicationBuilder的擴展方法UseMvc註冊了RouterMiddleware中間件以及針對ASP.NET Core MVC的路由處理器,後者接收路由分發的HTTP請求和路由參數,併在此基礎上實現對Controller的激活、Action方法的執行以及View的呈現等操作。

HelloController是我們定義的Controller類型。按照約定,所有的Controller類型名稱都應該以“Controller”字元作為尾碼。與之前版本的ASP.NET MVC不同的是,ASP.NET Core MVC下的Controller類型並不要求強制繼承某個基類。在HelloController中,我們定義了一個唯一無參Action方法SayHello,該方法直接返回一個內容為“Hello World”的字元串。我們在這個方法上利用HttpGetAttribute註冊了一個模板為“/hello”的路由,意味著請求地址為“/hello”的GET請求最終會被路由到這個Action方法上,後者執行的結果將作為請求的響應內容。所以啟動該程式後使用瀏覽器訪問地址“http://localhost:5000/hello”,我們依然會得到如圖1-13所示的輸出結構。

1-13

引入View

上面這個程式並沒有涉及View,所以算不上一個典型的ASP .NET Core MVC,接下來我們對它做進一步改造。在前面介紹如何安裝NuGet包的時候,我們曾經查看過定義項目的 .csproj文件的內容,實際上這是一個以<Project>作為根節點的XML文件。作為根節點的<Project>元素具有一個Sdk的屬性表示當前項目針對的SDK,不同的SDK在編譯發佈等方面對項目提供了不同的支持。當我們安裝了.NET Core SDK的時候,這些針對項目的SDK將被安裝在“%programfiles% \dotnet\sdk\{version}\Sdks”目錄下(如下圖所示)。

1-14

對於上面這個通過腳手架命令行創建的控制台應用來說,它預設採用的SDK為“Microsoft.NET.Sdk”。如果我們需要為這個應用添加View,這個SDK並不能提供針對View的動態編譯功能(在運行時動態編譯使用到的View,而不是在部署的時候將所有View進行預編譯),所以我們按照如下的方式編輯.csproj文件將SDK切換為“Microsoft.NET.Sdk.Web”。實際上不論是我們利用Visual Studio還是命令行創建的ASP.NET Core應用,項目都會採用這個SDK。

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" />
  </ItemGroup>
</Project>

在對SDK作了相應修改之後,我們對現有的程式作瞭如下的改造。當編譯器在對View進行動態編譯的時候,需要按照預定義的路徑去定位定義View的.cshtml文件,這些預定義的候選路徑都是相對路徑,所以我們需要預先指定一個基礎路徑,該路徑可以通過調用WebHostBuilder的擴展方法UseContentRoot來指定。如下麵的代碼片段所示,我們將當前路徑(當前項目的根目錄)作為這個基礎路徑。

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using System.IO;

namespace helloworld
{
    class Program
    {
        static void Main()
        {
            new WebHostBuilder()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseKestrel()
                .ConfigureServices(svcs => svcs.AddMvc())
                .Configure(app => app.UseMvc())
                .Build()
                .Run();
        }
    }

    public class HelloController: Controller
    {
        [HttpGet("/hello/{name}")]
        public IActionResult SayHello(string name)
        {
            ViewBag.Name = name;
            return View();
        }
    } 
}

為了讓HelloController具有View呈現的能力,我們讓它派生於基類Controller。Action方法SayHello的返回類型被修改為IActionResult介面,後者表示Action方法執行的結果。除此之外,我們為該方法定義了一個表示姓名的參數name,通過HttpGetAttribute特性註冊的路由模板(“/hello/{name}”)中具有與之對應的路由參數。換句話說,滿足該路由規則的請求URL攜帶的命名將自動綁定為該Action方法的name參數。具體在SayHello方法中,我們利用ViewBag將代碼姓名的name參數的值傳遞給將要呈現出來的View,該View正式執行View方法返回的結果。

由於我們調用View方法時並沒有顯式指定名稱,ASP.NET Core MVC的View引擎會自動將當前Action的名稱(“SayHello”)作為View的名稱。如果該View還沒有經過編譯(部署時針對View的預編譯,或者在這之前針對該View的動態編譯),View引擎將從若幹候選的路徑中讀取對應的.cshtml 文件進行編譯,其中首選的路徑為“{ContentRoot}\Views\{ControllerName}\{ViewName}.cshtml”。為了迎合View引擎定位View文件的規則,我們需要將SayHello對應的View文件(SayHello.cshtml)定義在目錄“\Views\Hello\”下(如下圖所示)。

1-15

如下所示的就是SayHello.cshtml這個文件的內容,這是一個針對Razor引擎的View文件。從文件的擴展名(.cshtml)我們可以這樣的文件可以同時包含HTML標簽和C#代碼。總的來說,View文件最終是為了在服務端渲染出最終在瀏覽器呈現出來的HTML,我們可以在這個文件中直接編寫原樣輸出的HTML標簽,也可以內嵌一段動態執行的C#代碼。雖然Razor引擎對View文件的編寫制定了嚴格的語法,但是我個人覺得沒有必要在Razor語法上花太多的精力,因為Razor語法的目的就是讓我們很“自然”地融合動態C#代碼和靜態HTML標簽來定義最終在客戶端渲染的HTML文檔,因此它的語法和普通的思維基本上是一致。比如下麵這個View最終會生成一個完整的HTML文檔,其主體部分只有一個<h3>標簽。該標簽的內容是動態的,因為包含從Controller利用ViewBag傳進來的姓名。

<html>
<head>
    <title>Hello World</title>
</head>
<body>
      <h3>Hello, @ViewBag.Name</h3>
</body>
</html>

再次運行該程式後,我們利用瀏覽器訪問地址“http://localhost:5000/hello/foobar”。由於請求地址與Action方法SayHello上的路由規則相匹配,所以URL上的foobar會被解析為姓名綁定到該方法的name參數上,所以我們最終將在瀏覽器上得到如下圖所示的輸出結果。

1-16

利用Startup註冊服務和中間件

對於幾乎所有的ASP.NET Core應用來說,應用啟動過程中必須完成的初始化操作都包括服務與中間件的註冊。在上面演示的實例中,我們都是直接調用WebHostBuilder的ConfigureServices和Configure方法來完成針對服務和中間件的註冊,但是在大部分真實的開發場景中,我們一般會將這兩種類型的註冊定義在一個單獨的類型中。按照約定,我們通常會將這個類型命名為Startup,比如我們演示實例中針對ASP.NET Core MVC的服務註冊和中間件註冊就可以放在如下定義的這個Startup類中。

public class Startup
{
    public void ConfigureServices(IServiceCollection svcs)
    {
        svcs.AddMvc();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc();
    }
}

如上面的代碼片段所示,我們不需要讓Startup類實現某個預定義的介面或者繼承某個預定義基類,所採用的完全是一種“約定”,隨著對ASP.NET Core框架認識的加深,我們會發現這種“約定優於配置”的設計廣泛地應用在整個框架之中。按照約定,服務註冊和中間件註冊分別實現在ConfigureServices和Configure方法中,它們第一個參數類型分別為IServiceCollection和IApplicationBuilder介面。現在已經將兩種核心的註冊操作轉移到了上面這個Startup類中,那麼我們需要將該類型按照如下的方式調用UseStartup<T>方法註冊到WebHostBuilder上即可。

new WebHostBuilder()
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseKestrel()                     
    .UseStartup<Startup>()
    .Build()
    .Run();


.NET Core多平臺開發體驗

.NET Core多平臺開發體驗[1]: Windows
.NET Core多平臺開發體驗[2]: Mac OS X
.NET Core多平臺開發體驗[3]: Linux
.NET Core多平臺開發體驗[4]: Docker


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文是經驗帖,以後遇到類似的情況會持續更新到這篇文章 普通用戶使用sudo會遇到一下情況 1.無法寫入 /var/log/messages /var/log/secure 2.無法使用字元重定向在 /etc/security/limit.d 目錄下新建文件 3.無法將字元流重定向到 /etc/gru ...
  • SELinux是美國國家安全局(NSA)對於強制訪問控制的實現,是 Linux歷史上最傑出的新安全子系統。但是SELinux的並不能與眾多服務很好的相容,有些人會關閉SELinux一了百了。在日常的運維過程中很少去頻繁的開啟關閉SElinux,今天我就寫一個關閉與開啟SELinux的腳本來鍛煉我的腳 ...
  • 話不多說, 直接上教程. 首先備份/etc/yum.repos.d/CentOS Base.repo 下載對應版本repo文件, 放入/etc/yum.repos.d/(操作前請做好相應備份) 運行以下命令生成緩存 參考: "CentOS鏡像使用幫助" ...
  • 用apt-get安裝軟體時提示: 無法獲得鎖 /var/lib/dpkg/lock - open(11:資源暫時不可用) 無法鎖定管理目錄(/var/lib/dpkg/),是否有其他進程正占用它? 其實報錯已經給了提示了,就是有進程正在占用apt-get命令,So... 命令跑起來,找出這個進程,k ...
  • 一、OpenTSDB簡介 開源監控系統OpenTSDB,用hbase存儲所有的時序(無須 採樣)來構建一個分散式、可伸縮的時間序列資料庫。它支持秒級數據採集所有metrics,支持永久存儲,可以做容量規劃,並很容易的接入到現有的報警系 統里。OpenTSDB可以從大規模的集群(包括集群中的網路設備、 ...
  • linux打包壓縮和解壓縮命令大全 linux壓縮和解壓縮命令大全 tar命令 解包:tar zxvf FileName.tar 打包:tar czvf FileName.tar DirName tar命令 解包:tar zxvf FileName.tar 打包:tar czvf FileName. ...
  • 在伺服器端 Web 應用程式框架中,其中非常重要的設計是開發人員如何將URL與伺服器上的資源進行匹配,以便正確的處理請求。最簡單的方法是將 URL 映射到磁碟上的物理文件,在 Razor 頁面框架中,ASP.NET團隊就是這樣實現的。 關於 Razor 頁面框架如何將 URL 與文件相匹配,有一些規 ...
  • 上篇有朋友提及到如果nginx做集群後應該還會有下一篇文章主講session控制,一般來說就是登陸;本篇分享的內容不是關於分散式session內容,而是netcore自帶的授權Authorize,Authorize粗略的用法,希望能對大家有好的幫助; web網站session和cookie關係 在N ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...