像咱們平日裏作慣了 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
甭管這圖是否好理解,通俗地來說,MVVM 這種模式拆分了視圖和數據,這樣咱們在開發時只要關心數據自己便可,而後視圖 DOM 這方面會由 Vue.js 自動解決。webpack
2、非工程化起步
爲了能支撐起一個最基本的應用,須要引入如下幾個必要文件:git
- vue.min.2.5.3.js,vue.js 庫
- iview.2.7.0.css,iView 樣式文件
- iview.min.2.7.0.js,iView 庫
- iview /locale/zh-CN.js 語言包
- iview /font 字體包
下載 Vue.js
來到 Github 上的 Vue 項目,直接下載 Zip 源碼:程序員
在 dist 目錄中就能夠找到 vue.js 文件:es6
根據不一樣的環境選擇一個版本便可,至此第 1 步就搞定了。
下載 iView 系列文件
在 iView 官網的「組件」 / 「安裝」 頁面的開頭處發現了這個連接:https://unpkg.com/iview/ ,經過它能夠查看到 dist 目錄:
必要文件都在這裏,這些文件沒法打包下載,我採起的笨辦法是逐個點開,而後複製其中的內容。
在獲取 iView 相關的 js 和 css 方面還有一個辦法,仔細觀察官網給出的 CDN 地址分別爲:
我嘗試將它們放在瀏覽器裏進行訪問:
發現地址有變動,不過這並沒有大礙。
至此,將各個文件放在指望的位置便可:
該圖中各文件的擺放並非很嚴謹,你們按本身習慣來便可。
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 方法使其生效。
綁定數據
首先把數據綁定起來,從而看一看總體效果,至於其餘的行爲操做先無論:
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 對象來訪問,故不受此影響。
運行頁面後,數據便可綁定成功。
添加操做所需按鈕
數據呈現出來後,就能夠補充必要的按鈕了:
這一步簡單,只須要修改一下 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 對話框,若是用戶點擊肯定,那麼就執行真正的刪除,看一看效果:
很是漂亮考究的 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發給了,本地運行,事故現場重現:
2、排查嫌疑對象
既然現象是必現,要麼是本身的代碼出了問題,要麼就是vue有Bug(內心莫名的偷笑,大夥都懂的)。
2.1 代碼文件結構和源碼展現
從代碼結構看,沒有好說的。就是用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模式下的運行是有報錯,在達裏咱們放大他的報錯位置:
看到這裏,你是否有想破口大罵的衝動,怎麼會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模式下的運行代碼:
注意三個紅框處的代碼,webpack在dev模式下代碼文件是沒有合併成一個文件的,而是遵行commanJs規範,進行模式化加載的,而他對這個service/index.js這個模式導出時,用的名稱正是a。也就是解釋了在dev模式下this.a爲何會有效,他的this.a.result有值,則是由於他雖然是單文件模式化加載,但其文件中的js代碼仍是被bable作了轉換,將箭頭運算符轉換爲了es5可執行的代碼。因此this.a.result是有值的。
- production模式下的運行代碼:
看這段代碼是否有些頭大,其實從中咱們只須要關心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?}"); }); }
效果圖下圖:
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") }); }
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關聯使用
- 擴展名以 "." 開頭。
- 運行結果以下:
-
這樣入門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項目,結果以下圖所示: - 運行
dotnet run
,便可運行此項目,此命令內部會執行dotnet build
命令編譯項目,而後運行,結果以下:
說明:此命令是在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
實現的,但也可使用手動建立。文件結果以下: - 執行
dotnet run
運行,而後網頁訪問對就的地址便可
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(); } } }
- 運行結果以下:
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
便可,看到以下結果:
6、其餘
- 若是你是使用vscode編寫,那麼測試項目是能夠在編譯器中進行運行和調試的
- 下載測試源碼
- dotnet new :建立項目(解決方案,類庫,單元測試等),如: