https://angular.io/docs/ts/latest/cookbook/visual-studio-2015.html
https://angular.io/docs/ts/latest/quickstart.html
1.確認是否安裝最新版node.js和npm
2.在cmd輸入node -v及npm -v,如果出現不名的指令代表未曾安裝過
2.1下載node.js -> https://nodejs.org/en/
2.2安裝完node.js後更新npm->至cmd輸入 npm install npm -g
3.修改visual studio的外部工具路徑
3.1工具->選項->專案和方案->外部Web工具->將$(PATH)移至第二順位(在.\node_modules\.bin下)->確定後重啟visual studio
4.VS安裝最新版TypeScript->工具->擴充功能和更新->線上->查"TypeScript"->找最新(最多人下載)的裝
5.下載QuickStart範例,建立WEB應用程式,將QuickStart COPY到專案根目錄然後加入專案
6.右鍵package.json->還原封裝->等3~10分鐘(注意輸出視窗說結束為止,都不要亂動VS)
7.不要理任何輸出視窗寫的錯誤訊息
8.到tsconfig.json加上"compileOnSave": true
9.F5編譯
10.app資料夾的ts檔會產生js檔,再把產生的js檔加入專案
Done.
--------------------------
關於index.html
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
shim.min.js 即使不載入 ng2也可以運作
zone.js Reflect.js Reflect.js這三者則有相依性 要按順續載入,systemjs.config.js才能運作
最後 System.import('app').catch(function(err){ console.error(err); });才能順利init
--------------------------
關於運行
在順利Init NG2後,app資料夾中的js關係為
從main.js為主入口,載入需要的模組塊(app.module),由各模組內設定需要的服務端口元件(app.component),最後才由元件設計/生成結果
main.js -> app.module -> app.component -> {htmlTemplate} -> Ng2 Objects -> Active UI -> release to User
--------------------------
發行
*.因node_modules會要求不要加入VS專案內,所以發行時不會連帶輸出,因此線上會缺少node_modules,故有兩種作法
1.在主機上也安裝NPM然後自行下npm install (如果有問題 改下npm install --no-optional)
2.土法練鋼的將自己專案的node_modules COPY上去(幾萬個檔案慢慢等吧)
2016年9月21日 星期三
2016年7月5日 星期二
2016年7月1日 星期五
[Nuget]從伺服器到發佈一次搞定 使用VisualStudio - Step2 建立你的Nuget分享套件
1.至Visual Studio的擴充功能下載 Nuget Packager


2.重啟Visual Studio後新增專案,會在專案範本看到Nuget選項,用它新增新專案

3.開啟專案後,到NuGet.Config去修改參數,把value改成你架設的Nuget私人網站

