PIXNET Logo登入

互聯網 - 大數據

跳到主文

本部落格為互聯網熱門頭條訊息管理中心

部落格全站分類:生活綜合

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 3月 09 週四 201720:39
  • 在ASP.NET Core MVC中構建簡單 Web Api


文章出處
Getting Started
在 ASP.NET Core MVC 框架中,ASP.NET 團隊為我們提供了一整套的用于構建一個 Web 中的各種部分所需的套件,那么有些時候我們只需要做一個簡單的 Web Api 程序怎么辦呢?
在 GitHub 中的 ASP.NET Core MVC 源碼里面,我們只要關注 Microsoft.AspNetCore.Mvc 這個包,那么除了這個包之外它還包含這些:
  • Microsoft.AspNetCore.Mvc.ApiExplorer

  • Microsoft.AspNetCore.Mvc.Cors

  • Microsoft.AspNetCore.Mvc.DataAnnotations

  • Microsoft.AspNetCore.Mvc.Formatters.Json

  • Microsoft.AspNetCore.Mvc.Localization

  • Microsoft.AspNetCore.Mvc.Razor

  • Microsoft.AspNetCore.Mvc.TagHelpers

  • Microsoft.AspNetCore.Mvc.ViewFeatures

  • Microsoft.Extensions.Caching.Memory

  • Microsoft.Extensions.DependencyInjection

  • NETStandard.Library

  • 通常情況下,我們在創建一個 Web MVC 網站的時候,會在 Startup.cs 文件中的 ConfigureServices 方法中,這樣添加:

    services.AddMvc();

    以上的代碼會將 MVC 中的服務注入到 DI 容器中,我們來看一下 AddMvc() 的源碼:

    public static IMvcBuilder AddMvc(this IServiceCollection services)
    {
    var builder = services.AddMvcCore();
    builder.AddApiExplorer();
    builder.AddAuthorization();
    AddDefaultFrameworkParts(builder.PartManager);
    // Order added affects options setup order
    // Default framework order
    builder.AddFormatterMappings();
    builder.AddViews();
    builder.AddRazorViewEngine();
    builder.AddCacheTagHelper();
    // +1 order
    builder.AddDataAnnotations(); // +1 order
    // +10 order
    builder.AddJsonFormatters();
    builder.AddCors();
    return new MvcBuilder(builder.Services, builder.PartManager);
    }

    簡單 Web Api
    實際上,如果想構建一個簡單 Web Api 程序的話,ASP.NET 團隊已經為我們想到了這一點,所以我們只需要修改我們注入的服務。
    首先,不需要引用 Microsoft.AspNetCore.Mvc 這個包了,轉而引用 Microsoft.AspNetCore.Mvc.Core。 Mvc.Core 這個包只會給你提供基本的 MVC 中間件,比如路由,Controller, HttpResult 等,其他更多的如關于 Razor,Cores,Views 等則沒有提供。
    在 Web Api 應用中,大多數情況下是以 Json 進行數據序列化傳輸的,所以需要添加 Microsoft.AspNetCore.Mvc.Formatters.Json 這個包。
    然后,在 ConfigureServices ,將 Mvc Core 中間件和 Json Formatter 添加里面。

    public void ConfigureServices(IServiceCollection services)
    {
    services.AddMvcCore()
    .AddJsonFormatters();
    }

    最后一點就是,你的 XXXController 類中要繼承 ControllerBase 而不是 Controller。 ControllerBase 里面沒有提供任何關于對 Views 的支持。

    public class XXXController: ControllerBase
    {
    }

    下面是最終的 project.json 引用的所有程序包。
    "dependencies": {
    "Microsoft.NETCore.App": {
    "version": "1.1.0",
    "type": "platform"
    },
    "Microsoft.AspNetCore.Mvc.Core": "1.1.0",
    "Microsoft.AspNetCore.Mvc.Formatters.Json": "1.1.0",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0",
    "Microsoft.Extensions.Configuration.Json": "1.1.0",
    "Microsoft.Extensions.Configuration.CommandLine": "1.1.0",
    "Microsoft.Extensions.Logging": "1.1.0",
    "Microsoft.Extensions.Logging.Console": "1.1.0",
    "Microsoft.Extensions.Logging.Debug": "1.1.0"
    }



    本文地址:http://www.cnblogs.com/savorboard/p/6340451.html
    作者博客:Savorboard
    歡迎轉載,請在明顯位置給出出處及鏈接


    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(553)

    • 個人分類:生活學習
    ▲top
    • 3月 09 週四 201720:39
    • 棒!使用.NET Core構建3D游戲引擎


    文章出處

    原文地址:https://mellinoe.wordpress.com/2017/01/18/net-core-game-engine/
    作者:ERIC MELLINO
    翻譯:楊曉東(Savorboard)


    譯者序
    通過翻譯這篇文章,我感受到了 .NET Core 真正的魅力,它真的是無所不能,相信在以后,.NET Core 一定會大放異彩,而.NET的 開源也會吸引越來越來的開發者參與其中。
    同時,就像作者所說,這賦予給了 .NET Core 另外一種道路和生命,感謝這個路上的先行者。
    正文
    很多人對于 .NET Core 都很關心,但是通常我們都在談論關于控制臺應用程序和服務器端應用程序。在這篇博客中,我們將探討 .NET Core 的另外一個用途,并展示我如何從頭構建一個3D平臺的游戲引擎,編輯器和游戲。作為一個 .NET 團隊中的開發,我已經和社區做了很多的討論并且已經看到了關于這方面的內容。我希望通過這篇博客能夠闡述 .NET Core的功能,并且激勵更多的人來做這方面的探索。
    在第一篇博客中,我將介紹我的游戲(Creazy Core),一個類似街機的3D 平臺的游戲,在這個游戲里,你通過控制一個球來穿越各種障礙物。這也許看起來很寬泛,稍后的博客中中,我將對關于游戲的引擎,編輯器和更多技術細節來做更加詳細的介紹,如他們能夠融合并工作起來。
    免責聲明:這只是一個從頭開始構建的單人開發的游戲。很明顯,這個游戲沒有任何商業用途,我不能保證在觀看原始的作品時候不會受到傷害。
    Creazy Core
    https://github.com/mellinoe/CrazyCore
    Windows.zip
    OSX.zip
    Ubuntu-1604.zip
    這是一個獨立的程序,你只需要下載對應平臺的 ZIP 文件包,然后運行 Creazy Core 可執行程序。如果你在 Ubuntu 上運行,則有一些先決條件。

    譯者注:使用 dotnet CreazyCore.dll 運行程序。 macOS 可以直接運行。


    這個游戲的機制就是利用力學來控制一個小球,在一個3D 的世界里運行,游戲世界起初很簡單,后來逐漸會有更加復雜的力學會引入進來,游戲環境和障礙物也越來越復雜,由于你的進步,游戲會變得越來越難,直到最后會有一些“瘋狂的”力學機制加入。
    為什么使用 .NET Core ?
    首先,這是一個使用 .NET Core 的另外一種偉大的方式。它打破了 .NET Core 原有的路線來探尋一個新的場景。雖然我可能會有點偏見,但是我認為使用 .NET Core 來做游戲是有很多優勢的:
  • 開源。您可以查看,修改和優化整個棧的任何部分。

  • 優秀,針對多平臺設計的優化的運行時。這意味著當在不同平臺上發布時,不必擔心兼容性。

  • 它是.NET。 您可以使用任何.NET語言和所有偉大的可以用的工具以及調試經驗。

  • 面向未來。.NET Core正在快速發展,并且每天都在合并進來性能優化的代碼。另一方面,CoreRT項目將是用于構建游戲的一個非常有趣的技術。雖然還沒有準備好迎接黃金時段,但是提供大量優化的,預編譯的二進制文件的能力將對游戲非常有用。

  • 游戲引擎架構
    同其他游戲引擎一樣,這里也是由大量不同的組件構成的,這使得實時3D 游戲引擎成為可能。我希望我在后續的博客中能夠更多的探討關于這方面更加詳細的內容。但是為了給出游戲引擎中涉及到的一些功能和概念,這里我強調一些重要的事情。
  • 引擎是基于組件的,它具有與 Unity 非常相似的編程模型。

  • 同時支持 Direct3D11(Windows)和 OpenGL (所有平臺) 的圖形。圖形是針對無關平臺的上層api抽象層,它叫做“Veldrid”。

  • 同時支持 XAudio2(Windows)和 OpenAL(所有平臺)的音頻。有另外一個(更輕量)抽象層,它允許 API為引擎中的3D位置音頻提供支撐。

  • 由 OpenTK 庫提供窗口化和輸入的處理。

  • 使用很棒的 BEPUphysics 庫來處理實時的 3D 物理特效。

  • 自定義的序列化系統和資源管理器,用于存儲各種資源,包括:

    • 二進制資源(模型,紋理,音頻)等。

    • 實體和組件狀態。

    • 場景構成以及鏈接器。

    • 元數據信息,比如玩家的進度以及最高分數等。

    • 項目設置。


  • 為了構建不同級別的游戲,我編寫了一個單獨的編輯器 程序,它重用了引擎的各個組件。編輯器是一個獨立的3D 程序,你可以查看和修改游戲資源,組合游戲實體,構建完整的場景,以及管理項目中的配置選項。

    以下視頻鏈接到 YouTube ,請科學上網觀看。


    就想一個典型的編輯器一樣,游戲本身可以在應用程序內測試,并且各種游戲狀態可以實時調整。編輯器還具有項目發布,調試,代碼熱插拔等功能。

    以下視頻鏈接到 YouTube ,請科學上網觀看。


    上面的視頻顯示了一些很酷的事情,你可以在編輯器中調整東西。
    編輯器其中一個最有用的功能是,它可以在多個平臺運行,因為它也是使用的 .NET Core 開發。這使得他可以非常容易的進行一些修改和測試并且方便的應用到游戲中去。
    開源庫
    下面是我這個項目中使用到的庫,以及這些庫是做什么的。所有對.NET 游戲相關感興趣的都可以看看這些庫,他們非常酷!
  • SharpDX -封裝Direct3D11和XAudio2。這些技術僅限于Windows,并且在引擎中默認使用。SharpDX已經支持PCL配置文件,因此它可以在.NET Core上原封不變地使用。

  • OpenTK -封裝OpenGL和OpenAL的(對于上面的替代),以及窗口化和輸入。這個庫相當大,相當老; 編譯為.NET Core它還需要再做一些工作。

  • ImageSharp -跨平臺的加載圖像的庫。這是用來加載游戲中使用的所有紋理。James 對這個項目做了非常偉大的一些工作。

  • BEPUphysics -實時3D物理特效。這是一個非常酷并且精心設計的庫。它最近搬到了GitHub,v2.0計劃了一些非常有趣的功能。

  • dear imgui -Immediate模式的UI,使用圖形用戶界面的編輯器,并為 Creazy Core 提供了菜單。我使用 C# 移植的一個 C++ 庫(ImGui.NET)。

  • SharpFont - TrueType字體加載及渲染。這用于引擎中的一些2D文本組件呈現。

  • Newtonsoft.Json -我想大家都知道這個庫。我使用它來序列化我引擎中的所有自定義數據類型,包括實體,組件及場景數據。

  • 謝謝閱讀!我希望這篇文章已經闡明了.NET Core 在今天可以做的一些事情。在下一篇文章中,我將詳細介紹如何在引擎中處理3D渲染。它是引擎中最復雜的部分,但也是開發中最有趣的一部分。敬請關注!


    本文地址:http://www.cnblogs.com/savorboard/p/net-core-game-engine.html
    本譯文僅用于學習和交流目的。非商業轉載請注明譯者、出處,并保留文章在譯言的完整鏈接。
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(148)

    • 個人分類:生活學習
    ▲top
    • 3月 09 週四 201720:39
    • .NET Core 之 MSBuild 介紹


    文章出處
    前言
    關于 .NET Core 舊版本的 sdk 介紹可以參看我以前的 這篇 文章。
    8 個小時前,.NET Core 項目組釋放了 .NET Core 新一輪的 sdk 工具更新,即 RC4 版本 ,這個版本也就是意味著基本功能已經確定了,下個版本應該就是RTM版了,會隨著 Visual Studio 2017 正式版釋放出來。
    眾所周知,從Tools RC3 版本開始,微軟已經拋棄了原來的 project.json 改為了 MSBuild 工具進行項目文件格式,這么做有好有壞,我想很大原因是為了兼容以前的項目吧。
    不管喜不喜歡以前的 MSBuild 這個風格,都已經是事實了,所以還是先提前了解一下最新的SDK 內容比較實際點吧。
    從 project.json 遷移到 MSBuild
    很簡單,只需要下載最近版本的 Visual Studio 2017 RC版,然后會幫你自動遷移。

    MSBuild(Microsoft Build Engine),它代表微軟Visual Studio 的項目構建工具,這是一種基于 XML 的文件格式。


    RC4 SDK 的一些改進和更改
    比起以前的 sdk dotnet 命令,新的 sdk 最大的改進就是關于腳手架的一些工作,首先就是 dotnet new 命令。
    dotnet new
    在使用 dotnet new 命令后,不會默認創建一個控制臺 Hello World 程序,而是會顯示以下。
    根據提示可以看到,需要制定相應的模板類型名稱,這個改進我認為是非常不錯了,也就是當使用非 Visual Studio 開發工具時,我們可以和容易的創建一個模板程序,而不用從頭開始。 這和使用 Yeoman 非常像,并且方便。
    還有一個特點是,模板并不是一成不變的,它具有更新功能,并且具有可擴展性,任何人都可以編寫自己的模板使用 dotnet new 命令,當前目前的 dotnet new 還不具備上述的一些功能,微軟會在后面的幾個月完善它。
    在使用 dotnet new創建一個程序的時候,除了指定模板類型外,還可以指定需要使用的框架。
    dotnet new console -f 框架名
    或者可以使用 dotnet new console --help 來查看本機都安裝了哪些框架。
    project.json vs MSBuild
    下面是兩個分別使用 以前的 project.json 方式和新的 msbuild 方式創建的兩個MVC項目,然后來看看他們項目文件之間的區別。
    project.json
    {
    "userSecretsId": "aspnet-WebApplication-0799fe3e-6eaf-4c5f-b40e-7c6bfd5dfa9a",
    "dependencies": {
    "Microsoft.NETCore.App": {
    "version": "1.1.0-preview1-001153-00",
    "type": "platform"
    },
    "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0",
    "Microsoft.AspNetCore.Diagnostics": "1.0.0",
    "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0",
    "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
    "Microsoft.AspNetCore.Mvc": "1.0.1",
    "Microsoft.AspNetCore.Razor.Tools": {
    "version": "1.0.0-preview2-final",
    "type": "build"
    },
    "Microsoft.AspNetCore.Routing": "1.0.1",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0",
    "Microsoft.EntityFrameworkCore.Sqlite": "1.0.1",
    "Microsoft.EntityFrameworkCore.Tools": {
    "version": "1.0.0-preview2-final",
    "type": "build"
    },
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
    "Microsoft.Extensions.Configuration.Json": "1.0.0",
    "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
    "Microsoft.Extensions.Logging": "1.0.0",
    "Microsoft.Extensions.Logging.Console": "1.0.0",
    "Microsoft.Extensions.Logging.Debug": "1.0.0",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
    "version": "1.0.0-preview2-update1",
    "type": "build"
    },
    "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": {
    "version": "1.0.0-preview2-update1",
    "type": "build"
    }
    },
    "tools": {
    "Microsoft.AspNetCore.Razor.Tools": {
    "version": "1.0.0-preview2-final",
    "imports": "portable-net45+win8+dnxcore50"
    },
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": {
    "version": "1.0.0-preview2-final",
    "imports": "portable-net45+win8+dnxcore50"
    },
    "Microsoft.EntityFrameworkCore.Tools": {
    "version": "1.0.0-preview2-final",
    "imports": [
    "portable-net45+win8+dnxcore50",
    "portable-net45+win8"
    ]
    },
    "Microsoft.Extensions.SecretManager.Tools": {
    "version": "1.0.0-preview2-final",
    "imports": "portable-net45+win8+dnxcore50"
    },
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
    "version": "1.0.0-preview2-final",
    "imports": [
    "portable-net45+win8+dnxcore50",
    "portable-net45+win8"
    ]
    }
    },
    "frameworks": {
    "netcoreapp1.1": {
    "imports": [
    "dotnet5.6",
    "dnxcore50",
    "portable-net45+win8"
    ]
    }
    },
    "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true,
    "preserveCompilationContext": true
    },
    "runtimeOptions": {
    "configProperties": {
    "System.GC.Server": true
    }
    },
    "publishOptions": {
    "include": [
    "wwwroot",
    "**/*.cshtml",
    "appsettings.json",
    "web.config"
    ]
    },
    "scripts": {
    "prepublish": [ "npm install", "bower install", "gulp clean", "gulp min" ],
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
    },
    "tooling": {
    "defaultNamespace": "WebApplication"
    }
    }

    msbuild
    <Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
    <TargetFramework>netcoreapp1.0</TargetFramework>
    <UserSecretsId>aspnet-test-A18C8943-54AF-4FC4-A73D-6130613B8C7C</UserSecretsId>
    </PropertyGroup>
    <ItemGroup>
    <None Update="test.db" CopyToOutputDirectory="CopyIfNewer" />
    </ItemGroup>
    <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore" Version="1.0.3" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.0.1" />
    <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="1.0.1" />
    <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="1.0.1" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.0.2" />
    <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.0.2" PrivateAssets="All" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="1.0.2" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="1.0.2" PrivateAssets="All" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.0.0-msbuild3-final" PrivateAssets="All" />
    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.0.1" />
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.0.1" />
    <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.0.1" />
    </ItemGroup>
    </Project>

    可以看出,兩者的區別還是蠻大的。
    其他
    關于 RC4 Tools 其他 sdk 命令,和以前的沒多大區別,創建一個項目并運行的基本的流程仍然是

    dotnet new console
    dotnet restore
    dotnet build
    dotnet run



    本文地址:http://www.cnblogs.com/savorboard/p/dotnetcore-msbuild-sdk.html
    作者博客:Savorboard
    歡迎轉載,請在明顯位置給出出處及鏈接


    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(44)

    • 個人分類:生活學習
    ▲top
    • 3月 09 週四 201720:39
    • 如何一秒鐘從頭構建一個 ASP.NET Core 中間件


    文章出處
    前言

    其實地上本沒有路,走的人多了,也便成了路。 -- 魯迅


    就像上面魯迅說的那樣,其實在我們開發中間件的過程中,微軟并沒有制定一些策略或者文檔來約束你如何編寫一個中間件程序, 但是其中卻存在者一些最佳實踐的方法,大多數人來使用這種方法來使應用程序變得更加容易理解并且易于維護,這就叫“路”,在2017年,這叫套路。
    在掌握了這些套路之后,能夠幫助你迅速的搭建一個中間件的基本框架,并且易于擴展和維護,下面我們就來看看怎么樣從頭開始開發一個中間件吧。
    如果你對 ASP.NET Core HTTP 管道還不太清楚的話,下面這篇文章將有助于你對其進行一個系統的了解:
    http://www.cnblogs.com/savorboard/p/aspnetcore-http-pipeline.html
    Getting Started
    說明: 這只是通常情況下,具體的情況還請使用具體的套路。
    Setup 1 創建擴展類
    如果你的中間件需要一個向 ASP.NET Core 的 DI 容器中添加默認的一些服務的話,那么你就編寫一個需要擴展類,用來在 Startup.cs 中的 ConfigureServices 中注冊服務。
    舉例,Microsoft.AspNetCore.ResponseCompression 這是一個用來壓縮請求內容的一個中間件,那么它就需要一個服務用來處理壓縮相關的東西,所以它擴展了 IServiceCollection 并且添加了自己的 Services。
    整個中間件的核心代碼并非在這里,這里只是一個開始,那么有同學可能會問了,什么情況下我們需要提前向一個DI里面注入我們中間件需要的服務呢? 答案是,如果你不知道或者不確定你需要什么樣的服務的時候,跳過此步驟,進入下一步,再等你需要的時候再回頭來補上就是。
    那么,我們先看一下編寫一個擴展Service的靜態類應該怎么做?
    首先,新建一個以 xxxServicesExtensions 文件名結尾的靜態類,用來編寫注入DI的擴展方法。
    類建立完成之后,需要向里面添加內容了。通常情況下,中間件中 Service 的擴展方法都是以 Addxxx(this IServiceCollection services) 開頭來命名。在這里有一個需要注意的地方就是它的命名空間,通常情況下我們使用 using Microsoft.AspNetCore.Builder 這個命名空間。
    然后,方法里面就是需要注冊的服務了。假設我們需要向里面注冊一個 IResponseCompressionProvider 和 它的實現類 ResponseCompressionProvider,那么最終的擴展方法可能看起來是這樣的。

    using System;
    using Microsoft.AspNetCore.ResponseCompression;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.DependencyInjection.Extensions;
    namespace Microsoft.AspNetCore.Builder
    {
    public static IServiceCollection AddResponseCompression(this IServiceCollection services)
    {
    if (services == null)
    {
    throw new ArgumentNullException(nameof(services));
    }
    services.TryAddSingleton<IResponseCompressionProvider, ResponseCompressionProvider>();
    return services;
    }
    }

    Setup 2 創建配置類
    有的時候,用戶在使用我們編寫的中間件的時候,我們需要向提供者提供一些配置項,這些配置項在中間件執行之前用來傳遞一些必要參數信息或者是一些設置信息。舉個我們熟悉例子,我們在使用 MVC 中間件的時候,可能會看到以下寫法:

    // Startup.cs
    public void ConfigureServices(IServiceCollection services)
    {
    var userDefinedFilter = new xxxFilter();
    services.AddMvc(x => x.Filters.Add(userDefinedFilter));
    }

    可以看到,用戶可將一些自定義的 Filter 傳入到中間件的,然后中間件在運行的時候,我們傳入的 Filter 就生效了。

    注意,中間件使用的配置項有兩種添加方法,一種是添加到 AddMiddleware(Action<xxxOptions> option) 另外一種是 UseMiddleware<>(Action<xxxOptions> option),那么這兩種有什么區別呢?
    那么,前者Add中的配置項一般情況下是中間執行之前就需要的一些信息,也就是說中間件的啟動就依賴于這些配置項,他放置于容器配置(Add DI Service)的時候添加進去更加方便或者合適的時候使用它,另外一種(后者)是容器已經構建完畢,不需要依賴于容器提供的配置項可以使用此種方式。


    同樣的道理,當你自己為你的用戶編寫一個中間件的時候,當你也需要用戶可以自定義一些配置或者需要傳入一些參數的時候,你也可以這么做。那到底怎么樣做呢? 我們一起來看看。
    首先,我們需要一個 xxxOptions 結尾的配置類,用來配置我們中間件需要的一些配置項。我們還是以上面的壓縮中間件舉例。
    public class GzipCompressionProviderOptions : IOptions<GzipCompressionProviderOptions>
    {
    public CompressionLevel Level { get; set; } = CompressionLevel.Fastest;
    GzipCompressionProviderOptions IOptions<GzipCompressionProviderOptions>.Value => this;
    }

    它其中配置了一個壓縮的等級 CompressionLevel ,這是一個枚舉字段。 然后我們可以看到,這個類它繼承了 IOptions<out T> 接口,這是一個知識點,什么意思呢? IOptions<out TOptions> 是 ASP.NET Core 新的一個配置體系里面的一個接口,當你實現這個接口之后,ASP.NET Core DI 容器提供了了一個 services.Configure<xxxOptions> 這樣的方法來讓你把配置項注入到容器中,當然你也可以將配置項和 appsetting.json 中的配置關聯起來,以便于配置一些在運行期可能需要變動信息。更多關于 IOptions<T> 的信息可以看 這里的翻譯。
    這個 xxxOptions 類通常情況下會提供一些默認值,也就是說當用戶不提供這些參數的時候,你需要有一個合理的機制或者默認值來正常運行你的中間件。
    假如你的配置項有很多,也就是說還有進一步比較細化的配置,那么你可以做一個封裝,就像MVC的Options類一樣,這樣能夠給你的中間件提供更加合理的維護和擴展。
    Setup 3 核心中間件
    接下來,就是我們的核心代碼類了,通常情況下會有一個 xxxMiddleware 結尾的類用來處理 HTTP 管道請求中的一些業務,這個類的構造函數中已經可以使用在Setup1或者Setup2中向DI容器中注冊的服務了。
    按照約定,Middleware 類中需要有一個 Invoke 方法,用來處理中間件的核心業務,它的簽名如下:

    public Task Invoke(HttpContext httpContext);

    注意,這是一個約定方法,并沒有接口來約束它。在 Invoke 方法中,是中間件實現的核心代碼。 示例如下:
    public class xxxMiddleware
    {
    private readonly RequestDelegate _next;
    public xxxMiddleware(RequestDelegate next)
    {
    if (next == null)
    {
    throw new ArgumentNullException(nameof(next));
    }
    _next = next;
    }
    public async Task Invoke(HttpContext context)
    {
    // ......
    await _next(context);
    return;
    }
    }

    在 xxxMiddleware 這個里面有一個構造函數參數 RequestDelegate,它是一個委托,代表的需要執行的下一個中間件,通常情況下我們會把它放到我們業務代碼的末尾。
    Setup 4 中間件擴展注冊

    中間件有三種注冊方法(Run,Map,Use),我們暫不考慮Run和Map,因為他們只適用于很小和少的一些情況


    完成了以上工作后,接下來,我們需要把中間件注冊到我們的 ASP.NET Core 的執行,這個時候我們需要一個 xxxBuilderExtensions 類,它也是一個靜態類,注意它的命名空間通常為
    Microsoft.AspNetCore.Builder,因為這個用戶在使用我們的中間件的時候就不必再添加額外的命令空間,依靠 Visual Studio 的智能提示就可以很快速的搜索到。我們來看一下示例:

    using System;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.DependencyInjection.Extensions;
    namespace Microsoft.AspNetCore.Builder
    {
    public static class xxxBuilderExtensions
    {
    public static IApplicationBuilder UseResponseCompression(this IApplicationBuilder builder)
    {
    if (builder == null)
    {
    throw new ArgumentNullException(nameof(builder));
    }
    return builder.UseMiddleware<xxxMiddleware>();
    }
    }
    }

    Yeoman 一秒鐘
    有同學可能會說了,這些套路既然是這樣的,那么有沒有什么代碼生成工具來幫我做這些事情呢?答案是肯定的。
    博主已經幫你們把工具做好了,它使用的是當今最流行的腳手架工具 npm 中的 Yeoman 。使用它可以幫助你迅速的搭建一個中間件解決方案代碼模板,讓你專注于業務開發。
    我已經把這個模板上傳于 Yeoman 的倉庫中,你只需要按照如下命令就可以幫你自動生成一套 ASP.NET Core 中間件解決方案代碼模板了,當然單元測試也包含其中。
    npm 工具的安裝相信你自己可以的。下面是安裝 Yeoman 工具和博主的模板工具。
    // 安裝 Yeoman 腳手架工具 -g 命令為全局安裝
    npm install -g yo
    // 安裝博主的 Yeoman(ASP.NET Core Middleware)模板
    npm install -g generator-aspnetcore-middleware

    然后選擇你需要生成解決方案的文件夾,使用如下命令生成。

    yo aspnetcore-middleware

    注意:生成的過程中需要輸入你中間件的名稱。按要求輸入即可。
    總結
    本篇文章主要講述了從頭創建一個 ASP.NET Core 的流程,這適用于大多數場合,但是并不代表所有的場合,在實際開發的過程中還需要具體的考慮一下。接著博主提供了一個yo自動化腳手架模板用來快速創建一個中間件解決方案。
    如果你覺得這篇文章對你有幫助的話,謝謝你的【推薦】。
    如果你對 .NET Core 感興趣可以關注我,我會定期在博客分享關于 .NET Core 的學習心得。


    本文地址:http://www.cnblogs.com/savorboard/p/generator-aspnetcore-middleware.html
    作者博客:Savorboard
    歡迎轉載,請在明顯位置給出出處及鏈接


    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(15)

    • 個人分類:生活學習
    ▲top
    • 3月 09 週四 201720:39
    • 為 .NET Core 設計一個 3D 圖形渲染庫


    文章出處

    原文地址:https://mellinoe.wordpress.com/2017/02/08/designing-a-3d-rendering-library-for-net-core/
    作者:ERIC MELLINO
    翻譯:楊曉東(Savorboard)


    第一篇文章請看:http://www.cnblogs.com/savorboard/p/net-core-game-engine.html
    在第二篇文章中,我將探索Veldrid,這個庫為Crazy Core的游戲引擎中的所有3D和2D渲染提供支持。我將討論這個庫的作用,我為什么建立它,以及它是如何工作的。
    注意:對于本文中討論的一些內容,建議對圖形API有基本的了解。對于初學者,我建議查看下面的示例代碼,以獲得所涉及概念的一般概念。
    使用像.NET這樣的托管語言最明顯的好處之一是,您的程序可以立即移植到支持該運行時的任何系統。一旦您開始使用本地原生庫,或者依賴于其他特定于平臺的功能,此優點就會消失。那么,你如何設計一個硬件加速的3D應用程序,它能夠運行在各種操作系統和各種圖形API?好吧,你做一個抽象層,并屏蔽不利的代碼!與任何編程抽象一樣,必須非常仔細地進行權衡以隱藏復雜性,同時仍然保持強大的和表達性的編程模型。有了Veldrid,我有幾個打到的目標和非必須目標:
    VELDRID的目標
  • 允許您編寫不綁定到任何特定圖形API的抽象代碼。 提供Direct3D 11和OpenGL 3+的具體實現。


  • 遵循通常的圖形API模式。Veldrid不發明自己的符號或quirkiness(圖形API是足夠多的)。


  • 更快。 不要增加大部分的不必要的開銷。鼓勵在正常呈現循環期間不分配內存的模式,否則分配最小內存。


  • VELDRID的非必須目標
  • 允許您在不知道3D圖形概念的情況下編程3D圖形。Veldrid的接口比具體的API稍微更抽象,像OpenGL或D3D,但是暴露了相同的概念。


  • 公開單個API的所有功能。通過Veldrid暴露的概念應該可以用所有后端表達; 沒有非常好的理由,不什么應該拋出NotSupportedException。對于相同的概念,不同的性能特征是可以預期的(在允許范圍內),只要行為不是不可觀察的。


  • 特性集
  • 可編程的頂點,片段和幾何著色器

  • 頂點和索引緩沖區,包括多個輸入頂點緩沖區

  • 一個靈活的材料系統,具有頂點布局和著色器變量管理

  • 索引和實例化渲染

  • 可自定義混合,深度模板和光柵化狀態

  • 可定制的幀緩沖區和渲染目標

  • 2D和cubemap紋理

  • 向我展示代碼
    現在這一切都很好,但是使用Veldrid的程序實際上是什么樣子?更一般的是:它甚至意味著使用抽象渲染庫?為了幫助展示,我創建了適當命名的“ Veldrid微小演示 ”。讓我們走一遍代碼,看看它是如何工作的。整個項目鏈接到那些誰想要修補它。它使用新的基于MSBuild的工具為.NET核心,所以構建它是容易,快速,萬無一失。
    設置窗口

    bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
    OpenTKWindow window = new SameThreadWindow();
    RenderContext rc;
    if (isWindows && !args.Contains("opengl"))
    {
    rc = new D3DRenderContext(window)
    }
    else
    {
    rc = new OpenGLRenderContext(window);
    }
    window.Title = "Veldrid TinyDemo";

    哇,我們做了一個空白的窗口。驚人!關于“RenderContext”的其他東西是什么?所有這些方法是什么,我用它做什么?簡單地說,RenderContext是表示計算機圖形設備的核心對象。它是允許您創建GPU資源,控制設備狀態和執行低級繪圖操作的對象。
    創建設備資源
    此演示在屏幕中心繪制旋轉的3D立方體。為了做到這一點,我們需要先創建幾個GPU資源。在Veldrid中,所有圖形資源都使用ResourceFactory創建,可從RenderContext訪問。這些資源對于以前寫過圖形代碼的任何人都會很熟悉。我們需要:
  • 包含多維數據集網格頂點的頂點緩沖區

  • 包含立方體網格索引的索引緩沖區

  • “material”,它是一個含有復合對象的

  • 頂點著色器和片段著色器。

  • 頂點數據的輸入布局的描述。

  • 所使用的全局著色器參數的描述。

  • VertexBuffer vb = rc.ResourceFactory.CreateVertexBuffer(
    Cube.Vertices,
    new VertexDescriptor(VertexPositionColor.SizeInBytes, 2),
    isDynamic:false);
    IndexBuffer ib = rc.ResourceFactory.CreateIndexBuffer(
    Cube.Indices,
    isDynamic: false);

    創建一個VertexBuffer,其中包含靜態Cube類及包含簡單的3D多維數據集數據。創建一個IndexBuffer包含立方體網格的靜態索引數據。
    DynamicDataProvider<Matrix4x4> viewProjection = new DynamicDataProvider<Matrix4x4>();
    DynamicDataProvider是一個簡單的抽象,便于將數據傳輸到全局著色器參數。在這個簡單的例子中,我們只有兩個數據,我們需要發送到頂點著色器:相機的視圖和投影矩陣。為了簡單起見,我將這些組合成一個Matrix4x4。

    Material material = rc.ResourceFactory.CreateMaterial(rc,
    "vertex", "fragment",
    new MaterialVertexInput(VertexPositionColor.SizeInBytes,
    new MaterialVertexInputElement(
    "Position", VertexSemanticType.Position, VertexElementFormat.Float3),
    new MaterialVertexInputElement(
    "Color", VertexSemanticType.Color, VertexElementFormat.Float4)),
    new MaterialInputs<MaterialGlobalInputElement>(
    new MaterialGlobalInputElement(
    "ViewProjectionMatrix", MaterialInputType.Matrix4x4, viewProjection)),
    MaterialInputs<MaterialPerOjbectInputElement>.Empty,
    MaterialTextureInputs.Empty);

    可以說是示例中最復雜的部分,這創建了上面描述的“material”對象。創建此資源需要這幾個信息:
  • 頂點和片段著色器的名稱。在這種情況下,它們簡單地稱為“vertex”和“fragment”。

  • 頂點輸入數據的每個元素的描述。我們的立方體每頂點只有兩個數據:3D位置和顏色。

  • 全局著色器輸入的說明。如上所述,我們只有一個緩沖區保存一個組合的視圖 - 投影矩陣。

  • Drawing
    現在我們有了所有的GPU資源,我們可以畫出一些東西!在這個演示中,渲染發生在一個非常簡單的循環中。在循環的每次迭代時改變著色器參數,以便給立方體旋轉的外觀。

    while(window.Exists)
    {
    InputSnapshot snapshot = window.GetInputSnapshot(); //處理窗口事件。
    rc.ClearBuffer(); //清除屏幕。
    rc.SetViewport(0,0,window.Width,window.Height); //確保視口覆蓋整個窗口,以防它被調整大小。
    float timeFactor = Environmental.TickCount / 1000f ; //得到粗略的時間估計。
    viewProjection.Data =
    //根據當前時間創建一個旋轉的相機矩陣。
    Matrix4x4.CreateLookAt(
    new Vector3(2 *(float)Math.Sin(timeFactor),(float)Math.Sin(timeFactor),2 *(float)Math.Cos(timeFactor)
    Vector3.Zero,//總是看世界的起源。
    Vector3UnitY)
    //將它與透視投影矩陣組合。
    * Matrix4x4.CreatePerspectiveFieldOfView(1.05f,(浮動)window.Width / window.Height。5F,10F);
    rc.setVertexBuffer(vb); //附加多維數據集頂點緩沖區。
    rc.SetIndexBuffer(ib); //附加立方體索引緩沖區。
    rc.SetMaterial(material); //附加材料。
    rc.DrawIndexedPrimitives(Cube.Indices.Length); //繪制多維數據集。
    rc.SwapBuffers(); //交換回緩沖區并將場景呈現到窗口。
    }}

    首先,屏幕被清除,并且視口被設置為覆蓋整個屏幕。早些時候,我說我們將渲染一個“旋轉3D立方體”。更準確地說,雖然,攝影機本身圍繞著坐在世界原點的靜態立方體旋轉。當“ viewProjection.Data ”被賦值時,矩陣值被傳播到頂點著色器的 “viewProjection”變量中。我們將我們先前創建的三個資源綁定到RenderContext,調用DrawIndexedPrimitives,然后交換上下文的后臺緩沖區,它將呈現的場景呈現給窗口。
    在上面的代碼中一個明顯的事情是,沒有提到任何具體的圖形API(除了上下文創建)。所有示例代碼都將在OpenGL和Direct3D上工作和運行相同。完整的項目可以在GitHub上的項目頁面上找到 ; 我鼓勵你下載它并且嘗試運行!
    場景的背后
    在這些調用背后都發生了什么?讓我們用兩個例子深入一點。
    VertexBuffer vb = rc.ResourceFactory.CreateVertexBuffer(
    Cube.Vertices,
    new VertexDescriptor(VertexPositionColor.SizeInBytes, 2),
    isDynamic:false);

    熟悉OpenGL的人將知道頂點緩沖區存儲在稱為VBO的特殊對象中,熟悉Direct3D的人員使用通用的“緩沖區”來存儲大量不同的東西。當OpenGL后端被要求創建一個VertexBuffer時,它會為你創建一個VBO,填充你的頂點數據,并存儲該緩沖區的輔助信息。Direct3D后端通過創建和填充 ID3D11Buffer對象來做同樣的事情。
    “VertexBuffer”本身是一個接口,用于顯示對頂點緩沖區有用的操作,例如設置頂點數據,檢索它,以及將緩沖區映射到CPU的地址空間。該Direct3D11和OpenGL此后端的每個返回一個VertexBuffer,一個自己版本衍生的D3DVertexBuffer 或OpenGLVertexBuffer,他們的操作是通過特定的調用到每個這些圖形API的實現。這種相同的模式用于Veldrid中可用的所有圖形資源。
    下一個例子是從主渲染循環:
    rc.DrawIndexedPrimitives(Cube.Indices.Length); //繪制多維數據集。
    具體來說,這是什么?讓我們來看看 OpenGL 的代碼:
    public override void DrawIndexedPrimitives(int count,int startingIndex)
    {
    PreDrawCommand();
    DrawElementsType elementsType =((OpenGLIndexBuffer)IndexBuffer).ElementsType;
    int indexSize = OpenGLFormats.GetIndexFormatSize(elementsType);
    GL.DrawElements(_primitiveType,count,elementsType,new IntPtr(startingIndex * indexSize));
    }}

    DrawIndexedPrimitives被翻譯成單個呼叫glDrawElements,并且參數被從存儲在RenderContext(原始類型)以及當前綁定的IndexBuffer(索引數據的格式)的狀態中拉出。
    Direct3D的后臺做了什么?
    public override void DrawIndexedPrimitives(int count, int startingIndex, int startingVertex)
    {
    _deviceContext.DrawIndexed(count, startingIndex, startingVertex);
    }

    該調用簡單地轉換為ID3D11DeviceContext :: DrawIndexed。當Vertex和IndexBuffers綁定到RenderContext時,所有其他相關狀態已經設置。
    如果你看了代碼,有一件事你會注意到,雖然大多數圖形資源在Veldrid被返回并且作為接口交換,代碼在每個后端將它們作為強類型的對象。例如,D3D后端總是假定它將傳遞D3DVertexBuffer或D3DShader。這意味著,如果由于某種原因嘗試將OpenGLVertexBuffer傳遞到D3DRenderContext,您將遇到災難性的異常。在帖子結束關于這個設計決定有關于我的想法。
    哪些工作正常,哪些不是
    庫是如何呈現我所要達到的目標呢?這是相當不錯的事情:
  • API是連貫的,并且暴露了一個好的功能集,同時保持API的封裝。

  • 這些概念是相似的,你可以通常遵循OpenGL或D3D教程,并將這些概念很容易地映射到Veldrid。

  • 在后端代碼中有足夠數量的“API泄漏”可能被黑客攻擊。OpenGL和D3D是相似的,我可以在大多數差異,而不失去大量的功能或速度。

  • 示例:如果幀緩沖區未綁定深度紋理,則OpenGL需要(全局)禁用深度測試。D3D似乎不關心這個,或在內部處理它。因此,當無深度幀緩沖器被綁定時,OpenGL后端禁用全局深度測試狀態,即使當前綁定的深度狀態應該被啟用。這種類型的問題不會泄漏到使用庫的最終用戶,但它確實會使一個干凈的實現變得有點丑。

  • 性能好。這不是“zero-cost abstraction”,但是抽象足夠薄。

  • 單獨的后端能夠跟蹤GPU狀態,延遲或省略沒有效果的呼叫。例如,如果使用相同的頂點數據一個接一個渲染的兩個對象。那么第二個對象對SetVertexBuffer()和SetIndexBuffer()的調用將基本上是無操作的,避免了昂貴的GPU狀態變化。

  • OpenTK和SharpDX都是非常好的,薄的,快速的包裝器為相應的圖形API。在需要時調用它們的開銷很小。

  • 在后端之間切換是微不足道的。該Veldrid RenderDemo 支持在運行OpenGL和Direct3D之間切換(無需重新啟動)。

  • 另一方面,這里是我在使用庫后的幾個我的項目中的幾個最大的問題:
  • 沒有統一的著色器代碼。您需要單獨編寫GLSL和HLSL代碼,這樣做的方式與D3D和OpenGL后端的工作方式相同。這意味著著色器需要暴露相同的輸入(統一/常量緩沖區),相同的頂點布局,相同的紋理輸入等。其他人如何處理?

  • Unity,Xenko:這些使用自定義著色語言。這是一個干凈的解決方案,但是巨大比我做的更復雜。

  • MonoGame,Unreal:自動著色器轉換。這里的方法是根據需要將單個著色器語言翻譯成許多。這可能相當簡單,取決于你愿意接受多少晦澀的語法。

  • 材質規格很詳細。上面的Tiny Demo的例子顯示了創建一個簡單的Material對象的詳細程度。有可能所有必要的信息可以通過著色器反射(使用OpenGL和D3D),但我沒有這樣做。

  • 沒有多線程支持。OpenGL是眾所周知的(不可用的)多線程,但D3D11后端可以很容易地與重新設計的API線程。

  • 資源創建是不尋常的,因為不使用構造函數。如果沒有每個對象中的間接級別,或者使用重新設計的程序集架構,這將很難解決(請參閱“Veldrid v2的想法”中的最后一個要點)。

  • 有一些泄漏到API中的東西應該放到另一個幫助庫中。一個更清潔的設計只會在核心庫中包含非常低級的概念,而其他的則在頂層。

  • “VELDRID V2” 的一些想法
    Veldrid的初始版本對我非常有用,我學到了很多東西。潛在“v2”版本的庫我已經建立了一個很長的改進列表。
    對庫的最明顯的改進是添加額外的后端實現。理想情況下,該庫的下一代版本將至少支持OpenGL ES和Vulkan以及現有的D3D11和OpenGL 3+后端。最重要的是,這將給我選擇在iOS和Android上運行,這是目前無法使用D3D或“完整”的OpenGL。實際上,這將是實施最昂貴的功能,但也是最有影響力的。
    正如我上面提到的,初始庫的一個明顯的問題是它不支持多線程渲染。像Vulkan這樣的API被明確地設計為用于多線程應用程序, 很明顯,線程是解決現代圖形庫的一個重要問題。在較小的程度上,甚至direct3d11,這已經在Veldrid支持,具有在我的庫中未使用的線程功能。我懷疑這個功能自然會落在下一代設計的支持Vulkan和其他現代圖形API的庫。
    我已經在Veldrid的當前版本提到材料的問題,這是一個顯然需要在v2中進行大修的領域。很難說,改進的版本將看起來是什么樣子,像沒有為庫的其余部分設計,但至少它需要減少冗長的代碼,和改進當前版本的一些缺陷。
    由于上述特性很可能需要重新構建庫的大部分代碼,我認為另一個核心部分需重新考慮,即在公共API中使用接口和抽象類將是有趣的。Veldrid是一個單個程序集,它包含單個API不可知界面的多個實現。這意味著您可以在運行時而不是部署時決定是使用Direct3D還是OpenGL,還可以在運行時切換API。另一方面,由于涉及接口和虛分派(virtual dispatch),該方法帶有一定級別的運行時開銷。大多數其他3D圖形層使用編譯時專門化,而不是運行時/接口專門化。我想探討是否可以使用替代方法,涉及“誘餌和轉換”技術用于一些PCL項目。自定義AssemblyLoadContext可用于加載使用特定圖形API的特定版本的Veldrid.dll。這將允許您保留當前方法的靈活性,而不需要接口或一些虛分派(virtual dispatch)。
    Veldrid是一個在我的GitHub頁面可以獲得的開源項目。它使用新的基于MSBuild 的.NET Core 工具,可以從任何針對.NET Standard 1.5或更高版本的項目中使用。


    本文地址:http://www.cnblogs.com/savorboard/p/designing-a-3d-rendering-library-for-net-core.html
    本譯文僅用于學習和交流目的。非商業轉載請注明譯者、出處,并保留文章在譯言的完整鏈接。
    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(18)

    • 個人分類:生活學習
    ▲top
    • 3月 09 週四 201720:39
    • ASP.NET Core Loves JavaScript


    文章出處
    前言
    在 ASP.NET 團隊的 Github 的主頁上,有這樣一個開源項目叫:“JavaScriptsServices”,那么
    什么是 JavaScriptsServices 呢? 它又有什么用呢?
    下面就讓我們一起來看一下吧。
    什么是 JavascriptServices
    GitHub:https://github.com/aspnet/JavaScriptServices
    JavascriptServices 是微軟提供給 ASP.NET Core 開發者的一項技術,如果你使用的是 Angular2,React,Knockout等這些Javascript技術之一的話, 他提供了一些基礎的程序集供開發者來很方便的調用Javascript,同時,你可以很方便的整合 NodeJS 代碼到你的ASP.NET Core應用程序中。
    JavascriptServices 是提供給開發者一套工具,目前已經以NuGet包的形式釋出,主要包括這三個程序集:
    Microsoft.AspNetCore.NodeServices,Microsoft.AspNetCore.SpaServices,Microsoft.AspNetCore.AngularServices。
    還有一個包叫ReactServices,現在已經不需要它了,你可以使用 SpaServices 替代之。
    現在就來分別看一下這三個包吧。
    必須的環境:
    1、NodeJS 環境,可以在程序目錄下使用node -v,來查看是否具有Node環境。
    2、ASP.NET Core 環境,可以在程序目錄下使用 dotnet --version,來查看是否具有 dotnet 環境。
    NodeServices
    NodeServices 是一個基礎包,它主要是提供了在 .NET 程序 Server 端運行 Javascript 的功能,要做到這一點,他是利用了NodeJS 的環境。來看看怎么樣使用吧。
    首先新建一個 ASP.NET Core WebApi 項目,然后在項目根目錄新建一個Node文件夾,然后添加一個 addNumbers.js的文件,
    文件內容如下:
    module.exports = function (callback, first, second) {
    var result = first + second;
    callback(null /* error */, result);
    };

    這里有有個JS函數,它將在.NET 程序中被調用,通過傳入一個 Node風格的回調函數和兩個參數來計算結果。
    在NodeJS中,一個 JS 文件即代表一個模塊,module.exports的意思是把當前函數作為一個對象提供出去以供調用。
    然后在 Controller 文件夾新建一個 NodeController.cs 的文件。整個解決方案看起來是這個樣子的:
    為了使用 NodeServices,你需要 using Microsoft.AspNetCore.NodeServices,然后在 Startup.cs 文件中的 ConfigureServices 方法添加如下:
    public void ConfigureServices(IServiceCollection services)
    {
    // ... 其他代碼 ...
    // 啟用 Node Services
    services.AddNodeServices();
    }

    現在,你就可以在 Action 中使用NodeServices庫為我們提供的功能了,打開NodeController.cs,修改如下:
    using Microsoft.AspNetCore.NodeServices;
    [Route("api/[controller]")]
    public class NodeController : Controller
    {
    public async Task<IActionResult> Get([FromServices] INodeServices nodeServices) {
    var result = await nodeServices.InvokeAsync<int>("./Node/addNumbers", 1, 2);
    return Content("1 + 2 = " + result);
    }
    }

    這里使用的是 [FromServices] 解析的INodeServices接口來供我們使用調用Node Javascript。然后我們再看一下InvokeAsync<T>(``),他是一個異步的方法,通過傳入一個node.js腳本文件(模塊),兩個形參 來得到一個結果。

    方法簽名: Task InvokeAsync(string moduleName, params object[] args);



    然后,我們使用 Postman 來測試一下:
    結果符合預期,現在,我們已經在ASP.NET Core 程序中成功的調用了Node提供的Javascript腳本服務,是不是很方便。
    SpaServices
    SpaServices 這個包是基于 NodeServices 構建的,當你基于單頁面應用(SPA)來構建應用程序的話,它為你提供了很多很有用的助手工具,像 路由助手(Routing)、服務端的預渲染(Pre-Rendering) 、Webpack中間件 、模塊熱替換(HMR)等。 下面來依次看一下:
    Routing helper
    在單頁面應用程序中,也許你想同時配置服務端路由以及配置客戶端路由,大多數時候,這兩個路由系統將互不干擾獨立運行。但是有些時候可能會有問題,就是怎么樣識別404。
    這個時候你可能就會用到 Routing helper ,它叫MapSpaFallbackRoute, 它將幫助你更加方便的做這個工作。
    app.UseStaticFiles();
    app.UseMvc(routes =>
    {
    routes.MapRoute(
    name: "default",
    template: "{controller=Home}/{action=Index}/{id?}");
    routes.MapSpaFallbackRoute(
    name: "spa-fallback",
    defaults: new { controller = "Home", action = "Index" });
    });

    Pre-Rendering
    你可以創建一個同構的(Isomorphic )JavaScript 服務器預渲染的應用。對于 isomorphic web app 可能了解的人不是特別多,就是說一套JS代碼可能同時運行于服務端和客戶端,是不是很有趣,利用這種技術有助于提高SEO(搜索引擎優化)和客戶端性能。
    Webpack
    如果你正在使用 webpack,那么 SpaServices 里面的 webpack 中間件將簡化你的開發過程,使用此中間件將會攔截webpack匹配的文件請求并且在內存中動態構建,然后直接到瀏覽器中。
    HMR
    使用這種技術,你可以減少大幅減少模塊加載的時間,通過啟用中間件的HMR支持,在你對磁盤上的文件(如 .ts/.html/.sass 等)做出更改的時候,會自動構建,然后會把結果推到瀏覽器上,你就不需要手動的去刷新瀏覽器了。
    app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions {
    HotModuleReplacement = true
    });

    這個包還包含了很多其他的一些功能,有興趣的可以去 github 了解一下。
    AngularServices
    AngularServices 主要提供了一些擴展的工具,包括一些驗證助手,還有一些"cache priming"的功能。
    示例模板
    你可以通過 yeoman 工具來生成基于 Angular2、Knockout、React、React+Redux 等的ASP.NET Core SPAs 示例模板。
    npm install -g yo generator-aspnetcore-spa
    npm install -g webpack

    然后創建項目:
    yo aspnetcore-spa
    可以選擇Angular2、Knockout、React、React+Redux等來生成SPA項目,生成完成后以開發環境方式啟動項目:
    Windows:
    set ASPNETCORE_ENVIRONMENT=Development
    dotnet run

    Linux 或 masOS:
    export ASPNETCORE_ENVIRONMENT=Development
    dotnet run

    現在,你就可以感受一下基于 ASP.NET Core + SPA 的應用了。
    試著對項目做更多你熟悉的操作吧:比如修改客戶端資源(.ts, .tsx, .html),看看瀏覽器的變化吧。
    總結
    這是一套對于ASP.NET Core開發者來說非常方便的工具在構建 JavaScripts 應用程序服務時候,目前該庫目前也在快速的迭代中,也許提供出來的這些功能只是一個開始……
    如果你覺得本篇博客對您有幫助的話,感謝您的【推薦】,如果你對 .NET Core 感興趣可以關注我,我會定期在博客分享關于 .NET Core 的學習心得。


    本文地址:http://www.cnblogs.com/savorboard/p/dotnet-javascript-services.html
    作者博客:Savorboard
    歡迎轉載,請在明顯位置給出出處及鏈接


    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(125)

    • 個人分類:生活學習
    ▲top
    • 3月 09 週四 201720:39
    • ASP.NET Core 之 Identity 入門(一)


    文章出處
    前言
    在 ASP.NET Core 中,仍然沿用了 ASP.NET里面的 Identity 組件庫,負責對用戶的身份進行認證,總體來說的話,沒有MVC 5 里面那么復雜,因為在MVC 5里面引入了OWIN的東西,所以很多初學者在學習來很費勁,對于 Identity 都是一頭霧水,包括我也是,曾經在學 identity 這個東西前后花了一個多月來搞懂里面的原理。所以大部分開發者對于 Identity 并沒有愛,也并沒有使用它,會覺得被綁架。
    值得慶幸的是,在 ASP.NET Core 中,由于對模塊的抽象化逐漸清晰,以及中間件的使用,這使得 Identity 的學習和使用路線變得更加平易近人,下面就讓我們一起來看看吧。
    Getting Started
    在開始之前,讓我們先忘記它和Entity Framework的關系,也忘記它和Authentication的關系,我們先學習幾個英語單詞。
    有這么幾個“單詞”你可能需要弄明白:
    # 1: Claims
    大家應該都知道身份證長什么樣子的,如下:
    其中,姓名:奧巴馬;性別:男;民族:肯尼亞;出生:1961.08.04,等等這些身份信息,可以看出都是一個一個的鍵值對,那如果我們想在程序中存這些東西,怎么樣來設計呢?對,你可能想到了使用一個字典進行存儲,一個Key,一個Value剛好滿足需求。但是Key,Value的話感覺不太友好,不太面向對象,所以如果我們做成一個對象的話,是不是更好一些呢?最起碼你可以用vs的智能提示了吧,我們修改一下,改成下面這樣:
    //我給對象取一個名字叫`Claim`你沒有意見吧
    public class Claim
    {
    public string ClaimType { get; set; }
    public string ClaimValue { get; set; }
    }

    ClaimType 就是Key,ClaimValue就代表一個Value。這樣的話,剛好可以存儲一個鍵值對。這時候姓名:奧巴馬是不是可以存進去了。
    微軟的人很貼心,給我們準備了一些默認的ClaimType呢?很多常用的都在里面呢,一起看看吧:

    這里延伸第一個知識點:ClaimTypes


    為了閱讀體驗,截圖我只放了一部分哦。可以看到有什么Name,Email,Gender,MobilePhone等常用的都已經有了,其他的還有很多。細心的讀者可能注意了,它的命名空間是System.Security.Claims,那就說明這個東西是.net 框架的一部分,嗯,我們暫時只需要知道這么多就OK了。
    Claim 介紹完畢,是不是很簡單,其他地方怎么翻譯我不管,在本篇文章里面,它叫 “證件單元”。
    # 2: ClaimsIdentity
    在有了“證件單元”之后,我們就用它可以制造一張身份證了,那么應該怎么樣制造呢?有些同學可能已經想到了,對,就是新建一個對象,然后在構造函數里面把身份證單元傳輸進去,然后就得到一張身份證了。我們給這張身份證取一個英文名字叫 “ClaimsIdentity”,這個名字看起來還蠻符合的,既有 Claims 表示其組成部分,又有表示其用途的 Identity(身份),很滿意的一個名字。
    實際上,在現實生活中,我們的身份證有一部分信息是隱藏的,有一部分是可以直接看到的。比如新一代的身份證里面存儲了你的指紋信息你是看不到的,這些都存儲在身份證里面的芯片中,那能看到的比如姓名啊,年齡啊等。我們在設計一個對象的時候也是一樣,需要暴露出來一些東西,那這里我們的 ClaimsIdentity 就暴露出來一個 Name,Lable等。
    我們造的身份證(ClaimsIdentity)還有一個重要的屬性就是類型(AuthenticationType),等等,AuthenticationType是什么東西?看起來有點眼熟的樣子。我們知道我們自己的身份證是干嘛的吧,就是用來證明我們的身份的,在你證明身份出示它的時候,其實它有很多種形式載體的,什么意思呢?比如你可以直接拿出實體形式的身份證,那也可以是紙張形式的復印件,也可以是電子形式的電子碼等等,這個時候就需要有一個能夠表示其存在形式的類型字段,對,這個AuthenticationType就是干這個事情的。
    然后我們在給我們的身份證添加一些潤色,讓其看起來好看,比如提供一些方法添加 Claims 的,刪除 Claims的,寫到二進制流里面的啊等等,最終我們的身份證對象看起來基本上是這樣了:
    public class ClaimsIdentity
    {
    public ClaimsIdentity(IEnumerable<Claim> claims){}
    //名字這么重要,當然不能讓別人隨便改啊,所以我不許 set,除了我兒子跟我姓,所以是 virtual 的
    public virtual string Name { get; }
    public string Label { get; set; }
    //這是我的證件類型,也很重要,同樣不許 set
    public virtual string AuthenticationType { get; }
    public virtual void AddClaim(Claim claim);
    public virtual void RemoveClaim(Claim claim);
    public virtual void FindClaim(Claim claim);
    }

    嗯,到這里,我們的身份證看起來似乎很完美了,但是從面向對象的角度來說好像還少了點什么東西? 對~,還是抽象,我們需要抽象出來一個接口來進行一些約束,約束什么呢?既然作為一個證件,那么肯定會涉及到這幾個屬性信息:
    1、名字。2、類型。3、證件是否合法。
    反應到接口里面的話就是如下,我們給接口取個名字叫:“身份(IIdentity)”:

    這里延伸第二個知識點:IIdentity接口。


    // 定義證件對象的基本功能。
    public interface IIdentity
    {
    //證件名稱
    string Name { get; }
    // 用于標識證件的載體類型。
    string AuthenticationType { get; }
    //是否是合法的證件。
    bool IsAuthenticated { get; }
    }

    所以我們的 ClaimsIdentity 最終看起來定義就是這樣的了:
    public class ClaimsIdentity : IIdentity
    {
    //......
    }

    ClaimsIdentity 介紹完畢,是不是發現也很簡單,其他地方怎么翻譯我不管,在本篇文章里面,它叫 “身份證”。
    # 3: ClaimsPrincipal
    有了身份證,我們就能證明我就是我了,有些時候一個人有很多張身份證,你猜這個人是干嘛的? 對,不是黃牛就是詐騙犯。
    但是,有些時候一個人還有其他很多種身份,你猜這個人是干嘛的?這就很正常了對不對,比如你可以同時是一名教師,母親,商人。如果你想證明你同時有這幾種身份的時候,你可能需要出示教師證,你孩子的出生證,法人代表的營業執照證。
    在程序中,一個身份證不僅僅代表你這個人了,而是代表一個身份,是證明你自己的主要身份哦。如果一個人還有其他很多種身份,這個時候就需要有一個東西(載體)來攜帶著這些證件了對吧?OK,我們給需要攜帶證件的這個對象取一個貼切點的名字,叫“證件當事人(ClaimsPrincipal)”吧。

    以下是 Principal 這個單詞在詞典給出的解釋,我用它你應該沒意見吧:


    principal ['prɪnsəpl] 
    adj. 主要的;資本的
    n. 首長;校長;資本;當事人

    這個時候可能有同學會問了,是不是應該叫ClaimsIdentityPrincipal比較好呢?嗯,我也覺得應該叫 ClaimsIdentityPrincipal 可能更好一點,或許微軟的人偷懶了,簡寫成了ClaimsPrincipal。
    知道其功能后,代碼就很好寫了,和上面ClaimsIdentity一樣的套路:
    public class ClaimsPrincipal
    {
    //把擁有的證件都給當事人
    public ClaimsPrincipal(IEnumerable<ClaimsIdentity> identities){}
    //當事人的主身份呢
    public virtual IIdentity Identity { get; }
    public virtual IEnumerable<ClaimsIdentity> Identities { get; }
    public virtual void AddIdentity(ClaimsIdentity identity);
    //為什么沒有RemoveIdentity , 留給大家思考吧?
    }

    當時人看起來也幾乎完美了,但是我們還需要對其抽象一下,抽象哪些東西呢? 作為一個當事人,你應該有一個主身份吧,就是你的身份證咯,可能你還會用到角色(角色后面會詳細介紹,這里你知道有這么個東西就行了)。

    這里延伸第三個知識點:IPrincipal 接口。


    public interface IPrincipal
    {
    //身份
    IIdentity Identity { get; }
    //在否屬于某個角色
    bool IsInRole(string role);
    }

    然后,我們的 證件當事人 看起來應該是這樣的:
    public class ClaimsPrincipal : IPrincipal
    {
    //...
    }

    ClaimsPrincipal 介紹完了,也很簡單吧? 其他地方怎么翻譯我不管,在本篇文章里面,它叫 “證件當事人”。
    想在,我們已經知道了 “證件單元(Claims)” , “身份證(ClaimsIdentity)” , “證件當事人(ClaimsPrincipal)”,并且整理清楚了他們之間的邏輯關系,趁熱打鐵,下面這個圖是一個identity登入部分的不完全示意圖,虛線圈出來的部分應該可以看懂了吧:
    可以看出,首先我們在app這邊有一些證件單元,然后調用ClaimsIdentity把證件單元初始化為一個身份證,然后再把身份證交給證件當事人由其保管。

    才把 Getting Started 寫完,發現已經這么長了,所以打算寫成一個系列了,可能3 - 4篇吧。


    總結
    好了,本篇就先介紹到這里,在本篇博客中,我們學會了幾個英文單詞,并且知道了這些英文單詞在程序中是扮演這怎么樣一個對象。并且根據圖我們知道了這些對象在整個認證系統種處在怎么樣一個位置。 我發現如果想把 identity 講清楚僅僅靠這一篇博客是不夠的,下一篇我們將對.NET Authentication中間件進行抽絲剝繭,直到掌握.NET的整個認證系統后,我們再來看一下 Identiy 到底和 Entity Framework 有著怎樣的愛恨情仇。
    這僅僅是一個開始,大家如果覺得本篇博客對您有幫助的話,感謝您的【推薦】,如果你對 .NET Core 感興趣可以關注我,我會定期在博客分享關于 .NET Core 的學習心得。


    本文地址:http://www.cnblogs.com/savorboard/p/aspnetcore-identity.html
    作者博客:Savorboard
    歡迎轉載,請在明顯位置給出出處及鏈接


    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(32)

    • 個人分類:生活學習
    ▲top
    • 3月 09 週四 201720:38
    • ASP.NET Core 之 Identity 入門(二)


    文章出處
    前言
    在 上篇文章 中講了關于 Identity 需要了解的單詞以及相對應的幾個知識點,并且知道了Identity處在整個登入流程中的位置,本篇主要是在 .NET 整個認證系統中比較重要的一個環節,就是 認證(Authentication),因為想要把 Identity 講清楚,是繞不過 Authentication 的。
    在之前寫過一篇關于 ASP.NET Core 中間件的文章,里面有一部分(怎么樣自定義自己的中間件)是具體關于認證系統的一個具體使用,有興趣的朋友可以看一下這篇文章。
    其實 Identity 也是認證系統的一個具體使用,大家一定要把 Authentication 和 Identity 當作是兩個東西,一旦混淆,你就容易陷入進去。
    下面就來說一下 ASP.NET Core 中的認證系統是怎么樣一回事。不要怕,其實很簡單,全是干貨~
    Getting Started
    大家應該還記得在上一篇中的奧巴馬先生吧,他現在不住在華盛頓了,他到中國來旅游了,現在住在北京,這幾天聽說西湖風景不錯,于是在 12306 定了一張北京到杭州的高鐵票。取到票之后,他向我們展示了一下:
    今天是11.11號,奧巴馬很開心,原因你懂的。快到出發的時間了,于是,拿著票走到了火車站檢票口,剛把身份證和火車票遞給檢票員。“cut”,導演喊了一聲。尼瑪原來是在拍電影呢~
    導演說:奧巴馬,你演的太爛了,別演了,你來演檢票員吧,讓旁邊小李來演要出行路由的奧巴馬吧。奧巴馬不情愿的說了一聲:“好吧,希望小李能夠受的了你”。
    “action”,導演又喊了一聲,故事開始了~
    AuthenticationManager
    奧巴馬當了檢票員以后,特別高興,因為他有權利了呀,他可以控制別人能不能上車了,說不定還能偷偷放幾個人進去撈點外快呢。
    得知了他能干什么以后,他覺得檢票員這個名字簡直太 low 了,很快,他就有了一個新的高大上的名字,叫:認證管理員(AuthenticationManager),而且,他覺得他自己應該處在整個核心位置,為什么呢?你想想看,那么龐大的一套鐵路載人系統,能不能有收入有錢賺,全靠他給不給放人進去,如果一個人都不放進去,另外那一大幫人只能去喝西北風了。
    到這里,聰明的同學可能已經知道奧巴馬把他自己放在怎么樣一個核心位置了。對,他把自己放到了 HttpContext 里面。怎么樣? 夠核心吧。

    這里延伸第一個知識點:AuthenticationManager 所處的位置


    有同學在上面的截圖里面發現了 public abstract ClaimsPrincipal User { get; set; }, 這不就是我們上一篇中講到的 “ 證件當事人 ” ,現在小李扮演的那個角色么? 對,這個 User 就是本文中的小李,被你提前發現他躲著這里了,嘿嘿。
    還有一個知識點,就是 AuthenticationScheme,什么意思呢? 且看
    奧巴馬敢把自己放在這么核心的位置也是有他的能力的,怎么講呢? 比如說在檢票的時候,別人遞過來一張身份證和一張火車票,那怎么樣驗證這兩個證件是合法的呢? 以下就是奧巴馬提出的針對兩種證件的驗證方案:
    方案1、針對身份證的驗證,可以查看其本人是否和身份證頭像是否一致,年齡是否符合當事人具體年齡。
    方案2、針對火車票的驗證,可以看車次,時間是否符合發車目標,另外可以看車票上的身份號碼是否和身份證一致。
    其中,這每一種方案,就對應一個 AuthenticationScheme(驗證方案名稱),是不是明白了。

    這就是第二個知識點 AuthenticationScheme 很重要。


    知道了奧巴馬的職責后,就很容易的把代碼寫出來了:
    public abstract class AuthenticationManager
    {
    //AuthenticateContext包含了需要認證的上下文,里面就有小李
    public abstract Task AuthenticateAsync(AuthenticateContext context);
    //握手
    public abstract Task ChallengeAsync(string authenticationScheme, AuthenticationProperties properties, ChallengeBehavior behavior);
    //登入
    public abstract Task SignInAsync(string authenticationScheme, ClaimsPrincipal principal, AuthenticationProperties properties);
    //登出
    public abstract Task SignOutAsync(string authenticationScheme, AuthenticationProperties properties);
    }

    奧巴馬做為一個檢票員,有一個認證方法,AuthenticateAsync() ,注意這是其一個核心功能,其他幾個都可以沒有,但是唯獨不能沒有這個功能,沒有的話他就不能稱之為一個檢票員了。
    然后還有一個握手ChallengeAsync,登入SignInAsync和登出SignOutAsync,下面說說筆者對這三個方法的理解吧。
    ChallengeAsync:是社區協議文件 RFC2167 定義的關于在HTTP Authentication 過程中的一種關于握手的一個過程,主要是摘要認證(digest authentication),更多信息查看這里。
    是不是有點專業,看不懂,沒事,有通俗版本的。 小李要進站了,這個時候小李問了一下我們的檢票員奧巴馬先生。
  • 小李:“你好,檢票員,我可以進站嗎?”

  • 檢票員奧巴馬:“要趕火車嗎?可以啊,請出示你的證件?”

  • 小李:“好的,這是我的證件,你檢查一下?”

  • 檢票員奧巴馬:“嗯,證件沒問題,進去吧”

  • 這樣一個過程就是握手(digest-challenge)或者叫問答的一個過程,明白了 ChallengeAsync 的原理了吧? 是不是很簡單。
    SignInAsync,SignOutAsync:個人覺得這兩個不應該放在這里,因為并不屬于認證的職責,也不屬于協議規定的內容。但是這兩個方法確實需要抽象,應該單獨抽取一個接口存放,至于為什么這樣做,或許是因為以下原因:
    1、對登入登出的抽象是和認證緊密結合的,大多數情況下認證資料的保存是需要在SignIn進行的,比如 Cookies Authentication 中間件就在SignIn方法里面做了Cookie的保存。
    2、 AuthenticationManager 這個對象是處在 HttpContext
    上下文里面的,本著面向抽象和封裝的原則,放到其里面是合適的,這樣能夠很方便的用戶對其調用。
    關于 AuthenticationManager 已經介紹完了,是不是很簡單呢?
    IAuthenticationHandler
    有些同學可能會問了,如果 AuthenticationManager 不提供接口的話,只是一個抽象類的話,那如果自定義認證方法就必須繼承它,這對于開發者來說是不友好的,也違背了面向接口編程的理念。嗯,確實是這樣,那么接口來了:
    public interface IAuthenticationHandler
    {
    void GetDescriptions(DescribeSchemesContext context);
    Task AuthenticateAsync(AuthenticateContext context);
    Task ChallengeAsync(ChallengeContext context);
    Task SignInAsync(SignInContext context);
    Task SignOutAsync(SignOutContext context);
    }

    這個接口是在 AuthenticationManager 實現類 DefaultAuthenticationManager 中延伸出來的,所以大家不用再去看里面的源碼了,記住以后如果需要重寫認證相關的東西,實現IAuthenticationHandler就可以了。
    Authentication 中間件
    對 IAuthenticationHandler 的初步實現,封裝了 AuthenticationHandler 這個抽象類,把具體的核心功能都交給下游去實現了,下面的CookieAuthentication 中間件核心類 CookieAuthenticationHandler 就是繼承自AuthenticationHandler, 知道這么多就夠了。
    CookieAuthentication 中間件
    故事還要繼續,奧巴馬在接到小李遞來的身份證和火車票之后,首先拿著火車票在一個二維碼機器上掃描了一下,然后又拿著身份證在一個機器上刷了一下,經過核查,發現都沒有問題。于是拿起印章在上面蓋了一個 “ 驗訖 ”。
    這中間都發生了什么呢?
    首先,在二維碼掃描的過程,這個過程二維碼機器會解析你火車票上的二維碼,如果發現解析失敗,會直接響應認證失敗。也就是你別想進站了。
    如果解析成功,就會得到你這個票據中的信息了,然后拿到你票據里面的的當事人信息進行驗證是否被列為了鐵路局黑名單中。
    如果驗證通過,則會給你頒發一個識別碼,把符合你身份的一個識別碼寫入到你的火車票中和檢票員旁邊的電腦系統中,即 “ 驗訖 ”。
    話說這個驗訖有點高級,它會向你的火車票芯片中寫入一些信息,那么都寫入些什么信息呢? 1、奧巴馬個人的信息。2、驗證途中的一些上下信息。3、使用的驗證方案。
    知道了,這些之后,那么就很容易實現這個驗證方法了,對吧? 以下是 CookieAuthentication 中間件中的核心類 CookieAuthenticationHandler 的里面的核心方法HandleAuthenticateAsync(),同樣你可以理解為實現的 IAuthenticationHandler 接口的 AuthenticateAsync:
    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
    // 解析二維碼
    var result = await EnsureCookieTicket();
    if (!result.Succeeded)
    {
    return result;
    }
    // 從二維碼中拿當事人信息進行驗證
    var context = new CookieValidatePrincipalContext(Context, result.Ticket, Options);
    await Options.Events.ValidatePrincipal(context);
    if (context.Principal == null)
    {
    return AuthenticateResult.Fail("No principal.");
    }
    if (context.ShouldRenew)
    {
    RequestRefresh(result.Ticket);
    }
    // 驗訖, 寫入芯片
    return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Options.AuthenticationScheme));
    }

    HandleSignInAsync
    我們故事繼續……
    奧巴馬檢票完成之后,把票就交給了小李,小李拿到票之后,導演又喊了一聲:“ cut ”……
    怎么又停了,小李和奧巴馬一肚子的疑惑,導演說:“ 奧巴馬呀,你檢票員演的不錯,還是繼續扮演你的本職角色吧,演好了中午盒飯給你雙份,小李,你來演檢票員吧 ”。
    可以吃兩份盒飯了,奧巴馬聽后心里還是很開心。
    “action” 導演喊了一聲……
    奧巴馬接過票,向著車站里面的列車停車處走去,走到了列車門口要進去的時候,又出現了一個人,奧巴馬知道,這個人就是做車內乘客登記的(ps: 一般情況下,做乘客登記都是在列車行駛的過程中,在這里我們假設這個做乘客登記的人比較勤快,就在車門口守著),登記完成之后就讓奧巴馬進去了。
    那么,登記這個過程中都干了些什么呢?
    首先,登記員的手持設備會解析火車票票里面寫入芯片中的信息,發現沒有問題,就開始向自己手里面的登記本登記信息了,主要包含車票主人信息,過期時間,審核人等。
    這樣整個過程就是 HandleSignInAsync 的一個過程,換成程序術語就是,組裝 Cookie 登入上下文信息,寫入到 Http 流的 header 中,也就寫入到了客戶端瀏覽器cookie。
    至此,整個過程就完了,我們來看一下代碼:

    //方法里面的流程,我只列出了核心部分,影響閱讀的全刪了
    protected override async Task HandleSignInAsync(SignInContext signin)
    {
    // 解析芯片中的信息
    var result = await EnsureCookieTicket();
    // 組織登入上下文,設置過期時間等
    // 使用 data protected 加密登記本上的信息
    var cookieValue = Options.TicketDataFormat.Protect(ticket);
    // 寫入到瀏覽器header
    await ApplyHeaders(cookieValue);
    }

    不想深入了解的可以忽略這部分內容:
    在 HandleSignInAsync 這個函數的源碼中,其中有一個很巧妙的設計, 就是 await Options.Events.SignedIn(signedInContext); 這樣一句代碼,干什么用的呢? 而且前后一共調用了兩次,有同學知道是為什么嗎? 我準備在下一篇中給出答案。


    還記得前面 HttpContext 中的ClaimsPrincipal User嗎? 就是小李臨時頂替的那個角色,現在有值了,他就是是奧巴馬了。
    奧巴馬在座位上坐好之后,經過6個小時的路程就從北京到杭州了,不得不佩服中國高鐵的速度呀,在欣賞晚西湖的風景后,奧巴馬給我們傳來了一張照片:
    至此,CookieAuthentication 中間件的整個工作流程已經講完了,故事也結束了。
    以上,就是這兩行代碼背后的故事:
    var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "奧巴馬") }, CookieAuthenticationDefaults.AuthenticationScheme));
    await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);

    總結
    在本篇中我們知道了 AuthenticationManager,也知道了 IAuthenticationHandler 并且簡單的介紹了一下 Authentication 中間件和 CookieAuthentication 中間件,其中 CookieAuthentication 中間件是我們以后使用最多的一個中間件了,本篇也對其做了一個詳細的介紹,我想通過本篇文章在以后使用的過程中應該問題不大了。
    有同學可能會問了,講了這么多認證的東西它和 Identity 有什么關系呢? 難道我通篇都在隱藏他和 Identity 的關系你沒看出來?。。。。真的想知道? 看下一篇吧。
    順便給自己打個廣告:成都地區有推薦工作的么?有意聯系右上角。
    如果覺得本篇博客對您有幫助的話,感謝您的【推薦】,如果你對 .NET Core 感興趣可以關注我,我會定期在博客分享關于 .NET Core 的學習心得。


    本文地址:http://www.cnblogs.com/savorboard/p/aspnetcore-identity2.html
    作者博客:Savorboard
    歡迎轉載,請在明顯位置給出出處及鏈接


    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(401)

    • 個人分類:生活學習
    ▲top
    • 3月 09 週四 201720:38
    • ASP.NET Core 1.1.0 Release Notes


    文章出處
    ASP.NET Core 1.1.0 Release Notes
    We are pleased to announce the release of ASP.NET Core 1.1.0!
  • Antiforgery

  • AspNetCoreModule

  • AzureIntegration

  • BasicMiddleware

  • Caching

  • Common

  • Configuration

  • CORS

  • DataProtection

  • DependencyInjection

  • Diagnostics

  • DotNetTools

  • EntityFramework

  • EventNotification

  • FileSystem

  • Hosting

  • HtmlAbstractions

  • HttpAbstractions

  • Identity

  • IISIntegration

  • JsonPatch

  • KestrelHttpServer

  • Localization

  • Logging

  • MetaPackages

  • Data.Sqlite

  • Mvc

  • MvcPrecompilation

  • Options

  • PlatformAbstractions

  • Razor

  • RazorTooling

  • ResponseCaching

  • Routing

  • Security

  • Session

  • StaticFiles

  • WebListener

  • WebSockets

  • (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(2)

    • 個人分類:生活學習
    ▲top
    • 3月 09 週四 201720:38
    • Entity Framework Core 1.1 升級通告


    文章出處

    原文地址:https://blogs.msdn.microsoft.com/dotnet/2016/11/16/announcing-entity-framework-core-1-1/
    翻譯:楊曉東(Savorboard)


    Entity Framework Core(EF Core)是一個輕量級的,可擴展和實體框架的跨平臺版本。今天,我們宣布 Entity Framewor Core 1.1 正式可用了。
    EF Core 和 .NET Core 遵循相同的發行周期。每2個月不斷的改進和每6個月的新功能發布。這是自1.0的第一個功能版本。
    請務必閱讀位于這個帖子的末尾的升級到1.1這個章節,有相關升級到1.1版本重要信息。
    1.1 版本有什么
    1.1版本的重點是解決人們采用EF Core 中遇到的問題。這包括修正了bug,增加了一些的那些尚未在EF Core實現的重要功能。雖然我們已經取得了這方面的一些良好的進展,但是我們也承認EF Core 仍然不會是對大家來說最好的選擇,更多詳細信息可以看這篇 EF Core和EF6.x比較。
    Bug修復
    在1.1版本有包含超過100個bug的修復。參見 EF Core 1.1 版本說明了解更多詳情。
    改進LINQ翻譯
    在1.1版本中,我們在提高Linq 對 EF Core 的支持取得了良好的進展。這使得更多的查詢成功執行,有更多的邏輯在數據庫進行執行(而不是在內存中)。
    DbSet.Find
    DbSet.Find(...)是存在于EF6.x并在 EF Core 中比較常見的一個 API。它可以讓你方便地查詢基于其主鍵值的實體。如果實體已經加載到上下文,則它直接返回而不再次查詢數據庫。
    using (var db = new BloggingContext())
    {
    var blog = db.Blogs.Find(1);
    }

    映射字段
    新的流式API HasField(...) 方法 允許你在屬性中配置一個數據庫不同名字的字段。
    這對于只讀屬性是非常有用的,而不是一個 get / set的屬性。有關詳細的指導,請參閱我們的文檔中的Backing Field相關文章。
    public class BloggingContext : DbContext
    {
    ...
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
    modelBuilder.Entity<Blog>()
    .Property(b => b.Url)
    .HasField("_validatedUrl");
    }
    }

    顯式加載
    顯式加載允許您加載DBContext上下文中跟蹤到的實體的導航屬性里面的內容。欲了解更多信息,請參見我們的文檔中的加載相關數據文章。
    using (var db = new BloggingContext())
    {
    var blog = db.Blogs.Find(1);
    db.Entry(blog).Collection(b => b.Posts).Load();
    db.Entry(blog).Reference(b => b.Author).Load();
    }

    從 EF6.x 增加的 EntityEntry的API
    我們已經加入在EF6.x.是可用的但是還沒有添加到 EF Core 中的EntityEntry的相關 API, 這包括 Reload(), GetModifiedProperties(), GetDatabaseValues() 等。這些API一般通過 DbContext.Entry(object entity) 調用。
    彈性連接
    彈性連接將會自動重試失敗的數據庫命令。SQL Server提供了一個專門針對SQL Server的執行策略(包括SQL Azure的)。識別到異常類型,可以重試并且為最大重試設置合理的默認值,重試之間的延遲等。更多信息,可以在我們的文檔請參閱彈性連接的文章。
    其實一個就是給你的數據庫上下文配置執行策略,在 ASP.NET Core 應用程序中,通常情況下是在 OnConfiguring方法中,或者是在 Startup.cs 里面。
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
    optionsBuilder
    .UseSqlServer(
    "connection string",
    options => options.EnableRetryOnFailure());
    }

    支持 SQL Server 內存優化表
    內存優化表是SQL Server 2014+ 的功能。現在,您可以指定一個實體映射到內存優化表。欲了解更多信息,請參閱我們的文檔中的內存優化表文章。
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
    modelBuilder.Entity<Blog>()
    .ForSqlServerIsMemoryOptimized();
    }

    簡化 service 替換
    在EF Core 1.0中你可以取代EF使用其內部服務,但這是很復雜的,需要你拿到 EF依賴注入容器的控制權來使用。在1.1中,這個要簡單得多。在配置上下文時候使用ReplaceService(...) 方法就行了。在 ASP.NET Core 應用程序中,這通常是在Startup.cs 文件中的 OnConfiguring(...) 方法中。
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
    optionsBuilder.UseSqlServer("connection string");
    optionsBuilder.ReplaceService<SqlServerTypeMapper, MyCustomSqlServerTypeMapper>();
    }

    升級到1.1
    如果您正在使用的EF團隊提供的連接數據庫的程序包(SQL Server, SQLite, InMemory),那就升級提供的程序包就行了。
    PM> Update-Package Microsoft.EntityFrameworkCore.SqlServer
    如果您使用的是第三方數據庫提供程序,檢查一下看看他們是否已經發布新版本,它取決于1.1.0更新。如果他們有,那么就升級到新版本。如果沒有, 那么你應該能夠升級他們依賴的EF Core Relational 組件。大部分的新特性數據庫組件提供者在1.1不需要修改。我們已經做了一些測試,以確保數據庫提供商依賴1.0和1.1,但沒有做詳盡的測試。
    PM> Update-Package Microsoft.EntityFrameworkCore.Relational
    升級工具包
    如果您正在使用Tools 工具包,那肯定就要升級了。需要注意的是Tools版本為 1.1.0-preview4 因為Tools還沒有達到其穩定版本。
    PM> Update-Package Microsoft.EntityFrameworkCore.Tools -Pre
    如果你在使用 ASP.NET Core,使用dotnet ef命令,那么你需要更新 project.json 的Tools部分使用新 Microsoft.EntityFrameworkCore.Tools.DotNet 包取代 Microsoft.EntityFrameworkCore.Tools 1.0 的包。由于.NET Cli,所以對我們來說分離dotnet ef到這個單獨的包已經是必要的了。
    json
    "tools": {
    "Microsoft.EntityFrameworkCore.Tools.DotNet": "1.1.0-preview4"
    },



    本文地址:http://www.cnblogs.com/savorboard/p/efcore11-announcing.html
    作者博客:Savorboard
    歡迎轉載,請在明顯位置給出出處及鏈接


    (繼續閱讀...)
    文章標籤

    AutoPoster 發表在 痞客邦 留言(0) 人氣(14)

    • 個人分類:生活學習
    ▲top
    «1...91011230»

    pop-under

    參觀人氣

    • 本日人氣:
    • 累積人氣:

    線上人數

    Marquee

    最新文章

    • 文章列表
    • jvm系列(四):jvm調優-命令大全(jps jstat jmap jhat jstack jinfo)
    • spring boot(一):入門篇
    • jvm系列(一):java類的加載機制
    • jvm系列(三):java GC算法 垃圾收集器
    • spring boot 實戰:我們的第一款開源軟件
    • jvm系列(六):jvm調優-從eclipse開始
    • 混合應用技術選型
    • jvm系列(二):JVM內存結構
    • spring boot(五):spring data jpa的使用

    熱門文章

    • (1,763)jQuery之前端國際化jQuery.i18n.properties
    • (1,001)Oracle Hint
    • (630)技術筆記:Indy控件發送郵件
    • (515)linux下安裝sqlite3
    • (501)學習筆記: Delphi之線程類TThread
    • (242)VC單選按鈕控件(Radio Button)用法(轉)
    • (104)單條件和多條件查詢
    • (51)淺談config文件的使用
    • (22)基于 Asp.Net的 Comet 技術解析
    • (15)Java中的抽象類

    文章分類

    • 生活學習 (2,296)
    • 未分類文章 (1)

    最新留言

    • [20/04/24] 我是女生想約炮 有男生願意給我溫暖的嗎?我賴是woyou58 於文章「(1)從底層設計,探討插件式GIS框架的...」留言:
      我叫黎兒女生最近內心掙扎著要不要約炮我的line:woy...

    文章搜尋

    文章精選

    誰來我家

    Live Traffic Feed