2012年1月18日 星期三

[C#] Web-farm Page error : Validation of viewstate MAC failed

(網路轉貼)

今天公司的某網站,突然無法登入,

出現錯誤訊息:Validation of viewstate MAC failed ...
查詢一下後,原來這是Web-Farm的問題, 若網站有負載平衡架構,可能在PostBack資料時,資料是送到另一臺主機,造成該主機無法辨識。

解決方式:將多台Server的網站,設定WebConfig的機器碼為同一個。

1. 取得機器碼: http://aspnetresources.com/tools/machineKey
2. 打開WebConfig,在 插入步驟一取得的機器碼。
3. 完成。

參考資料: http://blog.miniasp.com/

負載測試流程 (with Visual Studio 2010 SP1)


負載測試流程 (with Visual Studio 2010 SP1 )

作者: JB 

一、   準備:
a.
至少建立一個以上的【Web效能測試】→ 必要
b.
建立【資料產生計畫】
c.
修改【Web效能測試】計畫
d.
由【管理測試控制器】將測試結果與資料庫作連結 → 建議,否則無法輸出結果到Excel
e.
開始進行【負載測試】→ 必要

二、   Web效能測試】
Step1. 由【測試】→【新增測試】→選擇『Web效能測試』

 

Step2. 開始錄製使用者行為,完成後按下『停止』或直接關閉網頁。




Step3.. 成功錄製一個『Web效能測試』的結果。



三、   【資料產生計畫】
在上面的Web效能測試,第一個步驟是使用者登入帳號&密碼,此時資料庫只有一個使用者。 實務上應該資料庫會存在多筆使用者,所以我們使用【資料產生計畫】自動產生多筆使用者帳號及密碼。

Step1. 在原本的方案加入一個資料庫專案:『SQL Server 2008 精靈』

 

Step2.
SQL Server 2008 精靈』可直接切換到『匯入資料庫結構描述』,選擇資料庫或新增連結,然後按下【完成】。
此時Visual Studio會自動匯入該資料庫所有Table Schema到這個專案。




Step3. 完成後,在方案總管中,你建立的『SQL Server 2008 精靈』右鍵選擇新增一個『資料產生計畫』




Step4.
在『資料產生計畫』中,記得是選『資料轉換計畫』
上面那一個完全不會幫我們匯入Table Schema!



Step5.. 選一下來源連接字串,按下【確定】後,就可以把Table Schema全部抓出來。

 

Step6. 如下圖步驟開始設定『資料產生計畫』,按下【產生資料】圖示後,便會把產生的資料寫入資料表。



四、   修改【Web效能測試】計畫

Step1. 打開剛才建立的『Web效能測試』,點選功能列上的【加入資料來源】。

 
 
 

選擇我們的來源資料表按下【完成】。
 

加入後的資料來源如下圖
 
Step2.
選擇你要修改內容的參數,在屬性頁面的【值】選擇剛剛建立的資料來源裡面對應的欄位。
同理,Password欄位也可選擇從資料表抓取。




Step3. 其它設定: 可在『Web效能測試』加入其他迴圈或條件

五、   建立【管理測試控制器】

注意:若在資料庫已建立過 LoadTest 資料庫,則忽略步驟1.

Step1.
開啟命令提示字元,輸入下列文字:
32 位元版本的 Visual Studio 2010 Ultimate 上,輸入:cd C:\Program Files\Microsoft Visual Studio 10\Common7\IDE 

64 位元版本的 Visual Studio 2010 Ultimate 上,輸入:cd C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE

在該資料夾中,輸入下列文字:

SQL Express
SQLCMD /S localhost\sqlexpress /i loadtestresultsrepository.sql
SQL
:您可以將資料庫安裝到任何現有 SQL Server。 例如,如果您的 SQL Server 名稱為 ContosoServer1,可以使用下列命令:
SQLCMD /S ContosoServer1 -i loadtestresultsrepository.sql

若需要登入資料庫的帳號&密碼,請輸入:
SQLCMD /S ContosoServer1 -U <user name> -P <password> -i loadtestresultsrepository.sql

完成後,會在Sql Server(或Sql Express)上建立一個LoadTest的資料庫。

Step2.
回到Visual Studio 2010,打開【測試】→【管理測試控制器】

 

Step3.  選取剛才建立的LoadTest資料庫,完成【管理測試控制器】設定。 未來負載測試結果會直接寫到此資料庫。







六、   開始進行負載測試:

Step1. 加入一個『負載測試』
 

Step2. 【情節】:第一個畫面,輸入測試情節名稱,和設定考慮時間 ( 請參考MSDN )
 

Step3. 【負載模式】:設定虛擬使用者人數
 

Step4.
選取【測試混合模型】,這個一開始看匯有點霧煞煞。
如果跟【測試混合】一起看,就比較好理解。




舉例說明,如果我們建立兩個Web效能測試(WebTest1, WebTest2 … 兩種不同的使用者模式)…
a.
按總測試數
  
測試結束時,WebTest1WebTest2的總執行次數比例會剛好各自是70%30%(如下圖)
  
但是每個使用者執行AB的順序和次數會讓VS自己去排定。
  
~~ : WebTest1WebTest2WebTest1WebTest1
        
乙:WebTest2WebTest1WebTest2WebTest2



b.
按虛擬使用者人數
  
70%的使用者完全重複跑WebTest1到測試結束,其它30%的使用者是完全跑WebTest2
  
c.
按使用者步調
  
直接指定每小時測試的次數,另測試順序也是VS自己排。




d.
依據循序測試順序
  
所有使用者依據每個加入的『Web效能測試』順序,執行所有測試直到時間結束。
  
如 甲:WebTest1WebTest2WebTest1WebTest2
     
乙:WebTest1WebTest2WebTest1WebTest2
 

Step5. 【測試混合】: 請參考Step4.
Step6. 【網路混合】: 加入我們要測試的網路,並設定分佈。
 

Step7. 【瀏覽器混合】:加入我們要測試的瀏覽器
 

Step8. 【計數器集合】:加入你要測試的主機名稱,並選擇你要監測的部分,如:IIS狀態等。
      
詳細資料可參考 MSDN
 

Step9. 【回合設定】:
可選擇「負載測試持續期間」或「測試反覆項目」,詳細資料可參考MSDN

『負載測試持續時間』 (預設選項 )
準備持續期間
執行測試後、到開始記錄取樣資料之間的時間區段,可能在錄製樣本值之前,讓虛擬使用者逐步達到特定的負載量,但在此之前則不記錄。而準備期結束前所擷取的樣本值,依然會顯示在「負載測試監視器」中。

執行持續期間(預設值「 0100秒」):執行測試的時間。

『測試反覆項目』
指定在負載測試完成之前反覆執行個別測試的總數。

取樣率(預設值「 5」):擷取效能計數器值的間隔時間。

驗證層級(預設值「低」):定義在負載測試中,其驗證規則的層級。驗證規則與 Web測試要求有關,每條驗證規則都會定義驗證層級──高、中、低。此處指定當 Web測試在負載測試中執行時,會執行何種驗證規則。例如,如果設定為「中」,便執行所有標記為中或低的驗證規則。
 

Step10. 以上設定完成後,按下【完成】。 便會開始執行負載測試。
 

Step11. 結束後,會列出摘要。
 










六、   補充:
負載測試也可以搭配已寫好的單元測試,來測試多工的系統(如WCF … etc
Step1.
先寫好一個單元測試
Step2.
在測試專案加入一個負載測試
Step3.
在測試混合中,選擇步驟一的單元測試
 


PS.
如果單元測試裡面的內容,有包含initial(或結束)資料或設定的部分,建議把她們拿到其他函式。 然後在『測試混合』中的【初始化和結束測試】加上這部分,避免影響負載測試的結果
 

七、   參考資料:
           1. 
程式碼效能剖析(電腦科技電子報)Link
           2. NET 
記憶體配置檢視(MSDN)Link
         
           
3.  Web 效能測試中使用驗證規則和擷取規則(MSDN)Link                      4. 軟體測試實戰系列─VSTS負載測試…Link                      5. 在負載測試中指定電腦的計數器集合…Link         
           
6. VS 2010負載測試結果結果由SQL Server管理…Link                      7. HOW TO:使用 SQL 建立結果存放區(MSDN)… Link





Web效能測試&負載測試(Youtube課程錄影)

Web 效能測試






Visual Studio 2010 Ultimate 負載測試(上)






Visual Studio 2010 Ultimate 負載測試(下)

[轉貼]平行運算 vs 一般的多執行緒

.Net 2.0 以後就自動會將多緒分配到不同 CPU ,
本站先前就有文章討論如何限制只在某幾顆邏輯 CPU 上執行。

多緒跟平行不一樣的地方是多緒是多個工作,不同 CPU 執行,平行是同一工作不同 CPU 執行。
範例:
For i = 1 To 16
   b(i) = sin(a(i))
Next

迴圈是單一工作,所以會在同一工作緒執行,所以仍在同一顆邏輯 CPU 上執行。
經過平行處理的邏輯 (平行運算也需要邏輯上的配合) ,則可將這個迴圈拆到多個 CPU 上同時計算。

2012年1月13日 星期五

2012年1月12日 星期四

[C#] LINQ : JOIN Tables

這篇文章主要是討論如何將ADO.NETJOIN多個表格的Sql,轉換成用LINQ的寫法。

舉例來說,一間小學的資料庫有以下的資料表

TB_STUDENT (學生)
NO(學號)
NAME(姓名)
AGE(年齡)
0001
小明
12
0002
美美
10

TB_SUBJECT (科目)
SN(代號)
SUBJECT(科目)
CH
國文
EN
英文
MA
數學
AT
美術

TB_GRADE_LIST (成績列表)
SN
NO
GRADE
CH
0001
90
EN
0001
50
MA
0001
100
CH
0002
55
EN
0002
95
MA
0002
90


1   這邊以ASP.NET 應用程式(C#)為例,Default.aspx頁面有一個DropDownList,可選擇學生的姓名;選擇完畢後,會在下面的GridView將該學生的成績顯示出來。



2           
2.1   建立專案後,在專案新加入一個『LINQ to SQL 類別』。
名稱取為:Class.dbml





2.2   加入你的Sql Server資料連結,打開Class.dbml,然後將三個表格(記得都要加入Primary Key!)拖曳進去。 請參考下圖。 然後編譯! 這樣DataContext才會產生~




2.3  接下來,我們選擇Default.aspxDropDownList,加入資料來源

Step1.
選擇資料來源


Step2.選擇新資料來源


Step3. 選擇LINQ DataSource


Step4. 選擇剛才建立的DataContext


Step5. 選擇TB_STUDENT資料表,然後選擇NAME (學生姓名Select欄位。
按下「完成」,DropDownList便完成了~



3    我們先把DropDownListAutoPostBack功能打開,然後開啟它的「SelectedIndexChanged」事件。
輸入以下程式碼: (LINQ Sql 4. 討論)


     String sel_Name = DropDownList1.SelectedItem.ToString();
ClassDataContext iCE = new ClassDataContext();
//INNER JOIN
var data = ….; Linq (1)
//LEFT OUTER JOIN (以學生為母體)
var data = ….; Linq (2)
//LEFT OUTER JOIN (以科目為母體)
var data = ….; Linq (3)

DataTable dt_data = new DataTable();
DataColumn [] dc_data = new DataColumn[3];
dc_data[0] = new DataColumn("姓名");
dc_data[1] = new DataColumn("科目");
dc_data[2] = new DataColumn("成績");
dt_data.Columns.AddRange(dc_data);

foreach (var item in data)
{
   
DataRow dr_data = dt_data.NewRow();
   
dr_data["姓名"] = item.NAME;
   
dr_data["科目"] = item.SUBJECT;
   
dr_data["成績"] = item.GRADE;
   
dt_data.Rows.Add(dr_data);
   
dr_data = null;
}
GridView1.DataSource = dt_data;
GridView1.DataBind();
dt_data = null;



4   LINQ Sql討論

4.1  (1) INNER JOIN
var data =
                               from a in iCE.TB_STUDENT.AsEnumerable()
                               join b in iCE.TB_GRADE_LIST.AsEnumerable()
                               on  a.NO equals b.NO
                               join c in iCE.TB_SUBJECT.AsEnumerable()
                               on b.SN equals c.SN
                               where a.NAME == sel_Name
                               select new
                                {
                                    NAME =
                                        a.NAME,
                                    SUBJECT =
                                        c.SUBJECT,
                                    GRADE =
                                        b.GRADE
                                };


        

              說明:
              from x in 母體
               join y in 子表格1 on x.欄位 equals y.欄位
               join z in 子表格2 on x.欄位 equals z.欄位
               where 條件
               select new { 新欄位1, 新欄位2, … }
 


4.2  (2) LEFT OUTER JOIN (以學生為母體)
var data =
                    from x in
                    (
                               from a in iCE.TB_STUDENT
                               join b in iCE.TB_GRADE_LIST
                               on a.NO equals b.NO into group_GRADE
                               from item_GRADE in group_GRADE.DefaultIfEmpty()
                               where a.NAME == sel_Name
                               select new
                               {
                                   NAME = a.NAME,
                                   SN = item_GRADE.SN,
                                   GRADE = item_GRADE.GRADE
                               }
                    )
                    join c in iCE.TB_SUBJECT
                    on x.SN equals c.SN into group_SUBJECT
                    from item_SUBJECT in group_SUBJECT.DefaultIfEmpty()
                    select new
                    {
                         NAME = x.NAME,
                         SUBJECT = item_SUBJECT.SUBJECT,
                         GRADE = x.GRADE
                    };


             


說明:

我們先用 
TB_STUDENT 去 Left outer join TB_GRADE_LIST 取得每位學生的成績,再去Left outer join TB_SUBJECT 取得科目的中文名稱。
所以第一次 Left outer join 的 LINQ 如下 (紅色部分為Left outer join的方法,藍色字為自訂)

from a in iCE.TB_STUDENT
join b in iCE.TB_GRADE_LIST
on a.NO equals b.NO into group_GRADE
from item_GRADE in group_GRADE.DefaultIfEmpty()
where a.NAME == sel_Name
         select new
         {
             NAME = a.NAME,
             SN = item_GRADE.SN,
             GRADE = item_GRADE.GRADE
         }

接下來把上面的結果當作母體,作第二次Left outer join…

from x in
 (
   //上面第一次Left outerj oinLINQ
)
       join c in iCE.TB_SUBJECT
       on x.SN equals c.SN into group_SUBJECT
       from item_SUBJECT in group_SUBJECT.DefaultIfEmpty()
       select new
       {
           NAME = x.NAME,
           SUBJECT = item_SUBJECT.SUBJECT,
           GRADE = x.GRADE
       }

    這邊必須注意的地方是紅字的關鍵字,以及後面select新欄位時,要用Linq裡面暫存的group_XXX 的 item_XXX
   
附上實際上執行的TSQL
   
-- Region Parameters
DECLARE @p0 VarChar(10) = N'美美'
-- EndRegion
SELECT [t2].[NAME], [t3].[SUBJECT] AS [SUBJECT], [t2].[value2] AS [GRADE]
FROM (
    SELECT [t0].[NAME], [t1].[SN] AS [value], [t1].[GRADE] AS [value2]
    FROM [TB_STUDENT] AS [t0]
    LEFT OUTER JOIN [TB_GRADE_LIST] AS [t1] ON [t0].[NO] = [t1].[NO]
    ) AS [t2]
LEFT OUTER JOIN [TB_SUBJECT] AS [t3] ON [t2].[value] = [t3].[SN]
WHERE [t2].[NAME] = @p0




4.3  (3) LEFT OUTER JOIN (以科目為母體)
var data =
                    from x in
                    (
                        from a in iCE.TB_SUBJECT
                        join b in iCE.TB_GRADE_LIST
                        on a.SN equals b.SN into group_GRADE
                        from item_GRADE in group_GRADE.DefaultIfEmpty()
                        select new
                        {
                            SUBJECT = a.SUBJECT,
                            NO = item_GRADE.NO,
                            GRADE = item_GRADE.GRADE
                        }
                    )

                    join c in iCE.TB_STUDENT
                    on x.NO equals c.NO into group_STUDENT
                    from item_STUDENT in group_STUDENT.DefaultIfEmpty()
                    where item_STUDENT.NAME == sel_Name || Nullable.Equals(item_STUDENT.NAME, null)
                    orderby x.GRADE descending
                    select new
                    {
                        NAME = item_STUDENT.NAME,
                        SUBJECT = x.SUBJECT,
                        GRADE = x.GRADE
                    };

          



說明:

這個Linq(2) 是很像的,只是母體換了,然後WHERE條件放到最後才判斷。
最後一個不同點,是將沒有任何學生分數的美術科目,也列印到結果

所以我們的WHERE條件變成
where item_STUDENT.NAME == sel_Name || Nullable.Equals(item_STUDENT.NAME, null)
是的~~ 如果我們在Linq要判斷欄位值是否為空值,不能打 XXX is null XXX == null XXX==””
而是要使用 Nullable.Equals( XXX, null) !