基於 Vue.js 之 iView UI 框架非工程化實踐記要 使用 Newtonsoft.Json 操做 JSON 字符串 基於.net core實現項目自動編譯、並生成nuget包 webpack

基於 Vue.js 之 iView UI 框架非工程化實踐記要

 

Markdown

像咱們平日裏作慣了 Java 或者 .NET 這種後端程序員,對於前端的認識還經常停留在 jQuery 時代,包括其插件在須要時就引用一下,不須要就刪除。故觀念使然,儘管 Nuget 和 Maven 用得順溜,但對 NPM 仍不帶感,興許是周邊無人帶動的稀薄氣氛,也或者是沒參加過相似的大型活動,因而在自發性上差了許多。再者,我不用 MVVM 模式,領導也不會扣績效。javascript

爲了快速體驗 MVVM 模式,我選擇了非工程化方式來起步,並選擇使用 Vue.js,以及基於它構建的 iView UI 框架。css

Vue.js 是美籍華人尤雨溪創做的,那會兒他還在 Google 工做,他自感 Angular.js 繁雜,進而自創了更爲簡潔易用的 Vue.js。html

iView UI 是由 90 後梁灝[hào]創做,網名 Aresn,在大數據公司 TalkingData 負責可視化基礎架構,更了不得的是他還出了《Vue.js實戰》一書,我是在「雙十一」的前一天買的,行文措詞簡潔,表意直達困惑,入門很迅速,是我喜歡的風格。花了一週時間掃完了前十二章內容,用 WebStorm 練習了大部分實例,儘管書中用一整章內容介紹了 webpack 工程化構建方案,但因爲我慣性使然,仍是選擇對其跳過而使用了非工程化方式來體驗 Vue.js,其實多少有失暴殄。無奈,畢竟才學了一週,後期時間充裕了再接着分享工程化構建的學習心得吧。前端

1、 MVVM 模式

Vue.js 比較顯著的特徵是解耦了視圖和數據,也就是說視圖的變化再也不須要命令式編程去顯式改變,只要修改完數據就能當即自動同步,這是比較大的一個思惟模式的轉變,另外一個就是組件化思惟俯首皆是,這樣開發一個應用就至關是在搭積木。vue

其實以上對 Vue.js 所闡述的優勢也正是 MVVM 模式的寫照,它原是由 MVC 所衍生,即當視圖層發生變化時,會自動更新到視圖模型上,反之亦然,這就是常說的雙向綁定,上一張圖吧:java

Markdown

甭管這圖是否好理解,通俗地來說,MVVM 這種模式拆分了視圖和數據,這樣咱們在開發時只要關心數據自己便可,而後視圖 DOM 這方面會由 Vue.js 自動解決。webpack

2、非工程化起步

爲了能支撐起一個最基本的應用,須要引入如下幾個必要文件:git

  1. vue.min.2.5.3.js,vue.js 庫
  2. iview.2.7.0.css,iView 樣式文件
  3. iview.min.2.7.0.js,iView 庫
  4. iview /locale/zh-CN.js 語言包
  5. iview /font 字體包

下載 Vue.js

來到 Github 上的 Vue 項目,直接下載 Zip 源碼:程序員

Markdown

在 dist 目錄中就能夠找到 vue.js 文件:es6

Markdown

根據不一樣的環境選擇一個版本便可,至此第 1 步就搞定了。

下載 iView 系列文件

在 iView 官網的「組件」 / 「安裝」 頁面的開頭處發現了這個連接:https://unpkg.com/iview/ ,經過它能夠查看到 dist 目錄:

Markdown

必要文件都在這裏,這些文件沒法打包下載,我採起的笨辦法是逐個點開,而後複製其中的內容。

在獲取 iView 相關的 js 和 css 方面還有一個辦法,仔細觀察官網給出的 CDN 地址分別爲:

我嘗試將它們放在瀏覽器裏進行訪問:

Markdown

發現地址有變動,不過這並沒有大礙。

至此,將各個文件放在指望的位置便可:

Markdown

該圖中各文件的擺放並非很嚴謹,你們按本身習慣來便可。

3、實例演練

