整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          使用 ASP.NET Core 構建 Web API

          使用 ASP.NET Core 構建 Web API:2 我們的第一個 Web API 項目


          章涵蓋

          • 查看系統要求
          • 選擇和安裝集成開發環境 (IDE)
          • 創建新的 ASP.NET Web API 項目
          • 配置項目的啟動和設置文件
          • 調試、測試和改進我們的第一個項目

          在本章中,我們將創建MyBGList Web API,這是我們在第1章中介紹的面向服務的體系結構具體方案的基石。更具體地說,我們將穿上負責創建和設置項目的軟件開發團隊的鞋子。我們必須做出一些高級決策,例如選擇要采用的集成開發環境 (IDE),然后切換到更實用的方法,例如首次獲取源代碼,以及調試和測試它以確保它按預期工作。

          在本章結束時,您將能夠通過解決有關所涵蓋主題和概念的一些總結練習來測試您的知識。主要目標是創建一個工作 ASP.NET Web API 項目,你將在以下章節中擴展和改進該項目。

          2.1 系統要求

          由于我們已經選擇使用 ASP.NET Core 開發 Web API,因此回顧一下系統要求(我們需要安裝什么才能開始開發之旅)可能會很有用。

          2.1.1 .NET 開發工具包

          要獲取的最重要的工具是 .NET 軟件開發工具包(更廣為人知的 .NET SDK),其中包含 .NET 命令行界面 (.NET CLI)、.NET 庫和三個可用的運行時:

          • ASP.NET 核心運行時,運行 ASP.NET 核心應用所必需的
          • 桌面運行時,運行 WPF 和 Windows 窗體應用所必需的
          • .NET 運行時,承載前兩個運行時所需的一組低級庫和接口

          注意.NET SDK 可作為適用于 Windows、Linux 和 macOS 的獨立包提供,網址如下:https://dotnet.microsoft.com/download。

          2.1.2 集成開發環境

          從嚴格的角度來看,安裝.NET SDK是我們開始構建任何類型的.NET應用程序所需要做的就是,包括我們的 ASP.NET Core Web API。但是,使用 Windows、Linux 或 macOS 中可用的內置工具(例如默認文本編輯器和命令行終端)編寫源代碼遠非理想。經驗豐富的開發人員可以自豪地說他們可以通過使用記事本,Emacs或vim做任何事情的日子早已一去不復返了。事實上,現代 IDE 包含大量有用的功能,這些功能無疑會提高任何愿意學習如何高效利用它們的軟件開發人員的生產力。我不只是在談論語法突出顯示、代碼完成和其他“外觀”功能。現代 IDE 之所以出色,是因為它們能夠提供工具和擴展,使開發團隊能夠標準化和自動化某些流程,從而支持面向 DevOps 的方法:任務運行器、包管理器、代碼檢查器、集成源代碼控制、自動部署系統、安全憑據存儲、語法突出顯示等等。

          出于所有這些原因,因為我們想設身處地為MyBGList軟件開發團隊著想,我們將使用IDE(或具有高級功能的代碼編輯器)構建我們的Web API。Microsoft提供了兩種選擇:

          • Visual Studio - Visual Studio 是適用于 Windows 和 macOS 的綜合 .NET 開發解決方案,包括編譯器、代碼完成工具、圖形設計器和許多有用的功能,用于增強軟件開發體驗和生產力。
          • Visual Studio Code - Visual Studio Code 是一個適用于 Windows、Linux 和 macOS 的輕量級開源代碼編輯器。與專注于.NET開發的Visual Studio不同,該產品采用與框架無關,與語言無關的方法。但它提供了一個豐富的擴展生態系統,以添加對大多數開發框架和編程語言的支持,包括 ASP.NET Core和C#。

          注意許多非Microsoft替代品值得一提,例如JetBrains的Rider和Adobe的Brackets。但是,為了簡單起見,我們將分析限制為Microsoft開發工具。

          Visual Studio 和 Visual Studio Code 都可用于創建、配置和維護 ASP.NET Web API 項目。但是,由于我們希望在完成任務時充分探索.NET和 ASP.NET Core框架,因此我們將選擇Visual Studio。具體來說,我們將使用 Visual Studio 2022,這是撰寫本文時可用的最新版本。

          注意如果你想使用Visual Studio Code或其他編輯器,不要擔心。本書中的所有代碼示例,以及 GitHub 存儲庫中提供的所有內容,也將在這些編輯器中工作。

          2.2 安裝 Visual Studio

          Visual Studio 2022 有三個版本,每個版本都有一組特定的受支持功能:

          • 社區版具有創建、開發、調試、測試和發布各種 .NET 應用所需的所有功能。此版本是免費使用的,但它只能用于開源項目、學術研究和課堂學習,以及不超過五名開發人員的非企業組織。
          • 專業版具有社區版的所有功能,并且付費許可的限制較少。
          • 企業版具有其他兩個版本的所有功能,以及一些高級架構級別的設計、驗證、分析和測試工具。

          注意就本書而言,您有權通過以下網址下載并安裝社區版:https://visualstudio.microsoft.com。

          Visual Studio 安裝過程分為三個階段:

          1. 下載并安裝 Visual Studio Installer,它充當整個 Visual Studio 系列的安裝和更新管理工具。
          2. 選擇工作負載、單個組件和語言包。每個工作負載都包含我們要使用的框架、編程語言和平臺所需的一組組件。在我們的場景中,由于我們要開發 ASP.NET 核心 Web API,因此我們只需要安裝 ASP.NET 和 Web 開發工作負載(參見圖 2.1),而無需安裝其他單個組件 — 至少目前是這樣。語言包取決于我們希望如何設置圖形用戶界面 (GUI) 使用的語言。
          3. 安裝 Visual Studio 2022 以及選定的工作負載、組件和語言包。


          圖 2.1 將 ASP.NET 和 Web 開發工作負載添加到 Visual Studio 安裝

          注意如果您是第一次閱讀本書,安裝英語語言包可能是一個不錯的選擇,以便 IDE 命令始終與示例和屏幕截圖匹配。

          2.3 創建網頁接口項目

          當我們在系統上安裝了 .NET SDK 和 Visual Studio 2022 時,我們可以開始創建我們的第一個 Web API 項目。執行以下步驟:

          1. 啟動 Visual Studio 2022。
          2. 選擇“創建新項目”選項。
          3. 使用搜索框查找 ASP.NET 核心 Web API 項目模板,如圖 2.2 所示。


          圖 2.2 在 Visual Studio 中查找 ASP.NET 核心 Web API 項目模板


          配置模板相當容易。在我們的場景中,我們給項目命名 MyBGList,并接受其他默認設置,如圖 2.3 所示。請務必選擇 .NET 6.0 框架,這是撰寫本文時可用的最新版本。


          圖 2.3 配置 ASP.NET 核心 Web API 項目

          警告如果要使用其他 .NET 版本,可以自由執行此操作。但請記住,本書中的某些源代碼示例可能需要進行一些更改才能使用框架更新和/或重大更改。

          單擊“創建”按鈕后,Visual Studio 將立即為新的 MyBGList 項目生成源代碼,將其添加到具有相同名稱的解決方案中,然后在 IDE 中打開它。一切就緒!

          在繼續之前,讓我們快速檢查一切是否正常。按 F5 鍵(或單擊最上面的工具欄中的“運行”按鈕)以在調試模式下啟動項目。如果我們正確執行了所有操作,Visual Studio 應該自動啟動我們的默認瀏覽器,指向 https:/ /localhost:<someRandomPort> 并顯示圖 2.4 中顯示的頁面。


          圖2.4 MyBGList項目首次運行

          正如我們所看到的,我們用于創建項目的Visual Studio Web API模板提供了一個簡潔的起始頁,其中提到了Swagger,這是一個描述API結構的便捷工具。我將在本章后面介紹 Swagger。現在,我們已準備好更好地了解我們的項目。

          在我們開始編碼之前,可能值得討論項目和解決方案以及它們在Visual Studio生態系統中扮演的角色。簡而言之,我們可以說

          • 項目是一組源代碼文件,通常與一些(必需的)配置文件和一堆(可選)內容文件(如圖標、圖像和數據文件)一起編譯到可執行文件、庫或網站中。MyBGList項目包括一小組由Visual Studio生成的.cs和.json文件,用于使用我們選擇的配置設置創建我們的 ASP.NET Web API。
          • 解決方案是我們可以用來組織一個或多個相關項目的容器。當我們打開一個解決方案時,Visual Studio 會自動打開該解決方案包含的所有項目。在我們的方案中,該解決方案僅包含我們的 MyBGList Web API 項目并共享其名稱。

          在以下章節中,我們將向解決方案中添加其他項目。具體來說,我們將創建一些類庫,我們希望將其與 Web API 項目分開,以便我們可以在其他地方使用它們。這種方法提高了代碼的可重用性,同時讓我們有機會在同一 IDE 窗口中對項目進行邏輯分組和訪問。

          2.4 MyBGList項目概述

          現在我們已經了解了Visual Studio的基礎知識,讓我們花一些寶貴的時間來回顧我們全新的Web API項目的自動生成源代碼。默認的 ASP.NET Core Web API 模板提供了一個最小但方便的樣板,可用于理解典型項目的基本結構,這正是我們在開始編寫與棋盤游戲相關的 Web API 之前需要做的。

          讓我們從項目的文件結構開始。在“解決方案資源管理器”窗口中,我們看到項目包含一些重要文件:

          • launchSettings.json(在 /Properties/ 文件夾中)- 包含用于在開發模式下啟動項目的設置
          • appsettings.json - 包含所有環境的應用程序配置設置以及嵌套的應用程序設置。Development.json,僅包含特定于開發環境的設置
          • program.cs - 第 1 章中介紹的引導類
          • 天氣預報控制器.cs - 顯示如何提供一些虛擬天氣預報數據的示例控制器
          • WeatherForecast.cs - 控制器使用強類型方法提供示例天氣預報 JavaScript 對象表示法 (JSON) 數據的最小數據傳輸對象 (DTO) 類

          在下一節中,我們將簡要回顧所有這些文件,以了解它們的用途以及它們在樣板文件中扮演的角色。在執行代碼審查時,我們還將對一些默認行為進行一些小而重要的更新,以更好地滿足我們的需求。最終,我們將用我們自己的棋盤游戲主題類替換與天氣預報相關的樣板文件。

          2.4.1 查看launchSettings.json

          要查看的第一個文件是 launchSettings.json,位于 /Properties/ 文件夾中。顧名思義,此文件包含一些與項目啟動方式相關的配置設置。但是,請務必了解,此文件以及包含的所有設置將僅在本地開發計算機中使用。換句話說,當我們在生產服務器上發布項目時,它不會與我們的應用一起部署。正如我們通過打開它看到的那樣,配置設置分為三個主要部分(或 JSON 鍵):

          • “$schema”- 指向描述文件所用架構的 URL
          • “iisSettings” - 包含 IIS Express Web 服務器的一些基本配置設置
          • “配置文件”- 分為兩個子部分:
            • “IIS Express ”- 包含 IIS Express Web 服務器的其他設置
            • “MyBGList”—包含特定于 Kestrel Web 服務器的設置

          如果你不知道IIS Express和Kestrel是什么,讓我們快速回顧一下背景故事。ASP.NET Core 為兩個可用于本地開發的 Web 服務器提供內置支持:

          • IIS Express—Internet Information Services (IIS) Web 服務器的輕量級版本,自 Windows XP 和 Visual Studio 2012 起可用
          • Kestrel - 一個開源、跨平臺、事件驅動的異步 HTTP 服務器實現,隨 ASP.NET Core 的第一個版本一起引入

          注意在Visual Studio 2010及更早版本中,用于開發目的的默認Web服務器是 ASP.NET 開發服務器,通常稱為Cassini。

          我們可以通過單擊“開始”按鈕右側的箭頭處理程序來選擇在 Visual Studio 中運行應用時要使用的 Web 服務器。此處理程序是 Visual Studio 頂級工具欄上帶有綠色箭頭的按鈕,如圖 2.5 所示。


          圖 2.5 Visual Studio 的“開始”按鈕

          應用名稱的選項(在我們的方案中為 MyBGList)對應于 Kestrel。如我們所見,我們還可以選擇要使用的Web瀏覽器,以及現在可以跳過的其他一些選項。

          launchSettings.json 文件的 iisSettings 和配置文件部分包含 IIS Express 和 Kestrel 的配置設置。對于每個服務器,我們可以選擇要使用的 HTTP 和 HTTPS 端口、啟動 URL、啟動應用程序之前要設置的環境變量等。

          如圖 2.5 所示,如果我們現在單擊“開始”按鈕(或選擇“調試”>“開始調試”或按 F5),我們將看到 SwaggerUI 頁面,該頁面處理在兩個瀏覽器的 launchUrl 選項中配置的 swagger 終結點。請注意,無論我們選擇哪個 Web 服務器,都會顯示圖 2.4 中顯示的 SwaggerUI 頁面,因為瀏覽器已配置為使用該端點。唯一明顯改變的是用于建立HTTPS連接的本地TCP端口,因為Visual Studio在創建項目時隨機確定它們。讓我們借此機會規范化這些端口。

          注意我們將在后面的章節中廣泛使用 SwaggerUI 頁面及其內容,同時實現我們的示例 Web API。此外,第11章深入討論了Swagger。

          打開 launchSettings.json 文件,并更改其內容,如以下清單所示。更新的行和值以粗體顯示。

          清單 2.1 修改了 launchSettings.json 文件

          {
            "$schema": "https://json.schemastore.org/launchsettings.json",
            "iisSettings": {
              "windowsAuthentication": false,
              "anonymousAuthentication": true,
              "iisExpress": {
                "applicationUrl": "http://localhost:40080",                         ?
                "sslPort": 40443                                                    ?
              }
            },
            "profiles": {
              "MyBGList": {
                "commandName": "Project",
                "dotnetRunMessages": true,
                "launchBrowser": true,
                "launchUrl": "swagger",                                             ?
                "applicationUrl": "https://localhost:40443;http://localhost:40080", ?
                "environmentVariables": {                                           ?
                  "ASPNETCORE_ENVIRONMENT": "Development"
                }
              },
              "IIS Express": {
                "commandName": "IISExpress",
                "launchBrowser": true,
                "launchUrl": "swagger",                                             ?
                "environmentVariables": {                                           ?
                  "ASPNETCORE_ENVIRONMENT": "Development"
                }
              }
            }
          }

          ? IIS Express 本地 URL 和 TCP 端口,用于 HTTP 和 HTTPS

          ? Kestrel 本地 URL 和 TCP 端口,用于 HTTP 和 HTTPS

          ? 紅隼起始頁

          ? 紅隼環境變量

          ? IIS Express 起始頁

          ? IIS 快速環境變量

          正如我們所看到的,我們已經為IIS Express和Kestrel設置了40080(HTTP)和40443(HTTPS)TCP端口。這個簡單的調整確保了本書中引用的URL在我們的本地代碼庫中正常工作,無論我們要使用的Web服務器如何。

          內置 launchSettings.json 文件中指定的其余設置暫時足夠好,因此我們可以保留它們。但是,在關閉文件之前,讓我們仔細看看“環境變量”部分,其中包含IIS Express和Kestrel的單個ASPNETCORE_ENVIRONMENT環境變量。

          2.4.2 配置應用設置.json

          讓我們轉到 appsettings.json 文件,該文件將應用程序配置設置存儲在 JSON 鍵值對中。如果我們查看MyBGList Web API項目的自動生成代碼,我們可以看到Visual Studio創建了該文件的兩個實例:

          • appsettings.json
          • 應用設置。開發.json

          在了解這些文件的工作原理之前,探索 ASP.NET Core 中的運行時環境的概念可能會很有用。

          運行時環境

          Web 應用程序開發通常至少涉及三個主要階段:

          • 開發,軟件開發人員在其中執行調試會話
          • 暫存,其中選定的一組用戶(或測試人員)執行內部和/或外部測試
          • 生產,其中應用可供最終用戶使用

          根據 .NET 約定,這些階段稱為環境,可以使用應用執行上下文中的DOTNET_ENVIRONMENT和/或ASPNETCORE_ENVIRONMENT環境變量進行設置。每當我們啟動應用程序時,我們都可以通過相應地設置該環境變量來選擇要面向的運行時環境。

          提示如果我們還記得 launchSettings.json 文件的 “environmentVariables” 部分,我們已經知道如何在本地開發機器中設置 ASPNETCORE_ENVIRONMENT 變量。我們將在第 12 章部署 Web API 時學習如何在生產服務器中執行此操作。

          應用設置文件

          現在我們知道了所有這些,我們可以很容易地理解這兩個appsettings文件的用途:

          • appsettings.json 旨在存儲將由所有運行時環境使用的配置設置,除非它們被特定環境特定的文件覆蓋或補充。
          • 應用設置。Development.json就是其中之一。放置在那里的設置將僅由開發環境使用(并被任何其他環境忽略),覆蓋和/或集成 appsettings.json “通用”文件中存在的設置。

          警告特定于環境的文件將在通用版本之后讀取,從而覆蓋其中存在的任何鍵值對。換句話說,如果我們使用開發環境運行我們的應用程序,則應用程序設置中存在每個鍵值對。Development.json 將被添加到 appsettings.json 文件中存在的鍵值對中,如果它們已經設置,則替換它們。

          如果我們查看這兩個 appsettings 文件,我們會看到一堆與日志相關的設置(在日志記錄 JSON 鍵中),我們現在可以忽略這些設置。我們將有機會在第7章討論日志記錄技術時與他們一起玩。我們現在能做的是添加一個新的鍵/值對,以后可以幫助我們。打開 appsettings.json 文件,并將以下行(粗體)添加到現有 JSON 中:

          {
            "Logging": {
              "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning"
              }
            },
            "AllowedHosts": "*",
            "UseDeveloperExceptionPage": false
          }

          這個新的配置設置將為我們提供一些 appsettings 文件的練習,還允許我們在稍后將實施的實現技術之間切換。

          2.4.3 玩程序.cs文件

          讓我們轉到程序.cs文件,我們在第 1 章中簡要介紹了該文件。我們已經知道,此文件在應用程序開始時執行,以注冊和配置所需的服務和中間件來處理 HTTP 請求和響應管道。

          事實上,由 ASP.NET Web API 模板創建的默認 Program.cs 文件與我們在第 1 章中看到的相同,因此我們不會在其中找到任何新內容。通過簡要回顧一下,我們可以清楚地看到我們的 Web API 要使用的服務和中間件,如以下列表所示。

          清單 2.2 Program.cs文件

          var builder=WebApplication.CreateBuilder(args);
           
          // Add services to the container.
           
          builder.Services.AddControllers();              ?
          // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
          builder.Services.AddEndpointsApiExplorer();     ?
          builder.Services.AddSwaggerGen();               ?
           
          var app=builder.Build();
           
          // Configure the HTTP request pipeline.
          if (app.Environment.IsDevelopment())
          {
              app.UseSwagger();                           ?
              app.UseSwaggerUI();                         ?
          }
           
          app.UseHttpsRedirection();                      ?
           
          app.UseAuthorization();                         ?
           
          app.MapControllers();                           ?
           
          app.Run();

          ? 控制器服務和中間件

          ? 招搖服務和中間件

          ? HTTP 到 HTTPS 重定向中間件

          ? ASP.NET 核心授權中間件

          ? 控制器服務和中間件

          當我們在這里時,讓我們借此機會添加一些有用的中間件,以幫助我們更好地處理錯誤和異常。

          異常處理

          在Program.cs文件中找到以下代碼:

          if (app.Environment.IsDevelopment())
          {
              app.UseSwagger();
              app.UseSwaggerUI();
          }

          將其替換為以下內容(以粗體標記的更改):

          if (app.Environment.IsDevelopment())
          {
              app.UseSwagger();
              app.UseSwaggerUI();
              app.UseDeveloperExceptionPage();
          }
          else
          {
              app.UseExceptionHandler("/error");
          }

          正如我們所看到的,我們在 HTTP 管道中添加了新的中間件。僅當應用在開發環境中運行時,才會包含第一個添加項;第二個添加將僅存在于過渡和生產環境中。以下是此中間件的詳細操作:

          • DeveloperExceptionPageMiddleware - 顧名思義,此中間件從 HTTP 管道捕獲同步和異步異常,并生成一個 HTML 錯誤頁面(開發人員異常頁面),其中包含有關異常的有用信息,例如堆棧跟蹤、查詢字符串參數、Cookie 和標頭。此信息可能會向潛在攻擊者暴露配置設置或漏洞。出于這個原因,我們只在開發環境中使用它,以便這些有用但可能有害的信息僅供開發人員使用。
          • 異常處理中間件 - 此中間件還處理 HTTP 級別的異常,但更適合非開發環境,因為它將所有相關的錯誤信息發送到可自定義的處理程序,而不是生成詳細的錯誤響應并自動將其呈現給最終用戶。

          現在,盡管 DeveloperExceptionPageMiddleware 開箱即用,不需要任何額外的工作,但 ExceptionHandlingMiddleware 要求我們實現一個專用的處理程序。正如我們通過查看代碼所看到的,我們已經傳遞了 /error string 參數,這意味著我們希望使用我們需要實現的專用 HTTP 路由來處理這些錯誤。

          正如我們在第 1 章中已經知道的,我們有兩種方法可以做到這一點:使用控制器或使用最小 API。讓我們看看它們,然后選擇最有效的一個。

          使用控制器

          讓我們從基于控制器的方法開始。從 Visual Studio 的解決方案資源管理器中,執行以下步驟:

          1. 右鍵單擊 MyBGList 項目的“控制器”文件夾,然后選擇“添加>控制器”。將打開一個彈出窗口,要求我們選擇要添加的控制器。
          2. 導航到左側樹視圖中的“通用> API ”節點,選擇“API 控制器 - 空”選項,然后單擊“添加”按鈕。
          3. 將新控制器命名為 ErrorController.cs,然后單擊“確定”創建它。

          我們將看到新的 ErrorController.cs 文件的內容:一個空類,我們可以用來添加我們的操作方法 — 具體來說,我們需要處理 /error/ 路由的操作方法,我們的 ExceptionHandlingMiddleware 將轉發 HTTP 錯誤。下面是我們需要的操作方法的最小實現:

          using Microsoft.AspNetCore.Mvc;
           
          namespace MyBGList.Controllers
          {
              [ApiController]
              public class ErrorController : ControllerBase
              {
                  [Route("/error")]             ?
                  [HttpGet]                     ?
                  public IActionResult Error()
                  {
                      return Problem();         ?
                  }
              }
          }

          ? 要處理的 HTTP 路由

          ? 要處理的 HTTP 方法

          ? 返回給調用方的 HTTP 響應

          我們返回的 Problem() 方法是 ControllerBase 類(我們的 ErrorController 擴展)的一種方法,它生成 ProblemDetail 響應 — 一種機器可讀的標準化格式,用于基于 RFC 7807 (https://tools.ietf.org/html/rfc7807 指定 HTTP API 響應中的錯誤).簡而言之,它是一個 JSON 文件,其中包含有關錯誤的一些有用信息:標題、詳細信息、狀態等。但是,由于我們在未指定任何參數的情況下調用 Problem() 方法,因此這些值將由 ASP.NET Core 使用從已引發的異常中獲取的默認值自動設置。

          使用最小 API

          讓我們看看如何使用最小 API 來實現相同的結果。在 Visual Studio 的解決方案資源管理器中,打開 Program.cs 文件,并在應用之前添加以下代碼。MapControllers() 方法:

          app.MapGet("/error", ()=> Results.Problem());

          就是這樣。事實上,Minimal API 似乎是這場比賽的明顯贏家,因為它允許我們使用單行代碼獲得與我們的 ErrorController 相同的結果,而無需創建專用文件。這個結果應該不足為奇:此場景是死簡單路由操作的完美示例,其中最小 API 大放異彩,而控制器更適合復雜任務。

          在接下來的章節中,我們將看到許多基于控制器的方法將報復的場景。目前,我們不妨刪除 ErrorController.cs 文件,并將最小 API 單行代碼保留在 Program.cs 文件中。不過,首先,讓我們花幾分鐘時間討論一下,如果我們保持 ErrorController.cs 在原地會發生什么。

          路由沖突

          控制器和最小 API 可以毫無問題地存在于同一個項目中,因此開發人員可以兩全其美。但它們應配置為處理不同的路由。如果他們共享一個終端節點,會發生什么情況?

          如果我們記得在第1章中學到的內容,我們已經知道了答案:程序.cs文件中首先出現的中間件首先處理HTTP請求,并可能終止它,從而防止另一個請求發揮作用。這種行為非常好,不會在HTTP生命周期中造成任何重大問題,除了浪費在我們項目的代碼庫中有一個無用的實現。

          在我們當前的方案中,因為我們放置了最小 API 的應用。MapGet() 方法就在應用程序之前。MapControllers() 方法,“死代碼”受害者將是我們的 ErrorController.cs 文件。如果一切正常,我們為什么要刪除該控制器?我們不能把它留在那里嗎?

          回答該問題的最佳方法是再次按 F5 并執行我們的應用,然后再刪除 ErrorController.cs 文件。圖 2.6 顯示了我們應該得到什么。


          圖 2.6 SwaggerUI 錯誤 500(由于路由沖突)

          正如我們所看到的,以前工作的 SwaggerUI 頁面顯示一個獲取錯誤,因為它的數據源(自動生成的 swagger.json 文件在內部用于構建 UI)返回 HTTP 500 錯誤。如果我們復制該 URL (https:/ /localhost:40443/ swagger/v1/swagger.json) 并將其粘貼到我們 Web 瀏覽器的地址欄中,我們可以看到實際錯誤:

          SwaggerGeneratorException: Conflicting method/path combination "GET error" 
          for actions - MyBGList.Controllers.ErrorController.Error (MyBGList),HTTP: 
          GET /error. Actions require a unique method/path combination for 
          Swagger/OpenAPI 3.0. Use ConflictingActionsResolver as a workaround.

          這條錯誤消息將我們帶到了問題的根源:我們有兩個處理程序用于相同的方法/路徑組合(GET /error),這會阻止 Swagger 正常工作。要解決此問題,我們可以做以下兩件事之一:

          • 刪除其中一個“重復”處理程序(控制器的 Error() 操作或最小 API 的 MapGet() 方法)。
          • 設置沖突操作解析程序以指示 Swagger 如何處理重復處理程序。

          在這種情況下,刪除 ErrorController.cs 文件或將其從項目中刪除是更好的做法,因為我們無論如何都不想保留冗余代碼。但是,如果我們出于某種原因想要保留它,我們可以指示 Swagger 通過以下方式更改程序文件中的 SwaggerGeneratorMiddleware 配置來處理這種情況.cs(更新的代碼以粗體標記):

          builder.Services.AddSwaggerGen(opts=>
              opts.ResolveConflictingActions(apiDesc=>  apiDesc.First())
              );

          我們告訴 Swagger 通過始終采用找到的第一個并忽略其他沖突來解決與重復路由處理程序相關的所有沖突。但是,強烈建議不要使用此方法,因為它可以隱藏潛在的路由問題并導致意外結果。難怪錯誤消息稱其為解決方法!

          警告更一般地說,始終通過刪除冗余(或錯誤)操作處理程序來解決路由沖突。設置框架(或中間件)以自動“解決”沖突幾乎總是不好的做法,除非開發人員有足夠的經驗知道他們在做什么。

          因此,在繼續之前,我們能做的最好的事情是刪除 ErrorController.cs 文件或將其從項目中排除(右鍵單擊它,然后從解決方案資源管理器的上下文菜單中選擇“從項目中排除”),這樣 Swagger 就沒有機會找到任何重復。

          測試它

          現在,我們已經為開發環境配置了開發人員例外頁面,為生產環境配置了 Error() 操作,我們需要模擬實際錯誤。最快的方法是添加另一個引發異常的操作方法(或最小 API)。如果我們仍然有錯誤控制器,我們可以通過以下方式實現操作方法:

          [Route("/error/test")]
          [HttpGet]
          public IActionResult Test()
          {
              throw new Exception("test");
          }

          但是,由于我們選擇從項目中刪除或排除 ErrorController,因此我們可以將以下最小 API 單行代碼放在程序.cs文件中,正下方是我們添加的其他 MapGet() 方法:

          app.MapGet("/error/test", ()=> { throw new Exception("test"); });

          然后單擊“開始”按鈕(或按 F5 鍵)并將 Web 瀏覽器指向 https://localhost:40443/error/test。如果我們正確執行了所有操作,我們應該看到由 DeveloperExceptionPageMiddleware 生成的開發人員異常頁面,如圖 2.7 所示。


          圖 2.7 測試開發人員異常頁面中間件

          此結果是意料之中的,因為我們在開發環境中執行應用,由 launchSettings .json 文件中的 ASPNETCORE_ENVIRONMENT 變量指定。如果我們想測試 ExceptionHandlerMiddleware,我們需要做的就是將變量的值從開發更改為生產。

          或者,我們可以充分利用我們添加到appsettings.json文件中的UseDeveloperExceptionPage鍵。實現此設置將允許我們在開發人員例外頁面和 ExceptionHandler 之間切換,而無需更改應用程序的運行時環境。打開程序.cs文件,并替換代碼

          if (app.Environment.IsDevelopment())
          {
              app.UseSwagger();
              app.UseSwaggerUI();
              app.UseDeveloperExceptionPage();
          }
          else
          {
              app.UseExceptionHandler("/error");
          }

          使用此代碼:

          if (app.Environment.IsDevelopment())
          {
              app.UseSwagger();
              app.UseSwaggerUI();
          }
           
          if (app.Configuration.GetValue<bool>("UseDeveloperExceptionPage"))   ?
              app.UseDeveloperExceptionPage();                                 ?
          else
              app.UseExceptionHandler("/error");                                ?

          ? 從 appsettings.json 文件中檢索該文本值

          ? 如果為 TRUE,則使用 DeveloperExceptionPageMiddleware

          ? 如果為 FALSE,則改用 ExceptionHandlerMiddleware

          現在將使用 ExceptionHandlerMiddleware 而不是 DeveloperExceptionPageMiddleware,因為在 appsetting.json 文件中,UseDeveloperExceptionPage 鍵的值設置為 false。我們可以立即按 F5,導航到 https://localhost:40443/error/test URL,并接收 ProblemDetail JSON 響應:

          {
            "type":"https://tools.ietf.org/html/rfc7231#section-6.6.1",
            "title":"An error occurred while processing your request.",
            "status":500
          }

          注意此 JSON 輸出在我們的方案中(目前)足夠可行,因為它不會公開有關我們應用的潛在可利用信息。我們可以進一步自定義輸出。我們可以使用方法重載支持的可選參數,將通用的“發生錯誤”標題替換為實際的 Exception 消息,為不同類型的錯誤提供不同的狀態代碼,等等。

          現在我們已經完成這一系列測試,我們應該為開發環境重新啟用 DeveloperExceptionPageMiddleware。我們可以打開appsettings .json文件并將UseDeveloperExceptionPage值從false更改為true,但這不是正確的做法。我們希望確保這樣一個潛在的不安全頁面只能被開發人員看到,記得嗎?因此,重新啟用它的正確方法是執行以下步驟:

          1. 打開應用設置。開發.json 文件。
          2. 添加一個 UseDeveloperExceptionPage 鍵(此文件中不存在該鍵)。
          3. 將鍵的值設置為 true。

          以下是更新后的文件的外觀(粗體換行):

          {
            "Logging": {
              "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning"
              }
            },
            "UseDeveloperExceptionPage": true
          }

          現在我們放在應用程序設置中的值。每當我們的應用在開發運行時環境中啟動時,Development.json 文件都會覆蓋 appsettings.json 文件中的值,這正是我們想要的。

          2.4.4 檢查天氣預報控制器

          下一個要查看的文件是 WeatherForecastController.cs,我們可以在 /Controllers/ 文件夾中找到它。

          注意按照 ASP.NET 約定,所有控制器類都必須駐留在項目的根級 /Controllers/ 文件夾中,并從 Microsoft.AspNetCore.Mvc.Controller 基類繼承。

          正如我們從第 1 章中知道的那樣,控制器在 ASP.NET Core 中用于定義和分組處理 HTTP 請求(通過路由映射)并相應地返回 HTTP 響應的操作。如果我們看一下WeatherForecastController的源代碼,我們可以看到它也不例外。此示例控制器旨在處理對 /WeatherForecast 路由的 HTTP GET 請求,并返回一個 HTTP 響應,其中包含一個包含五個 JSON 對象的數組,其中包含一些隨機生成的日期、溫度 C 和摘要屬性值:

          using Microsoft.AspNetCore.Mvc;
           
          namespace MyBGList.Controllers
          {
              [ApiController]                                                    ?
              [Route("[controller]")]                                            ?
              public class WeatherForecastController : ControllerBase
              {
                     private static readonly string[] Summaries=new[] {
                      "Freezing", "Bracing", "Chilly", "Cool", 
                      "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
                  };
           
                  private readonly ILogger<WeatherForecastController> _logger;   ?
           
                  public WeatherForecastController
                      (ILogger<WeatherForecastController> logger)
                  {
                      _logger=logger;                                          ?
                  }
           
                  [HttpGet(Name="GetWeatherForecast")]                         ?
                  public IEnumerable<WeatherForecast> Get()
                  {
                      return Enumerable.Range(1, 5)
                          .Select(index=> new WeatherForecast
                      {
                          Date=DateTime.Now.AddDays(index),
                          TemperatureC=Random.Shared.Next(-20, 55),
                          Summary=Summaries[Random.Shared.Next(Summaries.Length)]
                      })
                      .ToArray();
                  }
              }
          }

          ? 添加特定于 API 的行為

          ? 默認路由規則

          ? ILogger 實例(通過依賴注入實例化)

          ? 處理 HTTP GET 到 /WeatherForecast 的操作

          如果我們嘗試執行此代碼,我們會得到以下結果:

          [{
            date: "2021-12-03T02:04:31.5766653+01:00",
            temperatureC: 0,
            temperatureF: 32,
            summary: "Warm"
          },
          {
            date: "2021-12-04T02:04:31.5770138+01:00",
            temperatureC: 23,
            temperatureF: 73,
            summary: "Freezing"
          },
          {
            date: "2021-12-05T02:04:31.5770175+01:00",
            temperatureC: 40,
            temperatureF: 103,
            summary: "Freezing"
          },
          {
            date: "2021-12-06T02:04:31.5770178+01:00",
            temperatureC: 47,
            temperatureF: 116,
            summary: "Cool"
          },
          {
            date: "2021-12-07T02:04:31.577018+01:00",
            temperatureC: 36,
            temperatureF: 96,
            summary: "Mild"
          }]

          返回的對象是 C# WeatherForecast 類的 JSON 表示形式,該類在項目根文件夾的 WeatherForecast.cs 文件中定義。 正如我們通過查看其源代碼所看到的,它是一個 POCO 類,其中包含一些可以輕松序列化為 JSON 輸出的屬性:

          namespace MyBGList
          {
              public class WeatherForecast
              {
                  public DateTime Date { get; set; }
           
                  public int TemperatureC { get; set; }
           
                  public int TemperatureF=> 32 + (int)(TemperatureC / 0.5556);
           
                  public string? Summary { get; set; }
              }
          }

          注意 POCO 代表普通舊 CLR 對象,換句話說,一個沒有依賴項、屬性、基礎結構問題、特殊類型或其他職責的普通類。

          WeatherForecastController 和 WeatherForecast 示例類可用于了解 ASP.NET 控制器的工作原理,但它們不適合我們的具體方案。在處理與棋盤游戲相關的 API 時,我們不需要了解任何有關溫度或預測的信息。出于這個原因,我們將刪除這些文件或將它們從項目中排除,就像我們之前對 ErrorController.cs 文件所做的那樣,并將它們替換為更相關的示例。

          2.4.5 添加棋盤游戲控制器

          讓我們從POCO類開始,它將取代以前的天氣預報。在 Visual Studio 的解決方案資源管理器中,執行以下步驟(清單 2.3):

          1. 刪除現有的天氣預報.cs文件。
          2. 右鍵單擊 MyBGList 項目的根文件夾,從上下文菜單中選擇“添加新項>”,然后創建一個新的 BoardGame.cs 類文件。
          3. 用托管一些棋盤游戲數據的 POCO 類填充新文件。

          清單 2.3 BoardGame.cs文件

          namespace MyBGList
          {
              public class BoardGame
              {
                  public int Id { get; set; }
           
                  public string? Name { get; set; }
           
                  public int? Year { get; set; }
              }
          }

          這個新類仍然是一個示例,但它與我們選擇的方案更一致!讓我們對控制器執行相同的操作。在 Visual Studio 的解決方案資源管理器中,執行以下步驟(清單 2.4):

          1. 導航到 /Controllers/ 文件夾,然后刪除現有的 WeatherForecastController.cs 文件。
          2. 右鍵單擊 /Controllers/ 文件夾,從上下文菜單中選擇“添加>控制器”,創建新的 API 控制器 - 空,并將新文件命名為 BoardGamesController.cs。
          3. 刪除 /api/ 前綴,因為我們不需要它。
          4. 添加一個新的操作方法,以使用我們創建的 BoardGame POCO 類返回棋盤游戲數據數組。

          清單 2.4 BoardGame.cs文件

          using Microsoft.AspNetCore.Mvc;
           
          namespace MyBGList.Controllers
          {
              [Route("[controller]")]                   ?
              [ApiController]
              public class BoardGamesController : ControllerBase
              {
                  private readonly ILogger<BoardGamesController> _logger;
           
                  public BoardGamesController(ILogger<BoardGamesController> logger)
                  {
                      _logger=logger;
                  }
           
                  [HttpGet(Name="GetBoardGames")]     ?
                  public IEnumerable<BoardGame> Get()
                  {
                      return new[] {
                          new BoardGame() {
                              Id=1,
                              Name="Axis & Allies",
                              Year=1981
                          },
                          new BoardGame() {
                              Id=2,
                              Name="Citadels",
                              Year=2000
                          },
                          new BoardGame() {
                              Id=3,
           
                              Name="Terraforming Mars",
                              Year=2016
                          }
                      };
                  }
              }
          }

          ? 更新的路線模式

          ? 新的獲取方法

          就是這樣。我們新的 BoardGamesController 將處理 /BoardGames 路由,并使用一個 JSON 數組進行響應,該數組包含過去 45 年左右發布的三款備受贊譽的棋盤游戲的一些相關示例信息。

          我們的BoardGamesController的最小行為可以通過Minimal API通過幾行代碼輕松處理。下面是一個代碼片段,我們可以將其放入 Program.cs 文件中,以從 Get() 操作方法獲取相同的輸出:

          app.MapGet("/BoardGames", ()=> new[] {
              new BoardGame() {
                  Id=1,
                  Name="Axis & Allies",
                  Year=1981
              },
              new BoardGame() {
                  Id=2,
                  Name="Citadels",
                  Year=2000
              },
              new BoardGame() {
                  Id=3,
                  Name="Terraforming Mars",
                  Year=2016
              }
          });

          此示例只是一個示例 JSON 響應,它模擬了更復雜的行為,其中通常包括重要的數據檢索。在接下來的章節中,我們將使用實體框架核心從數據庫管理系統 (DBMS) 獲取棋盤游戲數據,甚至可能為用戶更新它。當我們處理這些類型的操作時,基于控制器的方法變得方便,甚至可能比最小 API 更方便。出于這個原因,這次我們將保留控制器而不是更換它。

          2.5 練習

          建立對 ASP.NET 和Visual Studio的信心的最佳方法是,一旦我們了解了各種工具的工作原理,就立即練習使用它們。本節提供了一些有用的練習,使我們能夠使用在本章中學到的技能進一步自定義我們的第一個 Web API 項目。每個練習都旨在修改單個文件,但通過完成所有練習,我們將能夠實現一致的總體目標。

          假設我們需要為一組選定的內部測試人員配置新的 MyBGList Web API,這些測試人員將能夠通過一組給定的 TCP 端口訪問我們的開發機器。以下是我們需要確保的細節的完整積壓工作:

          1. 測試人員只能使用 55221 和 55222 TCP 端口。
          2. 測試人員只能使用 Kestrel Web 服務器。
          3. 用于測試應用的 Web 瀏覽器應從 BoardGamesController 的 Get() 操作方法返回的 BoardGames 的 JSON 列表開始。
          4. 必須允許測試人員(如開發人員)訪問 SwaggerUI 頁面,但不能訪問開發人員例外頁面,他們應該無法訪問該頁面。
          5. 測試人員需要為每個棋盤游戲檢索兩個附加字段:最小玩家和最大玩家。這些字段應包含棋盤游戲支持的最小和最大玩家數。

          提示如果您覺得大膽,請停止閱讀此處,并在沒有進一步幫助的情況下開始練習(困難模式)。如果您對到目前為止所學的內容不太有信心,可以閱讀以下部分,這些部分提供了所有相關步驟的一般指導,而不會泄露解決方案(寬松模式)。所有給定練習的解決方案都可以在 GitHub 的 /Chapter_02/Exercises/ 文件夾中找到。若要測試它們,請將 MyBGList 項目中的相關文件替換為該文件夾中的文件,然后運行應用。

          2.5.1 luanchSettings.json

          我們需要做的第一件事是確保測試人員能夠通過給定的TCP端口訪問本地機器。明智的做法是設置一個專用的運行時環境供他們使用。暫存環境似乎是完美的選擇,因為它允許我們定義一些特定的配置設置,而無需更改生產和開發環境的配置,我們可能需要這些配置。我們可以通過更新launchSettings.json文件并通過以下方式為MyBGList項目配置Kestrel啟動設置來執行這些任務:

          1. 將 TCP 端口 55221 用于 HTTP,將 55222 用于 HTTPS。
          2. 將運行時環境設置為“暫存”。
          3. 將起始終結點 URL 設置為由 BoardGamesController 的 Get() 操作方法處理的路由,以便 Web 瀏覽器在應用啟動時自動顯示該頁面。

          我們不需要更改 IIS Express 的設置,因為測試人員不會使用它。這些任務完成積壓工作中的第 1、2 和 3 項。

          2.5.2 appsettings.json

          接下來要做的是為暫存運行時環境創建設置文件,并定義一些對所有環境都有效的默認行為,我們可以在需要時有條件地覆蓋這些行為。以下是我們如何完成所有這些任務:

          1. 將新的 UseSwagger 配置設置添加到 MyBGList 應用設置,該設置對所有運行時環境都有效,值為 False。
          2. 將現有配置文件中相同的 UseSwagger 配置設置添加到開發環境中,值為 True。
          3. 為過渡環境創建新的配置文件,并覆蓋設置,如下所示:
          4. 使用開發人員異常頁面:假
          5. 使用招搖:真

          這些任務還不會影響任何事情,但它們符合我們規范的第 4 項。

          提示將暫存環境的 UseDeveloperExceptionPage 設置為 false 可能是多余的,因為該值已在通用 appsettings.json 文件中設置。但是,由于我們談論的是包含潛在機密信息的頁面,因此在給定環境中明確拒絕訪問不會造成傷害。

          2.5.3 Program.cs

          現在我們有了正確的應用設置變量,我們可以根據應用的運行時環境,使用它們有條件地添加(或跳過)相關中間件。我們需要打開 Program.cs 文件并更改 SwaggerMiddleware 和 SwaggerUIMiddleware 的當前初始化策略,以確保僅在 UseSwagger 設置為 True 時使用它們。通過這樣做,我們完成了積壓的第 4 項。

          2.5.4 BoardGame.cs

          若要實現積壓工作的第 5 項,我們需要向現有的 BoardGame POCO 類添加兩個新屬性。至于要使用的類型,最合適的選擇是可為空的 int,因為我們用于 Year 屬性;我們無法確定此類信息是否始終適用于所有棋盤游戲。

          2.5.5 BoardGameController.cs

          將這些屬性添加到 BoardGame 類不足以在 JSON 文件中正確顯示它們,除非我們希望它們始終為 null。因為我們目前正在處理示例數據,所以我們唯一能做的就是更新我們的 BoardGameController 的 Get() 方法并手動設置固定值。這項任務足以完成積壓工作的第 5 項并完成練習。

          我們剩下要做的就是選擇 Kestrel 作為啟動 Web 服務器,單擊“開始”按鈕(或按 F5)啟動我們的 Web API 項目,看看會發生什么。如果我們正確執行了所有操作,我們的 Web 瀏覽器應該自動調用 https://localhost :55221/boardgames 端點并顯示以下 JSON 響應:

          [{
            "id":1,
            "name":"Axis & Allies",
            "year":1981,
            "minPlayers":2,
            "maxPlayers":5
          },
          {
            "id":2,
            "name":"Citadels",
            "year":2000,
            "minPlayers":2,
            "maxPlayers":8
          },
          {
            "id":3,
            "name":"Terraforming Mars",
            "year":2016,
            "minPlayers":1,
            "maxPlayers":5
          }]

          如果我們取得了這個結果,我們就準備好繼續前進了。

          總結

          • 若要創建 ASP.NET 核心應用,我們需要下載并安裝 .NET Core SDK、.NET Core 運行時和 ASP.NET Core 運行時(除非您選擇了自動執行這些操作的 IDE,例如 Visual Studio)。
          • 我們還應該為自己提供一個合適的IDE,如Visual Studio:一個全面的Windows和macOS開發解決方案,我們將在本書中使用。Visual Studio 可以顯著提高我們的工作效率,并幫助我們標準化開發過程,這要歸功于任務運行程序、包管理器、集成源代碼管理和語法突出顯示等內置功能。
          • Visual Studio 包含許多有用的模板,我們可以將其用作創建應用程序的樣板,包括 ASP.NET Core Web API 模板,這是啟動我們的 MyBGList Web API 項目的完美選擇。
          • Visual Studio 的 ASP.NET Core Web API 模板附帶了一小組自動生成的文件:
            • 用于設置服務和中間件的啟動文件(程序.cs)
            • 用于使用開發 Web 服務器啟動應用的設置文件 (launchSettings.json)
            • 一組配置文件,用于存儲應用特定于環境的設置 (appsettings.json)
            • 用于模擬數據對象的 POCO 類 (天氣預報.cs)
            • 一個控制器類,可以使用一些示例 JSON 數據(天氣預報控制器.cs響應簡單的 HTTP 請求)
          • 在簡要回顧模板文件和一些小的代碼更改以了解它們的工作原理后,我們可以開始用一些與棋盤游戲相關的類替換內置的天氣預報示例類。
          • 在繼續之前,通過一些練習來測試我們獲得的知識可能會很有用,模擬來自客戶的一系列請求(積壓項)。
            • 根據我們的信心,我們可以嘗試在沒有任何建議的情況下實現它們或遵循一些高級指導。
            • 無論選擇的復雜程度如何,進行此類練習都是測試我們當前技能并為即將到來的主題做準備的好方法。

          站想要改版,但是以前的技術資料又舍不得丟棄?我公司最近對以往比較舊的asp進行了改版升級,并且把原來的access數據庫導入mysql數據庫中,實現了數據的無縫銜接。

          網站數據無縫對接

          因為asp+access的網站靜態生成占用服務器較少,并且是目錄化結構,所以從野狼SEO團隊到永易搜建站團隊對于企業網站都是這樣做的,但是這幾年發現很多客戶對于程序的交互性要求越來越高,尤其是現在開放平臺的對接等還是PHP程序要更好操作并且更強大,所以最近四五年我們主要就是提升我們的PHP建站系統功能和易用性。在電腦+手機適配方面,我司的建站系統表現突出,受到大家的親睞,所以怎么把老的ASP+ACCESS數據的內容導入到新的系統里并進行網站改版成為大家的呼聲,所以我們就進行了改造。

          升級網站數據不丟對SEO非常有幫助

          如果您需要我司為您建站,這些問題都交給我們來做,您也可以自己動手來做,實現步驟如下:

          第一步:了解老系統和新系統的數據適配關系,比如我司的ASP程序主要是這幾個字段:

          ID---------ID號不能變

          ClassID----欄目ID

          Title------標題

          Intro------描述

          Content----內容

          Hits-------點擊量

          KeyWords---關鍵詞

          UpdateTime-發布時間

          TemplateUrl-模板地址

          FileName----目錄名

          PicUrl------縮略圖

          OrderID-----排序

          IStop-------置頂

          如果你是參考著修改其他系統,可以看看這個字段的適配關系。

          第二步,在PHP系統中,通過PHP程序度access數據庫,然后存入到mysql數據庫。

          其中注意要做好轉碼或者發布時間的格式轉化。

          例如我司access導入到mysql數據庫中就用這樣的代碼:

          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

          <html xmlns="http://www.w3.org/1999/xhtml">

          <head>

          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

          <title>數據導入</title>

          </head>

          <body>

          <?php

          define('IN_yongyisou', true);

          require_once 'include/init.php';

          $act=isset($_GET['act'])?$_GET['act']:'';

          if($act=='yongyisou56789390'){

          $conn_mdb=new com("ADODB.Connection");

          $connstr_mdb="DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=". realpath("Data_ACT/#YeLangSCF4E9.mdb");

          $conn_mdb->Open($connstr_mdb);

          $rs=new com("ADODB.RecordSet");

          $rs->Open("select ID,ClassID,Title,Intro,Content,Hits,KeyWords,UpdateTime,TemplateUrl,FileName,PicUrl,OrderID,IStop from Article_ACT where 1",$conn_mdb,1,1);

          while(!$rs->eof)

          {

          $ID=$rs->Fields('ID')->value;

          $ClassID=$rs->Fields('ClassID')->value;

          $Title=iconv('GB2312','UTF-8',$rs->Fields('Title')->value);

          $Intro=iconv('GB2312','UTF-8',$rs->Fields('Intro')->value);

          $Content=iconv('GBK','UTF-8',$rs->Fields('Content')->value);

          $Hits=iconv('GB2312','UTF-8',$rs->Fields('Hits')->value);

          $KeyWords=iconv('GB2312','UTF-8',$rs->Fields('KeyWords')->value);

          $UpdateTime=iconv('GB2312','UTF-8',$rs->Fields('UpdateTime')->value);

          $TemplateUrl=iconv('GB2312','UTF-8',$rs->Fields('TemplateUrl')->value);

          $FileName=iconv('GB2312','UTF-8',$rs->Fields('FileName')->value);

          $PicUrl=iconv('GB2312','UTF-8',$rs->Fields('PicUrl')->value);

          $OrderID=iconv('GB2312','UTF-8',$rs->Fields('OrderID')->value);

          $IStop=iconv('GB2312','UTF-8',$rs->Fields('IStop')->value);

          $Content=htmlentities($Content,ENT_COMPAT,'UTF-8');//html進行轉義

          $UpdateTime=strtotime($UpdateTime);//發布時間變成時間戳

          if($ClassID==5734002122){

          //新聞中心

          $sql="INSERT INTO ".table("article")." (id,count,cat_id,title ,body ,intro,pic,keywords, description,click,pub_time,sort,recommend,hot,pub)" .

          " VALUES ('$ID','0','2','$Title','$Content','$Intro','$PicUrl', '$KeyWords','$Intro','$Hits','$UpdateTime','$OrderID','$IStop','0','1')";

          if($yys->query($sql)){

          echo("ID為".$ID."的文章導入成功<br/>");

          }else{

          echo("ID為".$ID."的文章導入失敗<br/>");

          }

          }

          $rs->MoveNext();

          }

          echo('導入成功');

          }else{

          die('參數不正確');

          }

          ?>

          </body>

          </html>

          最新版本的 ASP.NET 叫做 ASP.NET Core (也被稱為 ASP.NET 5) 它顛覆了過去的 ASP.NET。

          什么是 ASP.NET Core?

          ASP.NET Core 1.0是一個開源跨平臺的開發框架,用于構建基于云的現代 Web 應用 。它是從底層開始重新構建來提供性能優良的Web應用開發框架,可以部署在云上或者本地服務器上。另外,它使得 ASP.NET 應用更加精簡和模塊化(可以根據你的應用需要向里面添加其他模塊),跨平臺(你可以很容易的在 Windows, Mac or Linux 上開發和部署你的應用),云優化(你可以在云上在云上部署和調試你的應用)。

          以前的版本

          對于使用 ASP.NET 舊版本的我們來說,這意味著什么?

          如果你正在使用舊版本的 ASP.NET 或者你有 WebForms 的開發背景,那么你將會認識到 ASP.NET Core 有多完美,這感覺起來就像從古典的 ASP 時代來到全新的 ASP.NET 的世界。

          現在,讓我們來一探究竟

          下面列出 ASP.NET Core 1.0 的核心變化.

          跨平臺的運行時

          你可以在 OSX 和 Linux上運行 ASP.NET Core 應用,這對于 ASP.NET 來說,這具有跨時代的意義,也給 ASP.NET 開發者和設計師們帶來了全新的體驗。ASP.NET Core 具有兩個運行時,這意味著你可以選擇不同的運行環境來部署你的應用,使得你的應用將更加靈活。

          ASP.NET Core 1.0是一個 ASP.NET 的重構版本,它運行于最新的 .NET Core。它是模塊化的,允許開發者以插件的形式添加應用所需要的模塊,大多數的功能都將作為插件提供并通過 NuGet 程序包管理。這樣做的一個好處就是你可以升級應用的一個模塊,但絲毫不會影響其他模塊;另外,.NET Core 是一個跨平臺的運行時,因此你可以在 OSX 或 Linux 操作系統上部署你的應用;它也是一個云優化的運行時,用于在云上部署和調試應用;.NET Core 可以和你的應用程序一起被部署,當服務器上有多個 .NET Core 版本時, 你依舊可以運行 ASP.NET Core 應用。

          你也可以創建只運行在 windows 下完整 .NET 框架的 ASP.NET Core 應用。

          ASP.NET 4.6 是最新的完整 .NET Framework 的發布版本,它允許你可以利用所有的 .NET 組件并且具備向后兼容能力。如果你計劃將應用遷移到 .NET core,那么你需要做適量的修改,因為 .NET Core 相對于完整 .NET Framework 來說有所限制。

          需要明確的是,ASP.NET 4.6 更加成熟。它如今久經考驗并且現已發布并可使用。ASP.NET Core 1.0 是1.0 發布版本,包含 Web API 和 MVC,但是現在還沒有 SignalR 和 Web Pages。,它也不支持VB 和 F# 語言。

          ASP.NET Core 不再只依賴Visual Studio

          ASP.NET Core的跨平臺,讓它不再只依賴 Visual Studio,開發者和設計師們可以在自己喜歡的環境上工作。比如 Sublime Text,WebStorm ,這真是太棒了!

          新的工程解決方案結構

          如果你使用 Visual Studio 創建了一個空的 ASP.NET Core 工程,那么你將會看到下面的驚喜。(除非你沒有使用之前的 ASP.NET 創建過任何項目)

          你感覺到驚喜了嗎?新的工程結構完全不一樣了, 工程模板煥然一新,包含以下的新文件:

          · global.json: 你可以在這里放置解決方案的配置信息和工程之間的引用。

          · Program.cs: 這個文件包含了 ASP.NET Core RC2 應用的 Main 方法,負責配置和啟動應用程序。

          · src folder: 包含組成你應用程序的全部項目代碼。

          · wwwroot:你的靜態文件將被放置在這個文件夾,它們都將作為資源直接提供給客戶端,包含 HTML,CSS 和 JavaScript 文件。

          · project.json: 包含項目設置。在 ASP.NET Core中,你可以通過使用 NuGet 程序包管理工具(NPM)添加 NuGet 包或者編輯這個文件來管理從屬。你可以通過任何文本編輯器來編輯這個文件,如果你使用 Visual Studio 2015,,這將會更加 輕松,因為它的智能提示會幫助你找到合適的 NuGet 包作為從屬。project.json 就像下面這樣。

          · startup.cs這個主要放置你 ASP.NET Core 的 stratup 和 configuration 代碼,下面就是 stratup 類的樣子。

          ConfigureServices 方法定義了你應用程序使用的服務,Configure 方法用來定義組成請求管道的中間件。

          · References: 它包含了 .NETCoreApp 第一個版本運行時的引用。

          WebForms

          是的,WebForms 不再是 ASP.NET 5 的一部分,這真令人悲傷。你可以繼續使用 VS2015 的 .NET 4.6 來構建 Web Forms 應用,但是卻不能體會 ASP.NET 5 的新特性了。

          我已經開發了很多年從小型到大型的企業級 Web Forms 應用。 我很喜歡 Web Forms,,事實上我還會繼續支持在各種論壇使用 WebForms 的社區,比如 http://forums.asp.net。但是我們是時候進步了,去學習一些新東西。這是學習 ASP.NET MVC 最后的時間了,就像過去的許多事物,你要么去適應,要么被淘汰。

          除了 WebForms, the .NET Core 也沒有包含 Windows Forms, WCF, WPF, Silverlight 等等。

          VB.NET and F#

          目前,在當前 ASP.NET Core 1.0 RC2版本中, VB.NET 和 F# 也不被支持。

          MVC Core 統一架構

          ASP.NET Core 將見證 MVC, Web API 和 Web Pages(可能包含)組合在一個架構中,它被稱為 ASP.NET MVC Core。盡管當前發布版本中,還不支持 Web Pages and SignalR。

          在之前的 ASP.NET MVC 中, MVC 控制器和 Web API 控制器是不同的。 一個 MVC 控制器使用基類 System.Web.MVC.Controller,一個 Web API 控制器使用基類System.Web.Http.ApiController。 在 MVC Core 中,會為它們提供一個共同的基類,就是Microsoft.AspNetCore.Mvc.Controller。

          對于 HTML Helpers 來說,MVC 和 Web Pages 的合并是非常有可能的。 Web Pages 編程模型對當前版本來說還不適用,所以我們還不能負責任地說下一步計劃合并哪些特性。 但是我們可以預測到,傳統的 MVC 模型綁定將會出現。

          View Components

          在之前 ASP.NET MVC 中,, Html.Action 幫助方法一般用于調用一個 sub-controller。ASP.NET MVC Core 將會使用新的 View Components 用來代替使用Html.Action 的部件。

          View Components 支持完全異步,這允許你創建異步的視圖組件。

          下面是一個簡單的視圖組件的例子,根據身份會返回個人介紹。

          using Microsoft.AspNetCore.Mvc;  
          using MVC6Demo.Models;  
          using System.Threading.Tasks;  
          using System.Collections.Generic;  
            
          namespace MVC6Demo.ViewComponents  
          {  
              public class PersonListViewComponent : ViewComponent  
              {  
                  public async Task<iviewcomponentresult> InvokeAsync(string status) {  
           string viewToUse="Default";  
           bool isFiltered=false;  
            
           PersonModel model=new PersonModel;  
            
           if (status.ToLower.Equals("registered")) { 
           viewToUse="Registered"; isFiltered=true; 
           }  
           
           var p=await GetPersonAsync(status, isFiltered);  
           return View(viewToUse,p);  
                  }  
           
                  private Task<ienumerable<person>> GetPersonAsync(string status, bool isFiltered) {  
           return Task.FromResult(GetPerson(status,isFiltered));  
                  }  
                  private IEnumerable<person> GetPerson(string status, bool isFiltered) {  
           PersonModel model=new PersonModel;  
            
           if (isFiltered)  
           return model.GetPersonsByStatus(status);  
           else  
           return model.GetAll;  
            
                  }  
              }  
          }  </person>

          下面是 View Component 的視圖:

          <h3>Person List</h3>  
          <ul>  
              @foreach (var p in Model) {  
                  <li>@string.Format("{0} {1}",p.FirstName,p.LastName)</li>  
              }  
          </ul> 

          這里展示了如何在主視圖中調用 View Components

          <div>   
              @await Component.InvokeAsync("PersonList", new { type="Registered" })
          </div>  

          新指令: @inject, @using, @inherits

          ASP.NET MVC Core 提供了少量新指令。 下面我們來看看如何使用 @inject。 @inject 指令允許你注入一個類中的方法到你的視圖中。

          這是一個簡單的類,來展示一些異步的方法。

          using System.Threading.Tasks;  
          using System.Linq;  
            
          namespace MVC6Demo.Models  
          {  
              public class Stats  
              {  
                  private PersonModel _persons=new PersonModel;  
            
                  public async Task<int> GetPersonCount {  
           return await Task.FromResult(_persons.GetAll.Count);  
                  }  
            
                  public async Task<int> GetRegisteredPersonCount {  
           return await Task.FromResult(
           _persons.GetAll.Where(o=> o.Status.ToLower.Equals("registered")).Count);  
                  }  
            
                  public async Task<int> GetUnRegisteredPersonCount {  
           return await Task.FromResult(
           _persons.GetAll.Where(o=> o.Status.ToLower.Equals("")).Count);  
                  }  
              }  
          } 

          現在我們就可以在視圖中使用 @inject 指令來調用那些方法:

          @inject MVC6Demo.Models.Stats Stats  
            
          @{  
              ViewBag.Title="Stats";  
          }  
            
          <div>  

          這是不是很酷?

          查看我關于 ASP.NET MVC 新指令詳細例子的文章: Getting Started with ASP.NET MVC Core

          Tag Helpers

          ASP.NET MVC Core 另外一個非??岬臇|西就是 Tag Helpers。對于之前的 HTML Helpers,Tag Helpers 是可選的替代語法。

          所以相比于以下代碼:

          @using (Html.BeginForm("Login", "Account", FormMethod.Post, 
                  new { @class="form-horizontal", role="form" }))
           {
           @Html.AntiForgeryToken
           <h4>Use a local account to log in.</h4>
           <hr />
           @Html.ValidationSummary(true, "", new { @class="text-danger" })
           <div class="form-group">
           @Html.LabelFor(m=> m.UserName, new { @class="col-md-2 control-label" })
           <div class="col-md-10">
           @Html.TextBoxFor(m=> m.UserName, new { @class="form-control" })
           @Html.ValidationMessageFor(m=> m.UserName, "", new { @class="text-danger" })
           </div>
           </div>
          }

          你可以使用這些代碼:

          <form asp-controller="Account" asp-action="Login" method="post" class="form-horizontal" role="form">  
              <h4>Use a local account to log in.</h4>  
              <hr />  
              <div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>  
              <div class="form-group">  
                  <label asp-for="UserName" class="col-md-2 control-label"></label>  
                  <div class="col-md-10">  
           <input asp-for="UserName" class="col-md-2 control-label" />  
           <span asp-validation-for="UserName" class="text-danger"></span>  
                  </div>  
              </div>  
          </form> 

          ASP.NET Core 不止可以部署在IIS上

          14年前,ASP.NET 平臺基本只能部署在一種服務器上,那就是 IIS。幾年之后,Visual Studio Development Web Server(也叫作“Cassini”)作為一種開發服務被使用,但是它們最終都是調用 System.Web 作為應用程序和 Web 服務器中間的主機層。System.Web 主機與 IIS 耦合度很高,所以要想運行在另一臺主機上會非常困難。

          后來 OWIN作為應用程序和 Web 服務器中間的接口出現。 Microsoft 開發了Katana作為一個 OWIN 的實現,可以部署 ASP.NET Web API, SignalR 和其他第三方框架,這些框架可以在 IIS 和 IIS Express, Katana's 自托管主機和自定義主機。

          ASP.NET Core 是不強調主機的,它在 Katana 和 OWIN 上行為一致。ASP.NET Core 也可以部署在 IIS, IIS Express 或者自托管在你自己的進程里。另外,ASP.NET Core 也會包含一個叫做 Kestrel的 Web 服務器,它建立在 libuv 上,主要用于 iOS 和 Linux 操作系統。

          新的HTTP請求管道

          ASP.NET Core 提供了一種更加模塊化的 HTTP 請求管道, 你可以只添加你需要的組件。這個管道不再依賴 System.Web,通過降低管道中的開銷,你的 app 性能更加優良,更好的調諧 HTTP 協議棧。新的管道基于 Katana 項目經驗,同時支持 OWIN。

          動態的Web開發

          Visual Studio 2015 中另一個非常酷的特性就是支持動態編譯。在過去的 ASP.NET 中,當我們修改了應用的后臺代碼,我們需要重新編譯并且運行才能看到頁面的變化。 在新版本的 Visual Studio 中,你不需要再做這些額外的步驟,僅僅是保存你的修改和刷新瀏覽器即可。

          這是在刷新頁面之后的輸出:

          Attribute Routing: [controller] 和 [action] 標記

          在過去的 MVC 和 Web API 中,使用路由屬性可能會導致一些問題,尤其是你正在做一些代碼重構。這是因為路由必須設定為字符串類型,當你修改了控制器的名字,你就必須修改路由屬性的字符串

          MVC Core 提供了新的 [controller] 和 [action] 標記,它們可以解決這個問題。下面這篇文章重點說明了這些新標記的用法。 : ASP.NET MVC 6 Attribute Routing.

          集成的依賴注入 (DI)

          ASP.NET Core 內嵌了對依賴注入和 Service Locator 模式的支持,這意味著你不在需要通過第三方依賴注入框架 Ninject 或 AutoFac。

          集成 Grunt, Gulp and Bower

          Visual Studio 2015 內嵌了對流行開源 Web 開發工具的支持。 Grunt 和 Gulp 可以幫你自動化構建 Web 開發工作流, 你可以使用它們來編譯和壓縮 JavaScript 文件。Bower 是一個用于客戶端庫的管理工具,包含 CSS 和 JavaScript 庫。

          內置的AngularJs模板

          AngularJs 是當前最流行的前端框架之一,用于構建單頁面應用程序(SPAs)。Visual Studio 包含了用于創建 AngularJs 模塊,控制器,指令和工廠。

          對 GruntJS 的支持使得 ASP.NET 成為一個用于構建客戶端 AngularJs 應用的優秀服務器端框架。 當完成一個版本,你可以自動合并和壓縮全部 AngularJs 文件。查看我的關于開始在 ASP.NET 中使用 Angular 和 Angular2 的文章 。

          SignalR 3

          ASP.NET Core 也是以 SignalR 3 為基礎,這使得你可以向云連接的應用程序添加實時功能。查看我之前的 SignalR 例子: ASP.Net SignalR: Building a Simple Real-Time Chat Application

          Web.Config

          在 ASP.NET Core 中,混亂的 web.config 文件被新的云就緒配置文件代替,它稱作 “config.json”。微軟希望開發人員更容易地在云中部署應用程序,并使得應用能夠根據特殊環境自動的讀取正確的配置參數。

          這是一個新的配置文件的樣子:

          由于 ASP.NET Core 都是插件化的,你需要配置 Stratup 類的源代碼,就像下面這樣:

           public Startup(IHostingEnvironment env)
                  {
           var builder=new ConfigurationBuilder
           .SetBasePath(env.ContentRootPath);
          
           builder.AddEnvironmentVariables;
           Configuration=builder.Build;
                  }
                  public IConfigurationRoot Configuration { get; }
                  public void ConfigureServices(IServiceCollection services)
                  {
           services.AddMvc;
           services.AddTransient<MVC6Demo.Models.HeroStats>;
                  }
          
                  public void Configure(IApplicationBuilder app)
                  {
           app.UseDeveloperExceptionPage;
          
          
           app.UseMvc(m=> {
           m.MapRoute(
           name: "default",
           template: "{controller}/{action}/{id?}",
           defaults: new { controller="Home", action="Index"});
           });
                  }

          xUnit.Net: .NET 新的單元測試工具

          在之前的 ASP.NET MVC 中,默認的測試框架是 Visual Studio 單元測試框架(有時候也叫作mstest),這個框架使用 [TestClass] 和 [TestMethod] 特性來描述一個單元測試。

          ASP.NET Core 使用 xUnit.net作為它的單元測試框架。這個框架使用 [Fact] 特性來代替 [TestMethod] 特性,也消除了對 [TestClass] 屬性的依賴。

          絕對的免費和開源

          是的,ASP.NET Core 被作為一個開源項目托管到 GitHub上, 你可以查看源代碼,并下載并提交你的更改。

          我認同開源的 .NET 會產生重大的意義,它產生了積極的商業意義和社區意義,十分感謝微軟所做出的工作。

          文章來源:By Vincent Maverick Durano, 10 Jun 2016


          上一篇:自定義日歷(一)
          下一篇:Font Awesome 圖標
          主站蜘蛛池模板: 亚洲日韩国产精品第一页一区| 国产福利一区二区三区在线观看| 午夜性色一区二区三区免费不卡视频| 日本免费电影一区二区| 成人精品视频一区二区| 久久亚洲AV午夜福利精品一区| 精品乱码一区二区三区在线| 亚洲综合在线一区二区三区| 无码国产精品一区二区免费vr| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 少妇人妻精品一区二区| 激情亚洲一区国产精品| 亚洲制服丝袜一区二区三区| 亚洲AV无码一区二区三区DV| 亚洲一区二区三区无码中文字幕 | 在线视频一区二区三区| 射精专区一区二区朝鲜| 亚洲综合一区二区国产精品| 无码一区二区三区| 亚洲av福利无码无一区二区| 日本不卡免费新一区二区三区| 久久精品国产第一区二区| 国产综合一区二区在线观看| 精品日本一区二区三区在线观看 | 日韩一区二区三区视频| 一区 二区 三区 中文字幕| 无码日韩精品一区二区人妻| 国产高清一区二区三区四区| 99国产精品一区二区| 亚洲AV无码一区东京热| 日韩一区二区在线视频| 精品无码国产一区二区三区51安| 久久精品无码一区二区三区不卡 | 日本一区二区在线| 在线中文字幕一区| 精产国品一区二区三产区| 国产伦精品一区二区三区免费迷| 亚洲高清偷拍一区二区三区| 国产日韩AV免费无码一区二区| 亚洲av综合av一区| 国内精自品线一区91|