4.開啟命令字元,到剛才的專案目錄中,利用專案附載的Nuget.exe建立你的api key
nuget.exe setApiKey {password} -Source {httq://xxx.xxx/nuget}

5.最後到Package.nuspec設定你的套件相關內容資訊,即完成設置動作。


6.最後依你的套件性質,把對應的檔案放在預設的幾個資料夾內就可以了
content : 套件的檔案,依content 下的路徑產生
lib :使用到的DLL參考
src
7.發佈時只要使用建置就會自動發佈,Visual Studio的建置選項為Debug時只會編譯不會發佈,設定成Release才會發佈。

本文為記錄操作步驟 說明建議參考:
http://blog.darkthread.net/post-2016-04-28-nuget-packager.aspx
http://blog.sanc.idv.tw/search/label/NuGet
http://blog.darkthread.net/post-2011-03-29-create-nuget-package.aspx


2.重啟Visual Studio後新增專案,會在專案範本看到Nuget選項,用它新增新專案

3.開啟專案後,到NuGet.Config去修改參數,把value改成你架設的Nuget私人網站

4.開啟命令字元,到剛才的專案目錄中,利用專案附載的Nuget.exe建立你的api key
nuget.exe setApiKey {password} -Source {httq://xxx.xxx/nuget}

5.最後到Package.nuspec設定你的套件相關內容資訊,即完成設置動作。


6.最後依你的套件性質,把對應的檔案放在預設的幾個資料夾內就可以了
content : 套件的檔案,依content 下的路徑產生
lib :使用到的DLL參考
src
7.發佈時只要使用建置就會自動發佈,Visual Studio的建置選項為Debug時只會編譯不會發佈,設定成Release才會發佈。

本文為記錄操作步驟 說明建議參考:
http://blog.darkthread.net/post-2016-04-28-nuget-packager.aspx
http://blog.sanc.idv.tw/search/label/NuGet
http://blog.darkthread.net/post-2011-03-29-create-nuget-package.aspx
[Nuget]從伺服器到發佈一次搞定 使用VisualStudio - Step1 架設自己的Nuget伺服器
1.在Visual Studio新建空的Web專案
2.上Nuget套件中找 Nuget.Server 並安裝

3.不過因為新版以不支援.Net 4.5 所以如果還在4.5的要自行下載舊版本
PM> Install-Package NuGet.Server -Version 2.11.1

4.在Web.Config輸入網站的Push API密碼

5.編譯成功後直接部到IIS上,結束
本文為記錄操作步驟 說明建議參考:
http://blog.darkthread.net/post-2011-05-27-nuget-server.aspx
http://blog.darkthread.net/post-2011-09-03-nuget-1-5-support-authentication.aspx
2.上Nuget套件中找 Nuget.Server 並安裝

3.不過因為新版以不支援.Net 4.5 所以如果還在4.5的要自行下載舊版本
PM> Install-Package NuGet.Server -Version 2.11.1

4.在Web.Config輸入網站的Push API密碼

5.編譯成功後直接部到IIS上,結束
本文為記錄操作步驟 說明建議參考:
http://blog.darkthread.net/post-2011-05-27-nuget-server.aspx
http://blog.darkthread.net/post-2011-09-03-nuget-1-5-support-authentication.aspx
2014年6月12日 星期四
SignalR 強化您的網站應用(三) - HelloWorld2
承接著SignalR 強化您的網站應用(二) - HelloWorld,在上一篇的範例中,提到的是如何將訊息傳送給自己(Caller),但我們要的並不會只是這樣,因為這樣沒有太大意義,因此本節要說的是另外兩個功能,All和Other。
首先是Other,Other指的是除了自己以外,其它任何連線進來的Signalr使用者,都將會收到該訊息,也就是發送訊息給其他人。
如同上一篇,在前端的部份不需要異動,因此附圖沒有貼上前端的部份,我只有附上後端的部份,在這階段,只要使用Others,其它在相同頁面下的使用者就會收到HelloWorld的訊息,如下圖:
同Others,使用All的意思代表,除了其他人會收到HelloWorld以外,你自己也會收到。
你現在可以利用這三種功能,寫出不同應用的SignalR程式了。
重點整理
Clients.Caller : 回應給當前使用者
Clients.Others : 回應給其他使用者
Clients.All : 回應給所有使用者
首先是Other,Other指的是除了自己以外,其它任何連線進來的Signalr使用者,都將會收到該訊息,也就是發送訊息給其他人。
同Others,使用All的意思代表,除了其他人會收到HelloWorld以外,你自己也會收到。
你現在可以利用這三種功能,寫出不同應用的SignalR程式了。
重點整理
Clients.Caller : 回應給當前使用者
Clients.Others : 回應給其他使用者
Clients.All : 回應給所有使用者
2014年3月16日 星期日
SignalR 強化您的網站應用(二) - HelloWorld
在完成最基本的SignalR導入之後,我們可以開始屬於我們的SignalR程式,雖然SignalR主打的是訊息傳播,但一開始我們還是先來練習HelloWorld吧。
首先要做的是,Show出一個HelloWorld的Alert訊息給我們自己的簡單SignalR程式,在這之前,我們先來瞭解一下SignalR撰寫上的基本架構
這是我為了方便區別前後端所建立的資料夾,SignalRHubs及View,SignalRHubs專門置放繼承Hub的SignalR程式,View則是我們接收或傳遞結果的網頁(aspx,html,cshtml....)。
再來是建立Hub,Hub是伺服器端接收或分派訊息給您所希望的使用者所集中管理的程式碼區段,要建立Hub,只需要選擇一般的class.cs即可,接者引入Microsoft.AspNet.SignalR.Hubs及Microsoft.AspNet.SignalR兩份參考,再將該物件繼承Hub這個SignalR定義的個體就完成了。
其中,HubName及HubMethodName這兩個標籤是可以不用設定的,如果不設定它,SignalR在預設情況下,會直接使用物件名稱作為前後端溝通的名稱,但字首第一個英文字母會是小寫,如class名稱叫做MyHub的話,在js引用時必須為myHub,以此類推。
接下來先說明前端呼叫及接收的部份,之後在回到上圖,請參考:
我設置了一個Button,目的是按下它之後Alert一個訊息給我自己,僅此而已。
我們在使用SignalR的Hub模式時,我們必須先建立起一個連線,因此使用$.connection這個指令,再輸入剛才在後端定義的HubName去取得我們要使用的hub,接著使用$.connection.hub.start();將連線啟動。
後面可以看到我針對Button指定了helloworld事件去引發message_get(),而在之前ready時,有定義一個message_set()去接收結果,並alert出來,因此再回到後端程式碼的地方,可以看到負責接收前端傳來的訊息的HubMethodName取為message_get,而在message_get裡寫上了Clients.Caller.message_set這段程式碼,其中Clients指的是所有的客戶端,而Caller所指的是當下發出呼叫的那個網頁(連線),因此我是針對我自己要去回應一件事,而那件事便是message_set。
當你把滑鼠移至message_set上時,你會發現它叫做(動態運算式),其實它就是利用Dynamic去實作出來的,因此這邊可以隨便你愛叫什麼名稱都行,然後前端名稱跟著走就好,要注意的是,參數的數量必須一樣,否則將接收不到任何結果(HubMethod亦同)。
然後啟動我們的網站,你應該可以看到以下結果:
恭喜您,完成了第一隻SignalR程式。
與本文相關的附加資訊
展示網頁
附件下載
首先要做的是,Show出一個HelloWorld的Alert訊息給我們自己的簡單SignalR程式,在這之前,我們先來瞭解一下SignalR撰寫上的基本架構
這是我為了方便區別前後端所建立的資料夾,SignalRHubs及View,SignalRHubs專門置放繼承Hub的SignalR程式,View則是我們接收或傳遞結果的網頁(aspx,html,cshtml....)。
再來是建立Hub,Hub是伺服器端接收或分派訊息給您所希望的使用者所集中管理的程式碼區段,要建立Hub,只需要選擇一般的class.cs即可,接者引入Microsoft.AspNet.SignalR.Hubs及Microsoft.AspNet.SignalR兩份參考,再將該物件繼承Hub這個SignalR定義的個體就完成了。
其中,HubName及HubMethodName這兩個標籤是可以不用設定的,如果不設定它,SignalR在預設情況下,會直接使用物件名稱作為前後端溝通的名稱,但字首第一個英文字母會是小寫,如class名稱叫做MyHub的話,在js引用時必須為myHub,以此類推。
接下來先說明前端呼叫及接收的部份,之後在回到上圖,請參考:
我設置了一個Button,目的是按下它之後Alert一個訊息給我自己,僅此而已。
我們在使用SignalR的Hub模式時,我們必須先建立起一個連線,因此使用$.connection這個指令,再輸入剛才在後端定義的HubName去取得我們要使用的hub,接著使用$.connection.hub.start();將連線啟動。
後面可以看到我針對Button指定了helloworld事件去引發message_get(),而在之前ready時,有定義一個message_set()去接收結果,並alert出來,因此再回到後端程式碼的地方,可以看到負責接收前端傳來的訊息的HubMethodName取為message_get,而在message_get裡寫上了Clients.Caller.message_set這段程式碼,其中Clients指的是所有的客戶端,而Caller所指的是當下發出呼叫的那個網頁(連線),因此我是針對我自己要去回應一件事,而那件事便是message_set。
當你把滑鼠移至message_set上時,你會發現它叫做(動態運算式),其實它就是利用Dynamic去實作出來的,因此這邊可以隨便你愛叫什麼名稱都行,然後前端名稱跟著走就好,要注意的是,參數的數量必須一樣,否則將接收不到任何結果(HubMethod亦同)。
然後啟動我們的網站,你應該可以看到以下結果:
恭喜您,完成了第一隻SignalR程式。
與本文相關的附加資訊
展示網頁
附件下載
2014年3月13日 星期四
SignalR 強化您的網站應用(一) - 導入
首先推薦請先閱讀這份Blog SignalR 來達成電腦網頁與手機網頁即時互動文章,裡頭除了介紹SignalR的功用外,還有相當完整的範例檔可供下載,建議第一次想嘗試SignalR的魔力的讀者,可以抓回家試試,這份Blog文章也是我對SignalR的啟蒙之師。
在看完前段提供的連結內容,以及其範例後,是不是也想開始動手撰寫呢?如果是,有幾點事項可能要注意一下,該頁文章是2012年,當時SignalR的版本還在1.0.0,目前(2014初)已經是2.0以上版本,因此若您使用NuGet去取得SignalR套件的話,會取到2.0(以後)的版本,2.0和1.0的初始配置有些許不同 請參考 SignalR1.x To 2.0,若您的Visual Studio版本在2012(.NET4.5)以上,建議您直接使用2.0(含以後)版本,否則您就必須從NuGet上下載特定SignalR版本
例如:
Install-Package Microsoft.AspNet.SignalR -version 1.1.3
安裝完成後,首先應該會跳出一份文件檔,請不要直接將它關閉,上面有指示各種不同環境下的導入方式,在這邊要注意的是,Javascript腳本在引用時的順序性,SignalR的腳本檔有兩個主要的部份,一個是腳本的本體,依照您的版本,可能是jquery.signalR-x.x.x.js,另一個則是hubs(~/signalr/hubs),hubs的腳本來自於您所在後端程式碼中所建立並繼承Hub的物件,這些Hub物件會使用者點開網頁時,將其集中的內容送至~/signalr/hubs這個相對目錄下,這個目錄是虛擬的,所以您不需要在本機專案或網站上建立signalr/hubs這個位址。
在引用腳本時的順序:Jquery.js ->signalR.js->signalr/hubs
例如:

在成功引用之後(包含說明檔的其它步驟),您可以打開您的測試網頁,建議先使用Chrome,並打開F12(設計模式),如果在Source底下有看到hubs的路徑代表您成功了。
您可以開始準備寫第一隻SignalR程式了。
與本文相關的附加資訊
展示網頁
附件下載
標籤:
SignalR,
Visual Studio
位置:
台灣
2012年12月26日 星期三
Func & Action
這兩個用法我之前就很想搞懂,
但因為不知道怎麼去Google這關鍵字所以一直懸在心上
(<--實力差又沒在買書看的人)
剛好曹祖聖老師來公司上課時有舉到範例,解了我心懸一念
故在這邊簡略示意一般
一般我們可能會做個函式如:
然後去針對abc2()去呼叫它(static別管它),一般的呼叫我們應該都知道了,只是我們也可以用Func的方式去呼叫它,如:
簡略來說就這樣囉,謝謝有來看的人觀賞~~~~
PS:有無發現,其實內圈的自定函式,是跑delegate的,只是剛才我都省略掉而已哦。
故在這邊簡略示意一般
一般我們可能會做個函式如:
01 public static string abc2(int a,int b) 02 { 03 return (a+b).ToString(); 04 }
01 Func<int, int, string> dd = new Func<int, int, string>(abc2);
我們可以簡化它
01 Func<int, int, string> dd = abc2;
然後使用Invoke()或其它去執行它
01 dd.Invoke(1, 2)
但我們有時可能不希望函式寫一大堆,或是許多原因等,也可以用Func去改寫abc2:
01 Func<int, int, string> dd2 = new Func<int, int, string>( 02 (a1,a2) => 03 { 04 return (a1 + a2).ToString(); 05 } 06 );
一樣用Invoke()或其它去執行它
01 02 Console.WriteLine(dd.Invoke(1, 2)); 03 Console.WriteLine(dd.Invoke(1, 3)); 04 Console.WriteLine(dd.Invoke(1, 4)); 05 Console.WriteLine(dd.Invoke(1, 5));
有時依需求,因為這程式段落已經被拉到內層了使用了,所以甚至可以把a1 a2給省略或整合掉
01 int O1, O2; 02 O1 = 1; O2 = 2; 03 Func<string> dd2 = new Func<string>( 04 () => { 05 return (O1 + O2).ToString(); 06 } 07 ); 08 Console.WriteLine(dd2.Invoke());
嗯?怎麼沒講到Action?
其實Action一樣用法
只是Action對應的是void類型
而Func對應的是有return的類
看在你願意把畫面拉下來的份上,我還是貼個CODE好了
01 Action<int> fff = def; 02 03 Action<int> dfqefqf = new Action<int>( 04 delegate(int a1) 05 { 06 } 07 ); 08 09 10 Action<int> dfqefqf2 = new Action<int>( 11 (no) => 12 { 13 //code 14 } 15 );
以上~88
2012年11月20日 星期二
UserControl使用者控制項 CSS style
小筆記
使用UserControl(ascx)時,直接在.ascx裡寫css的style標籤
在IE(9)有可能不會動作?!
要把它拉出來變成css檔 放到主頁去載入才會動作...
不知為何,可能是我排版問題,暫記...
2012年4月11日 星期三
Linq時代的分頁使用關係 (C#)
在早期,我們在完成一個網頁表單會使用DataGird這個物件來實現,而DataGird這個物件本身也就支援著分頁的功能了。不過,我們應該都知道DataGird實現分頁的方式就是將資料透過ViewState保留後,再從中篩選要顯示的資料給User來檢閱,也因此在大量資料下,除了會造成資料庫負擔外,更會因為ViewState過大的關係,使得網頁停止回應,導致整個掛掉。
所以我們會利用資料篩選的方式,只透過回應少量且必要的資料來減低資料庫負擔並提高效能,而通常會透過一連串的SQL語法去達成,至今亦是如此。
在SQL2000之前,我們可能會透過cursor的方式叫用sp_cursoropen及sp_cursorfetch來達成,而在SQL2005之後多了ROW_NUMBER()這個函數,讓我們方便替每筆資料列做編號,之後只要透過where語法去取用需要的編號範圍,即可達成分頁。
例如我們有一語法取得資料表的幣別種類並替它編號
SELECT ROW_NUMBER() OVER (ORDER BY [Currency]) AS [ROW_NUMBER], [Currency], [CurrencyName] FROM [dbo].[Currency]
結果大概長這樣
如果我們打算將它分成兩頁並取第一頁前5筆時
select * from
( SELECT top 5 ROW_NUMBER() OVER (ORDER BY [Currency]) AS [ROW_NUMBER], [Currency], [ CurrencyName ] FROM [dbo].[Currency] ) AS a
where [ROW_NUMBER] > 0
結果自然長這樣
而至於我為什麼要講那麼多SQL呢,是因為使用Linq有著更令人一目瞭然的寫法,如:
var data = (from i in db.Currency select i).Skip(0).Take(5).ToList();
好了....解決了(註:Skip是略過幾筆,Take是取得幾筆),當你使用SQL Profiler時會發現,Linq會自動幫你轉成類似語法,來達到資料分頁,不過這其實不是啥了不起的事...,因為這已經好幾年前的舊聞了,我這裡會講這個,主要只是要表達使用Linq後,在背後的執行狀況。
在VS2005還是VS2008時,DataGird被捨棄了,取而代之的是GridView,而GridView可以搭配著各種DataSource容器,只要指定好DataSourceID,並在畫面上拖拖拉拉後,再將AllowPaging打開,分頁輕輕鬆鬆便做好了!而且更重要的是,透過Profiler去追蹤,你會發現DataSource傳送的SQL語法就是剛才所使用的ROW_NUMBER,簡直棒透了不是?
這當然也不是新聞。
問題在於一點,GridView必需搭配DataSource容器才得以自動完成[資料分頁],但是在分散式專案的架構下,想單單靠著指定DataSourceID來完成表單似乎有點難度,故在這情況下只好又做回原來的GridView.DataSource&DataBind()來製作表單,但不知道是不是由於DataSourceID太好用的關係吧?又或著有些人認為GridView搭配Linq會聰明的自己作分頁..?之類的,你可能會看到如下程式碼:
public void Page_Load(object sender, EventArgs e)
{
GridView1.DataSource = getData();
GridView1.DataBind();
}
public IEnumerable<TBX> getData()
{
var data = from i in DB.Table select i;
return data;
}
然後在介面上設定AllowPaging=true
這是一個不知道該說什麼好的一件事,似乎會以為這樣就會替你完成[資料分頁]?那當然是不可能的...,GirdView並沒有你想像的聰明,它只會將資料全數取回後送給GridView1,存放在GridView1的ViewState裡,緊接著在裡頭進行著分頁動作,就又回到N年前的DataGird問題裡(即使你用別人開發的控件亦同)。
要記得一個大原則,只要透過DataSource&DataBind()就代表你放棄好用的工具,所以所有功能你都得自己寫!!
是故,請好好利用Skip和Take進行分頁吧。
另外在Google時發現一篇文章,文章裡問道,為何我用Skip&Take後,出來的語法和想像的不大一樣?
其實這問題很簡單,因為你下的就是告訴它我要先Skip(跳過)再Take(取用),所以出來的資料截取方式當然是要先等資料讀過後,才知道要where和Top哪邊,如果要像此文章裡的想法下,只Top一定數再where範圍的話...。
只要反過來先Take再Skip就好囉!分頁程式如下:
public List<TheTable> ddd(int PageSize, int PageCount)
{
Conn db = new Conn();
var data = from i in conn.TheTable select i;
var Take = (PageSize * PageCount);
var Skip = ( (PageCount - 1) * PageSize);
return data.Take(Take).Skip(Skip).ToList();
}
之後只要去取用就好囉
public void Button1_Click(object sender, EventArgs e)
{
GridView1.DataSource = getAList(GridView1.PageSize, int.Parse(PageCount.Text));
GridView1.DataBind();
}
不過這個方法沒有詳細Debug,防呆做好的話理論上應該不會有問題....吧?
(甚至你想先Take再Take說不定也行?)
2012/4/19:
關於Take Skip,查執行計劃,效率上似乎一樣。
所以我們會利用資料篩選的方式,只透過回應少量且必要的資料來減低資料庫負擔並提高效能,而通常會透過一連串的SQL語法去達成,至今亦是如此。
在SQL2000之前,我們可能會透過cursor的方式叫用sp_cursoropen及sp_cursorfetch來達成,而在SQL2005之後多了ROW_NUMBER()這個函數,讓我們方便替每筆資料列做編號,之後只要透過where語法去取用需要的編號範圍,即可達成分頁。
例如我們有一語法取得資料表的幣別種類並替它編號
SELECT ROW_NUMBER() OVER (ORDER BY [Currency]) AS [ROW_NUMBER], [Currency], [CurrencyName] FROM [dbo].[Currency]
結果大概長這樣
如果我們打算將它分成兩頁並取第一頁前5筆時
select * from
( SELECT top 5 ROW_NUMBER() OVER (ORDER BY [Currency]) AS [ROW_NUMBER], [Currency], [ CurrencyName ] FROM [dbo].[Currency] ) AS a
where [ROW_NUMBER] > 0
結果自然長這樣
而至於我為什麼要講那麼多SQL呢,是因為使用Linq有著更令人一目瞭然的寫法,如:
var data = (from i in db.Currency select i).Skip(0).Take(5).ToList();
好了....解決了(註:Skip是略過幾筆,Take是取得幾筆),當你使用SQL Profiler時會發現,Linq會自動幫你轉成類似語法,來達到資料分頁,不過這其實不是啥了不起的事...,因為這已經好幾年前的舊聞了,我這裡會講這個,主要只是要表達使用Linq後,在背後的執行狀況。
在VS2005還是VS2008時,DataGird被捨棄了,取而代之的是GridView,而GridView可以搭配著各種DataSource容器,只要指定好DataSourceID,並在畫面上拖拖拉拉後,再將AllowPaging打開,分頁輕輕鬆鬆便做好了!而且更重要的是,透過Profiler去追蹤,你會發現DataSource傳送的SQL語法就是剛才所使用的ROW_NUMBER,簡直棒透了不是?
這當然也不是新聞。
問題在於一點,GridView必需搭配DataSource容器才得以自動完成[資料分頁],但是在分散式專案的架構下,想單單靠著指定DataSourceID來完成表單似乎有點難度,故在這情況下只好又做回原來的GridView.DataSource&DataBind()來製作表單,但不知道是不是由於DataSourceID太好用的關係吧?又或著有些人認為GridView搭配Linq會聰明的自己作分頁..?之類的,你可能會看到如下程式碼:
public void Page_Load(object sender, EventArgs e)
{
GridView1.DataSource = getData();
GridView1.DataBind();
}
public IEnumerable<TBX> getData()
{
var data = from i in DB.Table select i;
return data;
}
然後在介面上設定AllowPaging=true
這是一個不知道該說什麼好的一件事,似乎會以為這樣就會替你完成[資料分頁]?那當然是不可能的...,GirdView並沒有你想像的聰明,它只會將資料全數取回後送給GridView1,存放在GridView1的ViewState裡,緊接著在裡頭進行著分頁動作,就又回到N年前的DataGird問題裡(即使你用別人開發的控件亦同)。
要記得一個大原則,只要透過DataSource&DataBind()就代表你放棄好用的工具,所以所有功能你都得自己寫!!
是故,請好好利用Skip和Take進行分頁吧。
另外在Google時發現一篇文章,文章裡問道,為何我用Skip&Take後,出來的語法和想像的不大一樣?
其實這問題很簡單,因為你下的就是告訴它我要先Skip(跳過)再Take(取用),所以出來的資料截取方式當然是要先等資料讀過後,才知道要where和Top哪邊,如果要像此文章裡的想法下,只Top一定數再where範圍的話...。
只要反過來先Take再Skip就好囉!分頁程式如下:
public List<TheTable> ddd(int PageSize, int PageCount)
{
Conn db = new Conn();
var data = from i in conn.TheTable select i;
var Take = (PageSize * PageCount);
var Skip = ( (PageCount - 1) * PageSize);
return data.Take(Take).Skip(Skip).ToList();
}
之後只要去取用就好囉
public void Button1_Click(object sender, EventArgs e)
{
GridView1.DataSource = getAList(GridView1.PageSize, int.Parse(PageCount.Text));
GridView1.DataBind();
}
不過這個方法沒有詳細Debug,防呆做好的話理論上應該不會有問題....吧?
(甚至你想先Take再Take說不定也行?)
2012/4/19:
關於Take Skip,查執行計劃,效率上似乎一樣。
標籤:
C#,
Linq,
SQL SERVER 2008,
Visual Studio
位置:
台灣
2012年4月7日 星期六
網站效能的追源溯本(Linq)
Linq真好用(廢話)
Linq搭配LinqToxxx or Entity的結合根本好用到不行
用不著寫一堆連線方案,也不用擔心SQL Injection,也不用因為寫SQL語句時,造成的一堆"字"亂七八糟的難維護,甚至連SQL都不用學了。
真是好用的東西
事不宜遲,就來寫個輸入一筆訂單,若存在符合訂單則修改數量,不存在則新增一筆,超過一筆以上則保留數量最多的並刪除其它多餘資料的標準Linq語句吧。
我們姑且不論是什麼情況會有這麼詭異的需求...那不是重點。
基本上類似這樣子的寫法應該很常見,但這語法裡有什麼問題存在?相信應該很容易知道。
Linq因為它是一個你要它做時,它才會動的東西,所以即使你在最開頭寫好了select from....,它並不會做任何事,只是放在那裡,等你找它做事,當只有在count、max....xxx等語句出現或foreach它時,才會與資料做連繫,所以在這一個簡單判斷的語法裡,總共至少需要叫資料庫做至少5~7次以上的動作,會不會太浪費資源了一點?
catchOrder.Count()catchOrder.Max()catchOrder.XXX()太好用了,又容易看懂,如果你覺得這沒什麼,結果瘋狂使用它,去試著想用的人多一點時,會發生什麼事吧?一個人是7次,1000個人就是7千次,千萬不要因為好用而濫用。
這邊做簡單的調整(但不代表最好,因為更好的有很多,這邊只是減少對資料庫溝通而已)
利用ToList先行將資料取得到記憶體中,接著計取Count保留,若有需要時亦用來計取Max,如此一來對資料庫要求的次數則從最少5~7次降為最少2次,如此便減少與資料庫之間來往,理論上而言效能應是比較好的。(實際情況請依狀況而定)
在撰寫時,最好搭配SQL Profiler瞭解你的Linq到底幹了什麼事。
Linq搭配LinqToxxx or Entity的結合根本好用到不行
用不著寫一堆連線方案,也不用擔心SQL Injection,也不用因為寫SQL語句時,造成的一堆"字"亂七八糟的難維護,甚至連SQL都不用學了。
真是好用的東西
事不宜遲,就來寫個輸入一筆訂單,若存在符合訂單則修改數量,不存在則新增一筆,超過一筆以上則保留數量最多的並刪除其它多餘資料的標準Linq語句吧。
var dbLink = new db(); var catchOrder = from o in dbLink.OrderList where o.OrderID == "J001" select o; if (catchOrder.Count() == 0) { var newOrder = new OrderList(); newOrder.OrderID = "J001"; newOrder.OrderName = "新訂單01"; newOrder.Quantity = 10; dbLink.OrderList.InsertOnSubmit(newOrder); } if (catchOrder.Count() == 1) { foreach (var upd in catchOrder) { upd.Quantity = 11; } } if (catchOrder.Count() >= 2) { var MaxQuantity = catchOrder.Max(m => m.Quantity); var delSomeThing = from d in catchOrder where d < MaxQuantity select d; foreach (var delIt in catchOrder) { dbLink.OrderList.DeleteOnSubmit(delIt); } } dbLink.SubmitChanges();
我們姑且不論是什麼情況會有這麼詭異的需求...那不是重點。
基本上類似這樣子的寫法應該很常見,但這語法裡有什麼問題存在?相信應該很容易知道。
Linq因為它是一個你要它做時,它才會動的東西,所以即使你在最開頭寫好了select from....,它並不會做任何事,只是放在那裡,等你找它做事,當只有在count、max....xxx等語句出現或foreach它時,才會與資料做連繫,所以在這一個簡單判斷的語法裡,總共至少需要叫資料庫做至少5~7次以上的動作,會不會太浪費資源了一點?
catchOrder.Count()catchOrder.Max()catchOrder.XXX()太好用了,又容易看懂,如果你覺得這沒什麼,結果瘋狂使用它,去試著想用的人多一點時,會發生什麼事吧?一個人是7次,1000個人就是7千次,千萬不要因為好用而濫用。
var dbLink = new db(); var catchOrder = from o in dbLink.OrderList where o.OrderID == "J001" select o; var bakOrder = catchOrder.ToList(); int useCount = bakOrder.Count(); if (useCount == 0) { var newOrder = new OrderList(); newOrder.OrderID = "J001"; newOrder.OrderName = "???01"; newOrder.Quantity = 10; dbLink.OrderList.InsertOnSubmit(newOrder); } if (useCount == 1) { foreach (var upd in catchOrder) { upd.Quantity = 11; } } if (useCount >= 2) { var MaxQuantity = bakOrder.Max(m => m.Quantity); var delSomeThing = from d in catchOrder where d < MaxQuantity select d; foreach (var delIt in catchOrder) { dbLink.OrderList.DeleteOnSubmit(delIt); } } dbLink.SubmitChanges();
這邊做簡單的調整(但不代表最好,因為更好的有很多,這邊只是減少對資料庫溝通而已)
利用ToList先行將資料取得到記憶體中,接著計取Count保留,若有需要時亦用來計取Max,如此一來對資料庫要求的次數則從最少5~7次降為最少2次,如此便減少與資料庫之間來往,理論上而言效能應是比較好的。(實際情況請依狀況而定)
在撰寫時,最好搭配SQL Profiler瞭解你的Linq到底幹了什麼事。
2011年11月25日 星期五
令人懷念的MUD -- [AJAX GAME]自製簡易網頁的對戰小遊戲
https://sites.google.com/site/siggblog/sample/ajax-you-xi1
會想要寫這個,無非是想用AJAX作什麼,其實網頁遊戲現在多的跟什麼一樣,只是都是用FLASH來做...,目前先試試用AJAX純網頁能做到啥程度,接下來和HTML5結合,看能玩出啥花樣?
但是有很大的問題,就是敝人沒什麼設計天份,也畫不出好看的圖~所以整體介面醜死了...
(進入遊戲後請先點素質)
這是我為了瞭解AJAX運作寫的,純網頁無FLASH,應該算即時的猜拳制的對戰,線上隨機找其他活人對戰(不過因為沒人玩,所以我加上電腦)。
會想要寫這個,無非是想用AJAX作什麼,其實網頁遊戲現在多的跟什麼一樣,只是都是用FLASH來做...,目前先試試用AJAX純網頁能做到啥程度,接下來和HTML5結合,看能玩出啥花樣?
但是有很大的問題,就是敝人沒什麼設計天份,也畫不出好看的圖~所以整體介面醜死了...
如果玩過後有什麼意見給我參考或反應(不能玩、沒反應、不平衡、畫面太亂、不會動、網路慢之類的),我會感激不盡的,但是如果要我畫上萌圖當角色之類的,我可能沒辦法~
因為只是一個畫面而已,所以沒有啥故事主題之類的,因此我也沒有替這個小遊戲命名。
在IE、firefox、Chrome測試都沒問題,其它版本未知,但是請勿用IE6...
基本上我想要知道我這種設計是否很吃頻寬,所以如果我網路被撐爆,我可能會關掉這個遊戲...
最後,如果你有意願賞光稍微玩一下的,在這裡說聲謝謝~
以下是說明和注意事項,懶得看的可以跳過
註冊
1.先點擊[註冊]建立帳號,註冊的帳號和暱稱無法與他人重復。
2.帳號最多12位,暱稱最多20個字,Email請盡量輸入能用的。
3.註冊成功後會發送註冊成功的Email(沒收到信也沒關係),密碼無法變更和查詢。
遊戲方式
1.遊戲是以線上找玩家直接對戰的方式
2.進入畫面後,左側可查看資訊,[遊戲資訊]可查看線上人數(約每1分鐘更新一次)。
3.點選[尋找對手]可以開始搜尋並等待其它按下[尋找對手]的玩家(若要停止則再按一次)。
4.當互相找到玩家後,[準備完成]會亮起,決定好你的[對戰指令],及看HP夠不夠後,就可以按下。
5.進攻方式目前分4種:重擊(AK)、刺擊(SK)、防禦(DF)、反擊(BK) (如果你有更好的名詞歡迎告知...)
在戰鬥進行中可以任意變更,來改變戰術,
基本上攻防互剋情況為:
1.AK>SK>BK>AK
2.AK和SK打DF時,SK較有利
3.DF狀態下受到攻擊後,會進行蓄力狀態,當改進行攻擊時傷害會些許提高,最多可蓄10回合(會逐漸消退)。
4.雙方都DF或BK時,無傷害,DF也不會蓄積。
6.戰鬥大約每兩秒為一回合,進行到一方或雙方HP歸零為止,就算中途關閉瀏覽器也是會打到底。
7.每次參加戰鬥,最少都會有1的EXP,EXP計算以對手等級計算,當比對手等級高時,每多1級少一些的EXP,勝方可獲得全部EXP,敗方則只有1/3,但無論如何,一定有1EXP
8.戰鬥結束後,或未開打前,都可以恢復你的HP值,恢復HP需已EXP作為代價,每100HP要1EXP,但10級以內不用,11~30需求減半,若EXP為0則都不用,不會掉級請放心。
人物狀態
1.人物狀態在畫面左方[人物資訊]裡可查看,當升級時HP,STR,DEF,AGI,DEX會亮起讓玩家提升素質,若點下去就不可返回,請注意。
2.人物狀態分為:
LV:人物等級,最高99
HP:血量,每次升級+10滴HP,升級也可用點數提升,每1點+10HP
STR:力量,直接影響傷害,另外每1點+5HP
DEF:防禦,降低對手的傷害
AGI:迴避率(最多80%),及有機率產生額外傷害(最多33%,若在SK時發生,則會再稍微高一些)
DEX:命中率,提高命中能力,以及些微提升最小/最大傷害值,
EXP:經驗值
升級點數:1級時有20點供選擇,每次升級有5點
其它事項
1.發呆大約5分鐘沒作任何動作的話,會被強制登出,此時做任何動作會回到登入畫面。
2.承上,由於沒有寫登出~若已登入卻把整個瀏覽器關掉再開的話,可能要等5分鐘才能再登入
3."理論上"一種瀏覽器只能登入一個帳號,而且已登入的角色不能重復在其它地方再登入
4.升級時HP會補滿,但增加HP時不會恢復HP
5.現階段理論上24HR都能進入遊戲,如果無法登入...大概是被操爆了。
6.增加線上聊天,不過仍有點問題
我自己的暱稱: 希格
2011年8月16日 星期二
令人不解的VS2008 AJAX and AJAXToolkit with TabContainer
至今為止仍停留在ASP.NET的基礎的我,
對於什麼MVC、WPF、WCF...之類的雖然多少知道一些,但總覺得沒什實感。
AJAX也是。
相信有碰過AJAX的都不陌生,不過對我很陌生,雖然我知道它在做什麼的,但是工作上沒用到,所以也不曾理會過(真不稱職)。
現在才去試著去瞭解它在VS上的開發,因此我很開心的打開VS2008,選了AJAX範本
然後你會發現它預設帶了這個東西
http://msdn.microsoft.com/zh-tw/library/cc295440(v=Expression.40).aspx
總之就是要有它才會動就對了。
接著我想做類似這種東西的功能
http://www.asp.net/ajaxlibrary/AjaxControlToolkitSampleSite/tabs/tabs.aspx
但是VS2008內建卻沒有?
GOD!只有這5個你也敢出來混。
原來還得自己去上面的網址抓套件.......
當我抓好並增加到我的組件後,多了非常多的套件,真是非常之感動。
結果當我簡單打好了基本的標籤語法後(我習慣都用打的)
依2008的運行方式來想,這種東西應該是不需要額外再去Bind它,所以我就很自然的Run下去
疑?
空白的?
WTF?
我做Ajax上傳時也不會這樣啊
https://sites.google.com/site/siggblog/sample/shangchuanjizidongfasongmail
當我右鍵下去發現資料都是存在的,但是style都是hidden,我還很天真的寫了script去指定它顯示.....結果不行。
於是我就TabContainer1.Visable=true;TabContainer1.DataBind();之類的蠢事。
結果當然也是不行。
於是我開始Google,但是完全沒有人有這種問題,而且每個人都是直接向我這樣打就能Run了,我說....是七月到了我見鬼嗎?難到就真這麼神奇?
於是我花了兩個小時在幹這鬼打牆的事,由於我個人認為這應該是件滿蠢的事,所以我也不打算問人(上網問)。
最後我終於GOO到了一個BLOG
http://www.zhangyongjun.com/BLOG/article.asp?id=6618
我原本以為這份文件對我沒什麼用處,就草草看完然後繼續找,但是我越找越覺得哪怪怪的,於是我又回頭重看一次,看到了一個重點。
如下圖
ToolkitScriptManager?
怎麼有種即視感?
想到沒?
這跟我一開始建好的PAGE裡的<asp:ScriptManager ID="ScriptManager1" runat="server" />不是很像嗎?
於是我先不管它這麼多,照著網頁上的做,我拉了一個ToolkitScriptManager出來
結果發生了
故得知ScriptManager一個頁面應該只能擁有一個,而且ToolkitScriptManager和ScriptManager是相同的東西。
於是我試著把ScriptManager給砍了,只留ToolkitScriptManager再試行一次。
喔喔喔喔!
喔喔喔喔!!
喔喔喔喔!!!
見證奇蹟的時刻到了。
果然是件很蠢的事情啊!
簡而言之
用AjaxControlToolkit就要用ToolkitScriptManager,至於ScriptManager是沒辦法使用的。
這叫人情何以堪
學我最近去上課的老師常說的一句話
這個時後我只有一個字可以形容:氣!
對於什麼MVC、WPF、WCF...之類的雖然多少知道一些,但總覺得沒什實感。
AJAX也是。
相信有碰過AJAX的都不陌生,不過對我很陌生,雖然我知道它在做什麼的,但是工作上沒用到,所以也不曾理會過(真不稱職)。
現在才去試著去瞭解它在VS上的開發,因此我很開心的打開VS2008,選了AJAX範本
然後你會發現它預設帶了這個東西
<asp:ScriptManager ID="ScriptManager1" runat="server" />微軟的解釋是:控制項可管理具有 AJAX 功能的 ASP.NET 網頁所適用的用戶端指令碼。依預設,ScriptManager 控制項會透過網頁對 Microsoft AJAX Library 註冊指令碼。這可讓用戶端指令碼使用類型系統延伸模組,以及支援部分頁面呈現與 Web 服務呼叫等功能。
http://msdn.microsoft.com/zh-tw/library/cc295440(v=Expression.40).aspx
總之就是要有它才會動就對了。
接著我想做類似這種東西的功能
http://www.asp.net/ajaxlibrary/AjaxControlToolkitSampleSite/tabs/tabs.aspx
但是VS2008內建卻沒有?
GOD!只有這5個你也敢出來混。
原來還得自己去上面的網址抓套件.......
當我抓好並增加到我的組件後,多了非常多的套件,真是非常之感動。
結果當我簡單打好了基本的標籤語法後(我習慣都用打的)
<asp:TabContainer ID="TabContainer1" runat="server" ActiveTabIndex="1"> <asp:TabPanel runat="server" HeaderText="TabPanel1" ID="TabPanel1"> <HeaderTemplate>123</HeaderTemplate> <ContentTemplate>456</ContentTemplate> </asp:TabPanel> <asp:TabPanel ID="TabPanel2" runat="server" HeaderText="TabPanel2"> <HeaderTemplate>234</HeaderTemplate> <ContentTemplate>678</ContentTemplate> </asp:TabPanel> </asp:TabContainer>
依2008的運行方式來想,這種東西應該是不需要額外再去Bind它,所以我就很自然的Run下去
疑?
空白的?
WTF?
我做Ajax上傳時也不會這樣啊
https://sites.google.com/site/siggblog/sample/shangchuanjizidongfasongmail
當我右鍵下去發現資料都是存在的,但是style都是hidden,我還很天真的寫了script去指定它顯示.....結果不行。
於是我就TabContainer1.Visable=true;TabContainer1.DataBind();之類的蠢事。
結果當然也是不行。
於是我開始Google,但是完全沒有人有這種問題,而且每個人都是直接向我這樣打就能Run了,我說....是七月到了我見鬼嗎?難到就真這麼神奇?
於是我花了兩個小時在幹這鬼打牆的事,由於我個人認為這應該是件滿蠢的事,所以我也不打算問人(上網問)。
最後我終於GOO到了一個BLOG
http://www.zhangyongjun.com/BLOG/article.asp?id=6618
我原本以為這份文件對我沒什麼用處,就草草看完然後繼續找,但是我越找越覺得哪怪怪的,於是我又回頭重看一次,看到了一個重點。
如下圖
ToolkitScriptManager?
怎麼有種即視感?
想到沒?
這跟我一開始建好的PAGE裡的<asp:ScriptManager ID="ScriptManager1" runat="server" />不是很像嗎?
於是我先不管它這麼多,照著網頁上的做,我拉了一個ToolkitScriptManager出來
結果發生了
只能在此頁面加入一個 ScriptManager 的執行個體。
的錯誤。故得知ScriptManager一個頁面應該只能擁有一個,而且ToolkitScriptManager和ScriptManager是相同的東西。
於是我試著把ScriptManager給砍了,只留ToolkitScriptManager再試行一次。
喔喔喔喔!
喔喔喔喔!!
喔喔喔喔!!!
見證奇蹟的時刻到了。
果然是件很蠢的事情啊!
簡而言之
用AjaxControlToolkit就要用ToolkitScriptManager,至於ScriptManager是沒辦法使用的。
這叫人情何以堪
學我最近去上課的老師常說的一句話
這個時後我只有一個字可以形容:氣!
2011年7月21日 星期四
取得目前Web.config的驗證狀態
剛才google半天找不到,終於被我想出來,也許很多人都知道,不過我之前都沒想過這問題,所以不知道。
趁發現新大陸,趕緊記下吧。
趁發現新大陸,趕緊記下吧。
System.Web.Configuration.AuthenticationSection configSection = (System.Web.Configuration.AuthenticationSection)System.Web.Configuration.WebConfigurationManager.GetWebApplicationSection("system.web/authentication"); TextBox2.Text = configSection.Mode.ToString();
2011年6月23日 星期四
Linq To Sql 加密連線資訊
在使用Linq To Sql拉出DataContext並且依我們的需要代入Table後
會自動生成一組連接資訊,如下圖:
同時亦會在Web.Config裡記錄連線的資訊
由圖可知,記錄的資訊是包含帳密的完整的連線資訊,也許我們可以透過主機信任的方式,使得它不儲存密碼部份的機密資訊,但本篇不討論這部份(而且我也不確定這點),也許我們可以透過其它軟體,替Web.config做加密的動作,不過我只想要手動替這行連線字串加密,來保持我的隱密性就夠了,這就是我要的目的。
先直接貼上程式碼
MyDataContext是我建立的LinqToSQL所使用的dbml
SelfConnectionString是對應Web.Config的組態名稱
rtns(string s)是將從Web.Config取得的資料進行解密動作的方法,依照你個人設計方式去進行加解碼的動作,在我的範例裡,我另外事先寫好了加解碼的function讓我套用。
而我在Web.Config的原始字串,則是被我用RSA加密過的資料,一般來說除非取得我的私鑰,否則無法解析。
connectionString加密後的樣子:
當我要使用時
其實講明白點,就只是在
多加了一個rtns()的處理而已。
會自動生成一組連接資訊,如下圖:
同時亦會在Web.Config裡記錄連線的資訊
由圖可知,記錄的資訊是包含帳密的完整的連線資訊,也許我們可以透過主機信任的方式,使得它不儲存密碼部份的機密資訊,但本篇不討論這部份(而且我也不確定這點),也許我們可以透過其它軟體,替Web.config做加密的動作,不過我只想要手動替這行連線字串加密,來保持我的隱密性就夠了,這就是我要的目的。
先直接貼上程式碼
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data.Linq.Mapping; namespace Library.LinkSource { public partial class Link : MyDataContext { private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource(); partial void OnCreated(); public Link() : base(rtns(System.Configuration.ConfigurationManager.ConnectionStrings["SelfConnectionString"].ConnectionString), mappingSource) { OnCreated(); } public Library.LinkSource.MyDataContext DataBase() { return new Library.LinkSource.MyDataContext(rtns(System.Configuration.ConfigurationManager.ConnectionStrings["SelfConnectionString"].ConnectionString)); } public static string rtns(string s) { string xmlpath = func_Encryption.UserGroup.PrivateXmlKey; System.Xml.XmlDocument x = new System.Xml.XmlDocument(); //x.Load(xmlpath); x.LoadXml(xmlpath); return func_Encryption.RSA.DecryptRSA(s, x.InnerXml); } } }
MyDataContext是我建立的LinqToSQL所使用的dbml
SelfConnectionString是對應Web.Config的組態名稱
rtns(string s)是將從Web.Config取得的資料進行解密動作的方法,依照你個人設計方式去進行加解碼的動作,在我的範例裡,我另外事先寫好了加解碼的function讓我套用。
而我在Web.Config的原始字串,則是被我用RSA加密過的資料,一般來說除非取得我的私鑰,否則無法解析。
connectionString加密後的樣子:
<connectionStrings> <add name="SelfBlogConnectionString" connectionString="4E04EFD36139DFF903496A3C72B3E389914CC27617041075209CE2D819G197539F8A6E0E0F372D3D1446E451479A31FFBEA596DB99E2FDA7F32BFE817A6D5206C7BBC3771F861F3B5CFB52327AF118DF4CCBC0BB877561CFA243CA82372280E542BDEDAAE538E3443D79FB85B0B5FF2E21048658D7AAFAA7BA86CB20396C9610" providerName="System.Data.SqlClient"/> </connectionStrings>
當我要使用時
Link conn = new Link(); var sysc = from use in conn.DataBase().MyTable select use;
其實講明白點,就只是在
Library.LinkSource.MyDataContext(rtns(System.Configuration.ConfigurationManager.ConnectionStrings["SelfConnectionString"].ConnectionString)
多加了一個rtns()的處理而已。
2011年5月1日 星期日
多個sitemap時,自定sitemap容器位置
如果要在專案上擁有多個web.sitemap時
而且所存放的目錄不一定是根目錄時
要在web.config下自定標誌如下:
name是容器名稱
siteMapFile是路徑
之後在SiteMapDataSource容器下指定其Name即可
而且所存放的目錄不一定是根目錄時
要在web.config下自定標誌如下:
<siteMap> <providers><add name="sitemap1" type="System.Web.XmlSiteMapProvider" siteMapFile="~/Web.sitemap" /> <add name="sitemap2" type="System.Web.XmlSiteMapProvider" siteMapFile="~/Link/Item.sitemap" /></providers> </siteMap>
name是容器名稱
siteMapFile是路徑
之後在SiteMapDataSource容器下指定其Name即可
SiteMapDataSource1.SiteMapProvider = "sitemap2";
訂閱:
文章 (Atom)


