完成以上的準備工做後,就能夠結合 iView UI 來正式開發了,接下來基於 table 表格組件演示一下購物車的基本操做。

引入資源

通過起步工做的籌備,能夠在新建頁面中逐個地引入這些資源。

HTML head 部分
<head> <meta charset="UTF-8"> <title>購物車實例</title> <link rel="stylesheet" href="iViewContent/iview.2.7.0.css"> <script src="utility_js/vue.min.2.5.3.js"></script> <script src="utility_js/iview.min.2.7.0.js"></script> <script src="iViewContent/locale/zh-CN.js"></script> <script> iview.lang('zh-CN'); </script> </head>

按一向的方式引用,樣式居前,隨後緊跟着 vue.js 和 iView.js,以及 iView 中文語言包 zh-CN.js,而後當即調用 lang 方法使其生效。

綁定數據

首先把數據綁定起來,從而看一看總體效果,至於其餘的行爲操做先無論:

Markdown

HTML body 部分
<body> <div id="app"> <i-table id="datatable1"  size="small"  :columns="columns"  :data="cartList"  stripe  highlight-row> </i-table> </div> <script src="iViewUI_cart.js"></script> </body>

組件 i-table 最核心的兩個屬性分別是 columns 和 data,columns 是列定義,data 則爲數據。

這兩個屬性都添加了冒號(:)語法糖,它指代的是 v-bind 指令,表示這個屬性的值是動態綁定的,這樣在運行過程當中發現數據有變動時,表格視圖也會迅速的變動。

iViewUI_cart.js 腳本部分
var cart = new Vue({ el: '#app', data: function () { return { cartList: [ {id: 1, name: 'iPhone X', price: 8300.05, count: 1}, {id: 2, name: 'MacBook Pro', price: 18800.75, count: 3}, {id: 3, name: 'Mate 10 Porsche', price: 16600.00, count: 8} ], columns: [ { title: '名稱', key: 'name' }, { title: '單價', key: 'price' }, { title: '數量', key: 'count' } ] } }, methods: {} });

該文件是與頁面對應的業務腳本,整個文件就負責 new 一個 Vue 實例,並將其賦值給了變量 cart,能夠看到的 data 包含了兩個屬性,即表示數據源的 cartList 和 列定義的 columns,兩者正好與上述 i-table 的核心屬性相映射。

再次值得注意的是 data,它的值須要以匿名函數的形式進行書寫,即:

function () { return {} }

如此,在其 columns 中出現的 Render 函數體內才能正常經過 this 訪問到 methods 中定義的方法。固然本次演示是經過 cart 對象來訪問,故不受此影響。

運行頁面後,數據便可綁定成功。

添加操做所需按鈕

數據呈現出來後,就能夠補充必要的按鈕了:

Markdown

這一步簡單,只須要修改一下 columns 屬性,追加一項「操做」列,添加三個按鈕:

{ title: '數量', key: 'count' }, { title: '操做', render: (h, params) => { return h('div', [ h('Button', { props: { type: 'primary', size: 'small' }, style: { marginRight: '5px' }, on: { click: () => { console.info('減小數量'); cart.reduceQuantity(params.row.id); } } }, '-'), h('Button', { props: { type: 'primary', size: 'small' }, style: { marginRight: '5px' }, on: { click: () => { console.info('增長數量'); cart.increaseQuantity(params.row.id); } } }, '+'), h('Button', { props: { type: 'error', size: 'small' }, style: { marginRight: '5px' }, on: { click: () => { console.info('刪除當前項'); cart.deleteItem(params.row.id); } } }, '刪除') ]); } }

在這裏使用到了 Render 函數,該函數的內部機制略顯複雜,做爲初步演示只需依樣畫葫蘆便可。

說到 Render 函數,還須要再強調一下在其內部對 methods 中所定義方法的調用,若是試圖經過 this 來調用方法(好比 reduceQuantity),那麼 Vue 實例中 data 的值須要使用匿名函數的方式來表達;反之,如果經過 Vue 實例 cart 來調用,則無此顧慮,即 data 的值使用一向的對象大括號({})來表達便可。

添加操做所需方法

操做按鈕已經添加成功了,那就須要有對應的方法去執行,在 Vue.js 中,方法都定義在 methods 屬性中。

減去數量

首先關注一下「減去數量」的定義:

methods: { reduceQuantity: function (id) { for (let i = 0; i < this.cartList.length; i++) { if (this.cartList[i].id === id) { this.cartList[i].count--; break; } } } }

經過遍歷找到目標記錄,並將其 count 屬性減一,如同 MVVM 的定義,當數據變動的時候,視圖也跟隨着變化。

但凡是存在於購物車內的商品,其數量至少應該爲 1,爲防止減到 0,不妨再加一個判斷使其邏輯更爲完美:

methods: { reduceQuantity: function (id) { for (let i = 0; i < this.cartList.length; i++) { if (this.cartList[i].id === id) { if (this.cartList[i].count > 1) { this.cartList[i].count--; } break; } } } },
增長數量
methods: { increaseQuantity: function (id) { for (let i = 0; i < this.cartList.length; i++) { if (this.cartList[i].id === id) { this.cartList[i].count++; break; } } } }

只須要針對 count 屬性作 +1 操做便可。

刪除
deleteItem: function (id) { for (let i = 0; i < this.cartList.length; i++) { if (this.cartList[i].id === id) { // 詢問是否刪除 this.$Modal.confirm({ title: '提示', content: '肯定要刪除嗎?', onOk: () => { this.cartList.splice(i, 1); }, onCancel: () => { // 什麼也不作 } }); } } }

在刪除邏輯中,當遍歷到目標記錄時,會詢問用戶是否真的要刪除當前記錄,這裏用到了 $Modal 對話框,若是用戶點擊肯定,那麼就執行真正的刪除,看一看效果:

Markdown

很是漂亮考究的 iView Modal 對話框,使人賞心悅目,一見鍾情。

至此,針對 Vue.js 和 iView 框架的體驗就告一段落,後面抽時間再學習一下組件和 Render 函數,提高一下內功修養。

 

 

 

對 Newtonsoft.Json 的應用能夠說司空見慣,在 JSON 格式層級不深的狀況下使用很方便,但有時遇到的 JSON 字符串層級很是多,且真正須要的數據每每都「埋」得很深,這時若是去定義一個與之對應的多層嵌套實體類就顯得不划算,下面經過實例來演示如何一步到位抓取到指望的數據(集)。

1、把實體類轉化爲 JSON 字符串

1. 爲實體類賦值

SenderFromMQSearch senderFromMQSearch = new SenderFromMQSearch(); senderFromMQSearch.StartTime = new DateTime(2017, 9, 10); senderFromMQSearch.EndTime = new DateTime(2017, 9, 10); senderFromMQSearch.FlowType = "DataSender";

2. 序列化

經過簡單的序列化後,能夠將 C# 實體類轉換爲 JSON 格式的字符串

string paramsText = JsonConvert.SerializeObject(senderFromMQSearch);

轉換後其格式相似以下:

{\"StartTime\":\"2017-09-10\", \"EndTime\":\"2017-09-10\", \"FlowType\":\"DataSender\", \"SiteNo\":\"\"}

2、提取 JSON 字符串中部分屬性的值

JSON 屬性的值有多種類型,好比 String、Array 等,經過屬性提取到對應的值時須要特別留意這些類型,從而作出正確地轉化。

好比現藉助上面的查詢實體類,以及前文介紹的 Chloe.ORM 查詢到一段結果集,其形式如同這樣一段 JSON 字符串:

{ "Status": true, "Msg": "成功", "Data": { "SiteData": [ { "SiteNo": "200012", "SiteName": "上海公司", "Total": 100 }, { "SiteNo": "214001", "SiteName": "無錫分銷部", "Total": 200 } ] } }

並將該字符串存儲在變量 resultText 中。

1. JObject

將其轉化爲 JSON 對象,即 JObject:

JObject jObj = JObject.Parse(resultText);

接着能夠嘗試獲取"Data"屬性的值:

jObj["Data"].ToString();

其值的形式爲:

{ "SiteData": [ { "SiteNo": "200012", "SiteName": "上海公司", "Total": 100 }, { "SiteNo": "214001", "SiteName": "無錫分銷部", "Total": 200 } ] }

2. JArray

這時發現,真正指望的值其實還在屬性「SiteData」裏面,那不如索性一步到位:

jObj["Data"]["SiteData"].ToString();

此時,其值的形式爲:

[
  { "SiteNo": "200012", "SiteName": "上海公司", "Total": 100 }, { "SiteNo": "214001", "SiteName": "無錫分銷部", "Total": 200 } ]

可見這是一個數組格式的字符串,能夠嘗試將其轉化爲數組對象,即 JArray:

JArray siteDataArray = JArray.Parse(jObj["Data"]["SiteData"].ToString());

3. JArray 轉換爲 List

對於該數組中的每個對象,都存在三個屬性:SiteNo、SiteName,以及 Total,爲了更方便地操做這些數據,能夠考慮泛型集合。

首先來定義實體類:

public class SiteInfo { public string SiteNo { get; set; } public string SiteName { get; set; public int Total { get; set; } }

能夠看出,實體類的屬性實際上與數組中每個對象的屬性相對應。

接着來遍歷一下這個數組,對於數組中的每個對象都會有一個實體對象(siteInfo)與之對應,而後將該實體對象(siteInfo)逐個地添加至泛型集合(siteInfoList)便可。

List<SiteInfo> siteInfoList = new List<SiteInfo>(); foreach (var item in siteDataArray) { SiteInfo siteInfo = new SiteInfo(); siteInfo.SiteNo = item["SiteNo"].ToString(); siteInfo.SiteName = item["SiteName"].ToString(); siteInfo.Total = (int)item["Total"]; siteInfoList.Add(siteInfo); }

至此,核心數據就倒騰到泛型集合中,接下來藉助 Linq 就能夠玩各類花樣了。

 

 

近期想對本身的項目增長自動編譯並生成nuget包,網上資料很多。但總還有迷糊的時候。首先:此解決方案包含多種版本的項目,如:有編譯必須是x86平臺,以及還有傳統的.net foramework項目,以及多版本的.net core項目等。找到通用的解決方案仍是用了很多的時間。本文章就對此作下自我總結。望對同仁有所幫助。

1、遇到的問題,以及解決辦法

1.1 不一樣平臺的編譯怎麼辦

      .net能夠將dll(或者說是項目)編譯成x8六、x6四、anycpu 等至少三種平臺代碼。但若是用dotnet build生成項目時,默認是anycpu,須要經過platform參數來執行平臺。但是,若是你一個解決方法中即有x86項目、又有anycpu項目可怎麼是好呢。解決辦法:建立兩個sln文件,一個用x86平臺的編譯,一個用於anycpu平臺的編譯。

1.2 傳統.net framework項目,怎麼用dotnet 進行編譯

這個問題其實最終的解決辦法也很簡易,就是將.net framework項目直接遷移成dotnet 可編譯的項目。步驟以一個.net 4.6.1項目爲例:

  • 傳統的.net framework項目

  • 卸載此項目,並編輯.csproj文件

當前步驟編輯好的.csproj文件以下:

複製代碼
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net461</TargetFramework>
  </PropertyGroup> 

</Project>
複製代碼
  • 移除Properites中的assemblyInfo文件

由於dotnet 會自動建立assemblyInfo相關的信息文件,若是要自定義,能夠找到相關資料進行限制

注意,少了assemblyinfo.cs文件。

  • 還原相關引用

生成項目,根據提示引用相關類型,默認調整後的是 類庫 文件,若是須要變成 應用執行程序,能夠本身修正便可。

  • 生成並運行

在還原好依賴項,以及調整好輸出類型後,便可完成 項目的遷移。最終的項目結果:

以及最終生成的csproj文件:

複製代碼
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net461</TargetFramework>
    <ApplicationIcon />
    <OutputType>Exe</OutputType>
    <StartupObject />
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\src\SAM.Configuration\SAM.Configuration.csproj" />
    <ProjectReference Include="..\..\src\SAM.Framework\SAM.Framework.csproj" />
  </ItemGroup> 

</Project>
複製代碼
  • 多版本的支持

     若是你須要的項目即能在.net40,.net461, .net core2.0上運行,那就須要作到多版本兼容。方式即爲簡單,須要將TargetFramework改成TargetFrameworks,而後多版本用分號隔開便可:

<TargetFrameworks>net461;net40;netcoreapp2.0</TargetFrameworks>

2、統一實現

在解決了上述三個主要問題以後,實現自動編譯和出包就很簡單。咱們能夠寫一個ps1文件來實現,也就是powershell腳本,總體代碼以下:

複製代碼
#定義全局變量

$destFolder = Get-Location;
$version = "1.0.0.0-alpha";

#編譯anycpu的包
$anycpuPath = $destFolder.Path + "\..\SAM.Framework.anycpu.sln";
dotnet pack $anycpuPath --output $destFolder.Path /p:PackageVersion=$version;

#編譯x86的包
$anycpuPath = $destFolder.Path + "\..\SAM.Framework.x86.sln";
dotnet pack $anycpuPath --output $destFolder.Path /p:PackageVersion=$version /p:platform=x86;

pause
複製代碼

是否是很簡單,幾句代碼就是實現將全部項目生成nuget包。且還能夠分平臺實現。核心參數說明:

  • /p:是設置msbuild相關參數的入口,如:包版本(版本在dotnet core上好像此支持三個階段,如:1.0.0這種,而四階段沒有了),以及平臺等。
  • --output:生成的包輸出文件夾

此命令還有些不足點,如 anycpu和x86中都編譯同一個項目,後者的編譯會覆蓋前者(感受能夠用nuget包依賴來解決)。

3、後話

     在解決此問題以前,本人也走了很多的彎路。如尋找msbuild與dotnet build的兼容方案,以及如何動態修正sln文件等,但還好最終仍是解決解決。回過頭來看,其實遇到問題換個角度,打開思惟纔是最重要的。

 

 

 

上週的某一天,和一位一樣是前端技術極度愛好的開發者朋友聊天,他在提出了一個問題,他寫的vue程序爲何在dev模式運行良好,而在production模式就直接報錯了。這讓我感到驚訝,還有這麼神奇的事情。今就把這個歷險記道給大夥聽聽,看能從中學習到什麼?

1、還原現場

朋友在看到個人驚訝後,分分就把他出錯的demo發給了,本地運行,事故現場重現: image

2、排查嫌疑對象

既然現象是必現,要麼是本身的代碼出了問題,要麼就是vue有Bug(內心莫名的偷笑,大夥都懂的)。

2.1 代碼文件結構和源碼展現

image
從代碼結構看,沒有好說的。就是用vue-cli建立的模板開發項目,其保增長了service層而已。通過我多年來的經驗,將嫌疑放到了service/index.js和components/HellowWorld.vue兩個文件上。

  • service/index.js代碼
複製代碼
let item = {};
item.result = 22222;
item.do = callBack => {
  return callBack({ result: this.a.result });
};

export default item;
複製代碼
  • HelloWorld.vue代碼(只展現了js代碼部分)
複製代碼
import service from "@/service/index"
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  mounted () {
    service.do(item => {
      this.msg = item.result
    })
  }
}
複製代碼

簡要邏輯說明:

  • HelloWorld.vue引用了service/index.js文件
  • service/index.js中定義了do方法,且接受一個callback參數(使用了es6的箭頭函數)
  • HelloWorld.vue在mounted方法中調用了do方法,且傳入了一個函數表達式(也使用了箭頭函數)

2.2 報錯位置偵查

經過運行結果對比圖,能夠看出production模式下的運行是有報錯,在達裏咱們放大他的報錯位置:
image
     看到這裏,你是否有想破口大罵的衝動,怎麼會this.a.result呢,這代碼明顯有錯誤吧。而後我迅速查閱了他給的demo代碼,見service/index.js中的do方法,確實是怎麼樣寫的。馬上,我略帶鄙視的口吻質問個人那位朋友,你這個幾年的代碼白寫了吧,竟然能犯這麼低級的錯誤。我直接把這個錯誤現場圖扔給了他。   

     立刻,他回了一個更爲鄙視的表情,那爲何個人dev模式能正常運行呢。我當即無語且尷尬。由於確實他的dev模式運行是正常的,只有在production模式下才出的問題啊。

2.3 重點分析嫌疑對象

    通過上述的分析和折騰,咱們能夠初步肯定問題點就在service/index.js中do方法中和this上。也就是說在dev模式下這個this.a上是有result這個屬性的,而在production模式下this連這個a屬性都沒有了。

     做爲老鳥的我,忽然想到,dev模式和production模式都是運行在有sourcemap的的狀況下的。這很不利用咱們看編譯後的代碼。因而,我關閉了chrome瀏覽器的sourcemap功能,兩種模式下代碼以下:

  • dev模式下的運行代碼:
    image
    注意三個紅框處的代碼,webpack在dev模式下代碼文件是沒有合併成一個文件的,而是遵行commanJs規範,進行模式化加載的,而他對這個service/index.js這個模式導出時,用的名稱正是a。也就是解釋了在dev模式下this.a爲何會有效,他的this.a.result有值,則是由於他雖然是單文件模式化加載,但其文件中的js代碼仍是被bable作了轉換,將箭頭運算符轉換爲了es5可執行的代碼。因此this.a.result是有值的。

 

  • production模式下的運行代碼:
    image
         看這段代碼是否有些頭大,其實從中咱們只須要關心l這個變量的值,經測試發現,他的值不service/index.js中導出的對象,而是瀏覽器全局對象window。這就是爲何production模式下的代碼不能正常運行的問題了。

3、個人推理和總結

      經過上述分析,能夠大體推理出webpack在dev模式下是按照commonJs模式將各個文件獨立模式化加載和引用,而Build以後,各個文件模塊被合併成了一個,且對servcie/index.js進行了直接導出。再中上箭頭函數對this指向的處理,就形成了this.a無效了。
     在這個demo中就算把service/index.js中的this指向處理好了,但其值仍是會正常顯示,緣由在於vue組件中的mounted方法中也用到了箭頭函數,其this的指向在運行時也會不正確。具體解釋以下:

注意,不要在實例屬性或者回調函數中(如 vm.$watch('a', newVal => this.myMethod()))使用箭頭函數。由於箭頭函數綁定父級上下文,因此 this 不會像預想的同樣是 Vue 實例,並且 this.myMethod 是未被定義的。

vue官網說明地址:https://cn.vuejs.org/v2/guide/instance.html

3.1 緣由總結

  • this.a爲何能夠訪問,是由於webpack的dev下編譯是單個文件模式化引用致使的
  • vue組件的mounted中用不可以使用箭頭函數,這個vue的特性,官網可見。
  • 示例代碼下載

 

 

這樣入門asp.net core 之 靜態文件

 

本文章主要說明asp.net core中靜態資源處理方案:

1、靜態文件服務

首先明確contentRoot和webroot這兩個概念

  • contentRoot:web的項目文件夾,其中包含webroot和其餘bin等其餘文件夾
  • webroot:webroot是站點文件夾,可用url訪問的文件夾。默認爲:"contentroot/wwwroot"
  • 實現代碼以下
    Program中的代碼
複製代碼
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
    .UseKestrel()
    .UseContentRoot(Directory.GetCurrentDirectory()) //設置contentroot
    .UseWebRoot("mywwwroot") //設置webroot
    .UseUrls("http://*:5000") //其餘電腦能夠用ip地址訪問
    .Build();
複製代碼

     StartUp中的代碼

複製代碼
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseStaticFiles();//開啓靜態文件訪問
    //自定義靜態文件訪問
    app.UseStaticFiles(new StaticFileOptions(){
        FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "mystatic")),
        RequestPath = new PathString("/sam/static")
    });
     //配置mvc
    app.UseMvc(routers=>{
        routers.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });
}
複製代碼

效果圖下圖:
image

1.1 目錄瀏覽

實現代碼以下:

複製代碼
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{  
    app.UseDirectoryBrowser(new DirectoryBrowserOptions(){
        FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Controllers")),
        RequestPath = new PathString("/controller")
    }); 
}
複製代碼

image

1.2 默認文檔

app.UseDefaultFiles方法開啓默認訪問的配置,配置項用DefaultFilesOption類表示,代碼以下:

複製代碼
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{  
    //默認文件
    DefaultFilesOptions defaultFiles = new DefaultFilesOptions();
    defaultFiles.DefaultFileNames.Clear();
    defaultFiles.DefaultFileNames.Add("myindex.html");
    app.UseDefaultFiles(defaultFiles); 
    
    app.UseStaticFiles(); //開啓靜態文件訪問
}
複製代碼

注意此配置必定要在全部Use以前,不然設置不生效

1.3 UseFileServer

UserFileServer包含了UseStaticFiles, UseDefaultFiles, UserDirectoryBrowser的功能

複製代碼
app.UseFileServer(new FileServerOptions(){
    EnableDefaultFiles, //是否開啓默認文檔
    EnableDirectoryBrowsing, //是否開啓目錄瀏覽
    DefaultFilesOptions, //默認文件設置
    StaticFileOptions, //靜態資源訪問設置
    DirectoryBrowserOptions, //目錄瀏覽設置
});
複製代碼

2、靜態文件受權

靜態模塊是不對文件進行權限檢查的,包含wwwroot下的文件和文件夾。若是相進行權限控制,可使用action返回一個FileResult來實現:

複製代碼
private string basePath = Common.Uitls.HostingEnvironment.ContentRootPath;
public FileResult Index(int id){
    if(id == 1){
        return new PhysicalFileResult(Path.Combine(basePath, "aufolder","author.html"), "text/html");
    }
    return new PhysicalFileResult(Path.Combine(basePath, "error.html"), "text/html");;
}
複製代碼

3、FileExtensionContentTypeProvider類的使用

此類包含一個將文件擴展名映射到MIME內容類型的集合,代碼以下:

複製代碼
FileExtensionContentTypeProvider provider=new FileExtensionContentTypeProvider();
provider.Mappings.Add(".sam", "text/plain");
//自定義靜態文件訪問
app.UseStaticFiles(new StaticFileOptions(){
    FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "mystatic")),
    RequestPath = new PathString("/sam/static"),
    ContentTypeProvider = provider
});
複製代碼
  • FileExtensionContentTypeProvider類與UseStaticFiles關聯使用
  • 擴展名以 "." 開頭。
  • 運行結果以下:
    image
  •                                                   
  •                                                                                         
  • 這樣入門asp.net core,如何

     

    本文章主要說明asp.net core的建立和簡單使用。

    1、使用到的命令

    • dotnet new :建立項目(解決方案,類庫,單元測試等),如:dotnet new web
    • dotnet add package 添加一個nuget的引用
    • dotnet test:運行測試
    • dotnet build:編譯項目
    • dotnet sln add:將項目添加到解決方案
    • dotnet add reference:對此項目添加項目引用

    2、創建空項目

    • 在測試目錄下運行 dotnet new web -n baseWeb,建立web項目,結果以下圖所示:
    • image
    • 運行 dotnet run,便可運行此項目,此命令內部會執行dotnet build命令編譯項目,而後運行,結果以下:
    • image
      說明:此命令是在sln(解決方案)文件所在目錄運行的,因此增長了-p參數,用於指定啓動指定的項目。

    3、引入mvc

    • 因爲咱們建立是一個空web項目,是沒有mvc相關依賴包的,因此首先須要運行dotnet add package Microsoft.AspNet.Mvc 進行依賴包的安裝
    • 而後在StartUp類的ConfigureServices方法中添加以下代碼:
    public void ConfigureServices(IServiceCollection service){
        service.AddMvc();
        service.AddRouting();
    }

    上述添加此添加了Mvc,也添加了路由

    • 配置路由,仍是在StartUp類中,其方法爲Configure添加以下代碼:
    複製代碼
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        
        //添加的代碼
        app.UseMvc(routers=>{
            routers.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
        });
    
        app.Run(async (context) =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    }
    複製代碼
    • 對controller和view的建立
      在建立controller時,沒有找到徹底好的 命令建立方法,因此使用的是手動建立文件,而後繼承Controller類實現;而view是能夠經過dotnet new page實現的,但也可使用手動建立。文件結果以下:
      image
    • 執行dotnet run運行,而後網頁訪問對就的地址便可
      image

    4、更換依賴注入爲autofac

    aspnet core是自帶了依賴注入功能的,就是StartUp類中ConfigureServices方法的IServiceCollection類型的形參。若是你想替換爲autofac。請參考以下步驟

    • 安裝autofac,以及acutofac的擴展類
      • Autofac
      • Autofac.Extensions.DependencyInjection
    • 更改StartUp類中的configureSeervices方法
    複製代碼
    public IServiceProvider ConfigureServices(IServiceCollection service){
        service.AddMvc();
        service.AddRouting();
        var containerBuilder = new ContainerBuilder();
        containerBuilder.Populate(service);
        containerBuilder.RegisterType<Services.ProductService>().As<Services.IProductService>();
        var container = containerBuilder.Build(); 
        return new AutofacServiceProvider(container);
    }
    複製代碼
    • 其中,咱們更改了ConfigureServices方法的返回值,由void換成IServiceProvider;此返回爲AutofacServiceProvider類的一個實例;在上述過程當中,使用了continerBuilder.Populate方法將service(IServiceCollection的實例對象)注入到autofac中。
    • 其中爲了測試DI能力,咱們建立一個IProductService的注入,並在Controller中使用,相關代碼以下:
      • IProductService
    複製代碼
    namespace baseWeb.Services
    {
        public interface IProductService
        {
            int Get(int id);
        }  
    }
    複製代碼
    • ProductService
    複製代碼
    using System.Collections.Generic;
    
    namespace baseWeb.Services
    {
        public class ProductService:IProductService
        {
            List<int> ls = new List<int>();
            
            public ProductService(){
                for(var i=0; i<10; i++){
                    ls.Add(i+10);
                }
            }
            public int Get(int id){
                return ls[id];
            }
        }
    }
    複製代碼
    • HomeController
    複製代碼
    using System;
    using System.Collections.Generic;
    using Microsoft.AspNetCore.Mvc;
    
    namespace baseWeb.Controllers
    {
        public class HomeController:Controller
        {
            private Services.IProductService productService;
    
            public HomeController(Services.IProductService productService){
                this.productService = productService;
            }
    
            public IActionResult Index(int id){
                ViewData["value"] = this.productService.Get(id);
                return View();
            }
        }
    }
    複製代碼
    • 運行結果以下:
      image

    5、加入單元測試

    在實際開發中,常常須要用到單元測試。.net core的單元測試也是如此的 so easy, fallow me。

    • 運行dotnet new xunit -n baseWebTest,便可建立一個以xunit爲測試框架的單元測試項目
    • 運行dotnet add package Moq,安裝Moq模擬框架(此命令須要進入到baseWebTest項目文件夾後運行)
    • 運行dotnet add reference ../baseWeb/baseWeb.csproj,將baseWeb項目引入到此項目中。
    • 編寫單元測試代碼以下:
    複製代碼
    using System;
    using Xunit;
    using Moq;
    using baseWeb.Controllers;
    using baseWeb.Services;
    using Microsoft.AspNetCore.Mvc;
    
    namespace basewebtest
    {
        public class DemoTest
        {
            [Fact]
            public void Test1()
            {
                var productServiceMock = new Mock<IProductService>();
                productServiceMock.Setup(service=>service.Get(1)).Returns((int id)=>{
                    return id+10;
                });
                var _controller = new HomeController(productServiceMock.Object);
    
                var result = _controller.Index(1);
                var objectResult = Assert.IsType<ViewResult>(result);
                var destResult = Assert.IsAssignableFrom<int>(objectResult.ViewData["value"]);
                Assert.Equal(11, destResult);
            }
        }
    }
    複製代碼
    • 運行dotnet test -p ./baseWebtest/baseWebtest.csproj便可,看到以下結果:
    • image

    6、其餘

    • 若是你是使用vscode編寫,那麼測試項目是能夠在編譯器中進行運行和調試的
      image
    • 下載測試源碼
相關文章
相關標籤/搜索