Nine MVP's Blog

05/04/2014

Secure Server Side Information

Filed under: ASP.NET, ASP.NET MVC, Core System, WEB, Web Security — Nine MVP @ 4:24 pm

เนื่องจากเคยกล่าวไว้ไปหลายรอบในกลุ่ม Facebook เรื่องการปิด Server side information เพื่อความปลอดภัย ลดภาวะเสี่ยงที่จะถูกโจมตีจากช่องโหว่ของ software และ OS เอง

ตัวอย่าง  หลังจากที่ผมได้ยิง request ไปที่ website แห่งนึง ผมลองดู HTTP Header ที่ส่งกลับมาจะพบรายละเอียดดังภาพ

4-5-2014 3-48-28 PM

มาบทความนี้จะช่วยระบุวิธีการปิด HTTP Response Header ที่ส่งออกมาจากฝั่ง Server ไปยัง Client

 

3 ขั้นตอนลับลวงพราง สู่ความปลอดภัยระดับพื้นฐาน

 

1. ลบหรือลวงค่า header X-Powered-By : ASP.NET

ให้ไปแก้ไขใน IIS เปิด website ที่ต้องการมาแก้ไข กดเลือกที่ website ตามรูปด้านล่าง

4-5-2014 3-33-13 PM

4-5-2014 3-35-49 PM

เป็นอันสำเร็จ

 

2. ลบหรือลวงค่า header Server : Microsoft-IIS/8.0 และ X-AspNet-Version : 4.0.xxxx

สร้าง class ขึ้นมาตัวนึง แล้ว inherit IHttpModule Interface เพื่อลบหรือแก้ไขค่าของ Server header

public class SecureInfoModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.PreSendRequestHeaders += OnPreSendRequestHeaders;
    }
 
    public void Dispose() { }
 
    void OnPreSendRequestHeaders(object sender, EventArgs e)
    {
        HttpContext.Current.Response.Headers.Set("Server", "I don't know ..."); //ใส่ข้อความถึง hacker
    }
}

ต่อจากนั้นนำ module ที่สร้างไว้มา register ลงใน webserver tag
ให้เปิด Web.Config มาแก้ไขกำหนดสั่งปิดการแสดงผล version ของ http runtime

<system.web>
  <httpRuntime enableVersionHeader="false"/>
 ....
 </systen.web>
 นำ class module ที่สร้างไว้ มาใส่ใน webServer tag
 <system.webServer>
 <modules>
 <add name="SecureInfoModule" type="ใส่  namespace ให้ตรง.SecureInfoModule" />
 .........
 </modules>
 </system.webServer>

 

3. ลบหรือลวงค่า X-AspNetMvc-Version : 4.0

เปิดโปรเจ็คใน Visual Studio มองหา Global.asax.cs เปิดมาใส่โค้ด

protected void Application_Start()
{
    MvcHandler.DisableMvcResponseHeader = true;
    .....
}

 

หวังว่าจะเป็นประโยชน์สำหรับเหล่าสาวก .NET  😀

Advertisements

23/09/2013

Object Mapping Library Performance Testing

ตอนนี้ปั่นไวๆ ไม่มีแบบแผนอะไรมาก เนื่องจากมีการ discuss กันในกลุ่ม ASP.NET & MVC Developers Thailand เกี่ยวกับการทำ mapping object
และได้หยิบยกประเด็นเรื่อง
Performance ว่าน่าวิตกแค่ไหนสำหรับการใช้ Library กลุ่มนี้

ผมจึงได้หยิบออกมาทดสอบด้วยกัน 4 วิธีคือ

  1. Custom Mapping
  2. EmitMapper
  3. ValueInjection
  4. AutoMapper

ทุกตัวใช้ version ล่าสุดจาก nuget (prerelease option)

เพื่อหา performance ของ simple object collection จำนวน 1M ล้านตัว เพื่อเปรียบเทียบดู ก็ได้ผลตามนี้

หลักการคือต้องการ .ToList() เพื่อทำการ copy object ไปยังตัวแปรที่รับค่าจริงๆ

เห็นได้ชัดว่าแย่ที่สุดคือ ValueInjection

แย่รองลงมาคือ EmitMapper

ผลเทสดีอันดับที่สองคือ Custom Mapping

และประสิทธิภาพดีที่สุดและทำงานได้ไวสุดยกให้ AutoMapper

มาดู code ที่ใช้ทดสอบ

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using AutoMapper;

using Omu.ValueInjecter;

namespace DemoPartialUpdate

{


public class User

{


public int Id { get; set; }

public string UserName { get; set; }

public string Password { get; set; }

public DateTime LastLogin { get; set; }

}


class Program

{


static void Main(string[] args)

{


int objectLenght = 1000000;


List<User> users = new List<User>(objectLenght);


for (int i = 0; i < objectLenght; i++)

{


User user = new User();

user.Id = i;

user.UserName = “User” + i;

user.Password = “1” + i + “2” + i;

user.LastLogin = DateTime.Now;

users.Add(user);

}


Stopwatch st = new Stopwatch();


//Custom Mapping

st.Start();

var userList = users.Select(o => new User{ Id = o.Id, UserName = o.UserName, Password = o.Password, LastLogin = o.LastLogin}).ToList();

st.Stop();

Console.ForegroundColor = ConsoleColor.Green;

Console.WriteLine(“Custom mapping {0} objects within {1}, objectLenght, st.Elapsed.ToString(“g”));


//EmitMapper

st.Start();

var map = EmitMapper.ObjectMapperManager.DefaultInstance.GetMapper<User, User>();

IEnumerable<User> emitUsers = users.Select(o => map.Map(o)).ToList();

st.Stop();

Console.ForegroundColor = ConsoleColor.Blue;

Console.WriteLine(“EmitMapper mapping {0} objects within {1}, objectLenght, st.Elapsed.ToString(“g”));


//ValueInject

st = new Stopwatch();

st.Start();

IEnumerable<User> valueUsers = users.Select(o => (User)new User().InjectFrom(o)).ToList();

st.Stop();

Console.ForegroundColor = ConsoleColor.Red;

Console.WriteLine(“ValueInjecter mapping {0} objects within {1}, objectLenght, st.Elapsed.ToString(“g”));


//AutoMapper

st = new Stopwatch();

st.Start();

var userMap = Mapper.Map<IEnumerable<User>>(users).ToList();

st.Stop();

Console.ForegroundColor = ConsoleColor.Yellow;

Console.WriteLine(“AutoMapper mapping {0} objects within {1}, objectLenght, st.Elapsed.ToString(“g”));


Console.ReadKey();


}

}

}

จบครับ

21/04/2012

Application Design : Logging 2

Filed under: Core System — Tags: , — Nine MVP @ 6:58 pm

ตอนที่แล้ว
https://nine69.wordpress.com/2012/03/15/application-design-logging-1/

ในตอนนี้ขอลงรายละเอียดเรื่องราวทั้งหมดนี้ครับ

  1. การใช้งาน NLog เบื้องต้นกับ .NET Application
  2. การ config Alternate Source
  3. แนวคิดการเก็บ Audit Data ของข้อมูลในระบบ

ต่อไปสำหรับการเก็บ Log ของการทำงานใน Application นั้น จะขอแนะนำการใช้งาน

NLog Framework

มาทำความรู้จักเจ้า NLog กัน  โดย NLog เป็น Logging Framework ที่มีความสามารถและประสิทธิภาพในการทำงานที่อยู่ในระดับที่ดี ซึ่งสามารถทำการบันทึก log ได้หลากหลายชนิด บันทึก log พร้อมกันได้หลายชนิดในรูปแบบข้อมูลที่สามารถกำหนดให้แตกต่างกันได้ เพียงแค่ทำการ config เท่านั้นหรือจะเขียนโปรแกรมกำหนดก็ได้  สามารถกำหนด buffer ของการเขียน  ทำการบันทึกแบบ async ทำ load balancing และรองรับ Failover  รวมไปถึงสามารถนำไปใช้กับ .NET/ SliverLight / Windows Phone/ Mono ได้อีกด้วย 

Target Source ที่รองรับ

  • Files – บันทึกลงไฟล์เดียวหรือจะหลาย file, กำหนดให้ rename หรือจะ zip ด้วยก็ได้ แถมยังกำหนด size ของ file เพื่อให้ split file ออกตามขนาดที่กำหนดก็ได้
  • Event Log – สามารถบันทึกแบบ local และ remote ก็ได้
  • Database – เก็บ log ลง database
  • Network – ยิง log ออกไปด้วย protocol ชนิดต่าง ๆ ไม่ว่าจะ TCP, UDP, SOAP, MSMQ เป็นต้น
  • Command-line- สามารถ show log ออก console app ได้ด้วยสีสันต่าง ๆ
  • E-Mail – กำหนดให้ส่ง email ออกไปตาม config
  • ASP.NET trace – บันทึกเข้าไว้ใน trace ของ asp.net

เริ่มต้นใช้งาน NLog เบื้องต้น

    สำหรับหัวข้อต่อไปต้องใช้ Software ต่อไปนี้

  1. Visual Studio 2005 ขึ้นไป (บทความใช้ VS2010)
  2. NuGet  (download here)
  3. MS SQL
  4. Internet

เปิด Visual Studio ขึ้นมาแล้วทำการสร้าง Console Project ตามภาพ

image

เสร็จแล้วจะได้โปรเจ็คตามภาพด้านล่างนี้

image

ต่อไปให้ทำการเรียก Package Manager Console ขึ้นมาเพื่อทำการติดตั้งตัว NLog ในโปรแกรมของเรา

image

หลังจากได้ Package Manager Console Window มาแล้วก็ทำการรันคำสั่งด้านล่างนี้

PM> Install-Package NLog

ก็จะได้ output ต่อท้ายว่า

Successfully installed ‘NLog 2.0.0.2000’.

Successfully added ‘NLog 2.0.0.2000’ to NLog01.

จากนั้นให้ติดตั้งตั้ว Schema ของ NLog เพิ่มดังนี้

PM> Install-Package NLog.Schema

ก็จะได้ output ต่อท้ายว่า

Attempting to resolve dependency ‘NLog.Config (≥ 2.0.0.0)’.

Attempting to resolve dependency ‘NLog (≥ 2.0.0.2000)’.

Successfully installed ‘NLog.Config 2.0.0.2000’.

Successfully installed ‘NLog.Schema 2.0.0.2000’.

Successfully added ‘NLog.Config 2.0.0.2000’ to NLog01.

    เข้าไปดูใน Project เพื่อตรวจสอบจะต้องได้ภาพตามนี้

    image

    จากนั้นเปิด file NLog.config มาแก้ไขตามนี้

image

อธิบาย config

1: เปลี่ยนไปตาม .NET Framwork version ที่ใช้งานในโปรเจ็ค

2: ทำการใช้งาน target source แบบ File โดยกำหนด option

– fileName :  ให้เก็บ log ไว้ที่เดียวกับที่โปรแกรมอยู่ และสร้าง log folder ขึ้นถ้่าหากไม่มี /  ตามด้วยชื่อไฟล์ โดยเอา date format ตามด้วย .log

– layout :  เมื่อจะเขียน log ทุก level จะต้องเขียนด้วย format ของ วันที่ LEVEL และตามด้วย ข้อความของ Log ที่จะบันทึก

3: บอกตัว log ให้ทำการบันทึกลง Target Source ใดๆบ้าง

– minlevel :  กำหนดไว้ต่ำสุดที่ Trace Level

– writeTo :  อ้างไปยัง target source ที่ชื่อว่า file (ในข้อ2) 

    จากนั้นให้เปิด Program.cs ขึ้นมาเพื่อแก้ไข Code ตามตารางด้านล่างนี้

    Code Snippet
    1. using System;
    2. using NLog;
    3.  
    4. namespace NLog01
    5. {
    6.     public class Program
    7.     {
    8.         //  NLog instance
    9.         private static Logger logger = LogManager.GetCurrentClassLogger();
    10.  
    11.         private static void Main(string[] args)
    12.         {
    13.             TestLog(); //  method  test
    14.             Console.ReadLine();
    15.         }
    16.  
    17.         public static void TestLog()
    18.         {
    19.             logger.Trace("Test trace message");
    20.             logger.Debug("Test debug message");
    21.             logger.Info("Test informational message");
    22.             logger.Warn("Test warning message");
    23.             logger.Error("Test error message");
    24.             logger.Fatal("Test fatal error message");
    25.             //  Log() method  Level
    26.             logger.Log(LogLevel.Info, "Test fatal error message");
    27.         }
    28.     }
    29. }

    อธิบาย code

    1. line2: เรียกใช้ namespace ของ NLog

    2. line17-27:  เป็นการทดสอบเขียน Log ใน Level ต่าง ๆ  รวมไปถึงการกำหนด level ผ่าน Log() method ได้เอง

    3. line13:  เรียกใช้ TestLog() ที่ได้เขียนไว้

      จากนั้นก็ทดสอบ run โดยกด F5 ก็จะได้หน้าต่างดำๆ ค้างนิ่งอยู่ตามภาพ และกด Enter หรือ Key อื่น ๆ ลงไปเพื่อจบโปรแกรม

      image

      กลับมาที่ Visual Studio แล้วไปที่ Solution Explorer แล้วกดตามลำดับหมายเลขในรูปด้านล่าง

      image

    4. เลือกโปรเจ็ค
    5. กดเพื่อดู file/folder ทั้งหมดในโปรเจ็ค
    6. กดเข้าไปใน bin –> Debug –> logs –> จะพบ file log เกิดขึ้นใน folder ดังกล่าว
    7. เปิด file log ขึ้นมาเพื่อดูผลลัพธ์ ก็จะพบ log message ที่เราได้สั่งบันทึกไปตามรูปด้านล่าง image
    8. จากนั้นหากเราจะกำหนดให้ File Target จำกัดขนาดของ log file และ split ออกตามขนาดเพื่อความง่ายในการเปิดมาอ่าน โดยเปิดให้เพิ่ม config เข้าไปตามนี้
      Code Snippet
      1. <?xml version="1.0" encoding="utf-8" ?>
      2. <nlog xmlns="http://www.nlog-project.org/schemas/NLog.netfx40.xsd"
      3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" internalLogFile="int.log">
      4.      <!–See http://nlog-project.org/wiki/Configuration_file   
      5.   for information on customizing logging rules and outputs.   –>
      6.   <targets>
      7.     <!– add your targets here –>
      8.     <target xsi:type="File" name="file" fileName="${basedir}/logs/${shortdate}.log"
      9.             layout="${longdate} ${uppercase:${level}} ${message}"
      10.             archiveEvery="Day"
      11.             archiveAboveSize="10000"
      12.             archiveNumbering="Sequence" />
      13.   </targets>
      14.   <rules>    
      15.     <!– add your logging rules here –>
      16.     <logger name="*" minlevel="Trace" writeTo="file" />
      17.   </rules>
      18. </nlog>

    9.  เสร็จแล้วไปปรับ Code ใน Program.cs มาแก้ไข TestLog() ใหม่ตามนี้ เพื่อจำลองสร้าง log file ขนาดใหญ่

    Code Snippet
    1. public static void TestLog()
    2. {
    3.     for (int i = 0; i < 500; i++)
    4.     {
    5.         logger.Trace("Test trace message");
    6.         logger.Debug("Test debug message");
    7.         logger.Info("Test informational message");
    8.         logger.Warn("Test warning message");
    9.         logger.Error("Test error message");
    10.         logger.Fatal("Test fatal error message");
    11.         //  Log() method  Level
    12.         logger.Log(LogLevel.Info, "Test fatal error message");
    13.     }
    14. }

    -10.  ทดลองรันโปรแกรมดูด้วยการกด F5 แล้วกลับไปดูใน Log Folder จะพบ log file หลากตัวเกิดขึ้นเนื่องจากเรากำหนด size ของไฟล์ไว้นั้นเอง

    image

    และเราก็ยังสามารถ config เพิ่มเติมได้อีกมากมายสามารถเข้าไปอ่านรายละเอียดได้ที่นี่ http://nlog-project.org/wiki/File_target

    การเก็บ log ใน Event Log ของ Windows

    ต่อไปเราจะเก็บ log ลงไปใน Event Log มีขั้นตอนดังนี้    

    1.  ไปที่ Solution Explorer และเปิด NLog.config ขึ้นมาเพื่อแก้ไข

    2. เพิ่ม config เข้าไปตามตารางด้านล่าง

    Code Snippet
    1. <?xml version="1.0" encoding="utf-8" ?>
    2. <nlog xmlns="http://www.nlog-project.org/schemas/NLog.netfx40.xsd"
    3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" internalLogFile="int.log">
    4.      <!–See http://nlog-project.org/wiki/Configuration_file   
    5.   for information on customizing logging rules and outputs.   –>
    6.   <targets>
    7.     <!– add your targets here –>
    8.     <target xsi:type="File" name="file" fileName="${basedir}/logs/${shortdate}.log"
    9.             layout="${longdate} ${uppercase:${level}} ${message}"
    10.             archiveEvery="Day"
    11.             archiveAboveSize="10000"
    12.             archiveNumbering="Sequence" />
    13.     <target xsi:type="EventLog" name="evl" layout=" ${longdate}|${level:uppercase=true}|${logger}|${message}"
    14.             machineName="NINE-WNB"
    15.             source="NLog01" eventId="9001" log="Application" />
    16.   </targets>
    17.   <rules>    
    18.     <!– add your logging rules here –>
    19.     <logger name="*" minlevel="Trace" writeTo="file" />
    20.     <logger name="*" minlevel="Trace" writeTo="evl" />
    21.   </rules>
    22. </nlog>

      line13-15:  เป็นการเพิ่ม event log target เข้าไป

      line14: อย่าลิมแก้เป็นชื่อ computer name ของตัวเองนะครับ

      3.  จากนั้นกลับไปแก้ file Program.cs ใน method TestLog() โดยลบ For Loop ออกตามด้านล่างนี้

      Code Snippet
      1. public static void TestLog()
      2. {
      3.     logger.Trace("Test trace message");
      4.     logger.Debug("Test debug message");
      5.     logger.Info("Test informational message");
      6.     logger.Warn("Test warning message");
      7.     logger.Error("Test error message");
      8.     logger.Fatal("Test fatal error message");
      9.     // custom log level
      10.     logger.Log(LogLevel.Info, "Test fatal error message");
      11. }

      4.  และทำการ กด F5 เพื่อรันโปรแกรมทดสอบ กด Enter เพื่อจบโปรแกรม

      5.. เสร็จแล้วไปเปิด Start –> Administrative Tools –> Event Viewer เพื่อดูผลก็จะพบ log ที่เราสั่งบันทึกไปตามรูปด้านล่าง

      image

    การเก็บ log ลงใน Database

    เริ่มต้นด้วยการสร้าง Database ใน MS SQL ชื่อว่า Logging

    จากนั้นนำ script ไปสร้าง Table ใน Database ด้วย script ด้านล่างนี้

    Code Snippet
    1. CREATE TABLE [dbo].[MyLog](
    2.     [Id] [bigint] IDENTITY(1,1) NOT NULL,
    3.     [CreateDate] [varchar](50) NULL,
    4.     [Origin] [nvarchar](50) NULL,
    5.     [Level] [varchar](50) NULL,
    6.     [Message] [nvarchar](1000) NULL,
    7.     [Exception] [nvarchar](max) NULL,
    8.     [StackTrace] [nvarchar](4000) NULL,
    9.     [Module] [varchar](100) NULL,
    10.     [User] [nvarchar](200) NULL,
    11. CONSTRAINT [PK_MyLog] PRIMARY KEY CLUSTERED
    12. (
    13.     [Id] ASC
    14.   )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS= ON) ON [PRIMARY]
    15. ) ON [PRIMARY]
    16.  
    17. GO

    เมื่อสร้าง Database และ Table ตาม script ตามข้างต้นเสร็จแล้ว

    กลับมาที่ Visual Studio ไปเปิดไฟล์ NLog.config ขึ้นมาเพื่มค่าตามตารางด้านล่างนี้

    Code Snippet
    1. <?xml version="1.0" encoding="utf-8" ?>
    2. <nlog xmlns="http://www.nlog-project.org/schemas/NLog.netfx40.xsd"
    3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" internalLogFile="int.log">
    4.      <!–See http://nlog-project.org/wiki/Configuration_file   
    5.   for information on customizing logging rules and outputs.   –>
    6.   <targets>
    7.     <!– add your targets here –>
    8.     <target xsi:type="File" name="file" fileName="${basedir}/logs/${shortdate}.log"
    9.             layout="${longdate} ${uppercase:${level}} ${message}"
    10.               archiveEvery="Day"archiveAboveSize="10000" archiveNumbering="Sequence" />
    11.     <target xsi:type="EventLog" name="evl" layout=" ${longdate}|${level:uppercase=true}|${logger}|${message}"
    12.             machineName="NINE-WNB" source="NLog01" eventId="9001" log="Application" />
    13.     <target xsi:type="Database" name="db" keepConnection="false"
    14.             useTransactions="true"
    15.             connectionString="Data Source=NINE-WNB\MSSQL2K8R2;Initial Catalog=LoggingDB;Integrated Security=True">
    16.       <commandText>
    17.         insert into MyLog ([CreateDate], [Origin], [Level], [Message], [Exception], [StackTrace], [Module], [User]) values (@createDate, @origin, @logLevel, @message, @exception, @stackTrace, @module, @user);
    18.       </commandText>
    19.       <parameter name="@createDate" layout="${longdate}"/>
    20.       <parameter name="@origin" layout="${callsite}"/>
    21.       <parameter name="@logLevel" layout="${level}"/>
    22.       <parameter name="@message" layout="${message}"/>
    23.       <parameter name="@exception" layout="${exception:format=Message,StackTrace}"/>
    24.       <parameter name="@stackTrace" layout="${stacktrace}"/>
    25.       <parameter name="@module" layout="${mdc:item=module}"/>
    26.       <parameter name="@user" layout="${mdc:item=user}"/>
    27.     </target>
    28.     
    29.   </targets>
    30.   <rules>    
    31.     <!– add your logging rules here –>
    32.     <logger name="*" minlevel="Trace" writeTo="file" />
    33.     <logger name="*" minlevel="Trace" writeTo="evl" />
    34.     <logger name="*" minlevel="Trace" writeTo="db" />
    35.   </rules>
    36. </nlog>

    อธิบาย config

    1: line3: ตรง option internalLogFile จะเป็นการบันทึกหากเกิด error จากการทำงานของ NLog

    2: line13-29:  จะเป็นการเพิ่ม database target เข้ามาใน NLog โดยค่า default จะเป็น driver ของ MSSQL

    3: line15: ให้แก้เป็น connection string ของเครื่องตัวเองครับ

    4: line25,26: เป็นการอ้างถึงค่าเพิ่มเติมที่ต้องการจะส่งมาจากโปรแกรมเพื่อบันทึกลง log table

    5: line 34: เป็นการสั่งให้ NLog ทำการบันทึกลง Target ที่ชื่อ db

     

    ต่อไปเปิดไฟล์ Program.cs เพื่อแก้ไขโค้ดตามตารางด้านล่างนี้

    Code Snippet
    1. public static void TestLog()
    2. {
    3.     //Assign variable value
    4.     NLog.MappedDiagnosticsContext.Set("module", "Main Program");
    5.     NLog.MappedDiagnosticsContext.Set("user", "Nine");
    6.  
    7.     //write log
    8.     logger.Trace("Test trace message");
    9.     logger.Debug("Test debug message");
    10.     logger.Info("Test informational message");
    11.     logger.Warn("Test warning message");
    12.     logger.Error("Test error message");
    13.     logger.Fatal("Test fatal error message");
    14.  
    15.     // custom log level
    16.     logger.Log(LogLevel.Info, "Test fatal error message");
    17. }

    จากโค้ดด้านบนเป็นการส่งค่าที่ต้องการจะบันทึก จากโปรแกรมลง Log Table เพื่อเก็บ User ที่ทำรายการ และ Module ที่ทำการบันทึก Log ในครั้งนี้

    ทำการกด F5 เพื่อทดสอบ

    กด Enter เพื่อจบโปรแกรม

    และลองไปเปิด Table ใน Database ดูจะได้ผลลัพธ์ตามภาพด้านล่าง

    image

    ตัว NLog ยังรองรับ Database อีกหลายชนิดไม่แต่เพียง MS SQL Server เพียงอย่างเดียว

    จึงจบการสอนใช้งานตัว NLog ไว้แค่นี้หวังว่าพอจะได้แนวทางการนำไปใช้งานกัน ซึ่งจริงๆแล้วตัว NLog นั้นยังมีความสามารถมากกว่านี้ครับ ลองไปอ่านเพิ่มเติมจากเว็บไซต์หลักของเขาที่นี่ http://nlog-project.org/

     

     

    แชร์แนวคิดการเก็บ Audit Data ในระบบ

      ก่อนที่เราจะไปเข้ารายละเอียดของแต่ละ Application แต่ละชนิดกัน จะพูดถึงว่าแต่ละระบบเองก็จะมีส่วนของ Security ที่มีใช้งานกันเช่น ใช้ user account ในการเข้าใช้งานในระบบ ก็ต้องใส่ username/password เข้ามาเพื่อตรวจสอบตัวตนว่ามีสทธิ์เข้าใช้งานระบบหรือไม่ ส่วนกรณีที่เป็น public access application เราอาจจะเก็บข้อมุลจาก client ที่เข้ามาใช้งานเท่าที่จำเป็น เช่น IP Address, การเข้าใช้งานในแต่ละหน้า เป็นต้น
      การบันทึกข้อมูลที่เป็น information data ในระบบนั้น ความเป็นเจ้าของข้อมูล ทั้งการ Create/Update เนื่องจากเมื่อมีการแก้ไขข้อมูลไปแล้ว แน่นอนว่าข้อมูลนั้นจะมีการเปลี่ยนแปลงไปเป็นข้อมูลใหม่ ซึ่งในหลายโอกาสจะเกิดปัญหา ไม่ว่าต้องการรู้ว่าใครสร้างข้อมูลนี้ ใครเป็นคนแก้ไขข้อมูลนี้ เมื่อไหร่เวลาไหน เป็นต้น ซึ่งความต้องการเหล่านี้ทำให้เราจำเป็นที่จะต้องเก็บข้อมูลเหล่านั้นเอาไว้เพื่อตอบโจทย์เหล่านี้

    เก็บข้อมูลเฉพาะ username / datetime

    เช่นตัวอย่าง Customer table

    ID FirstName Age Salary Status CreatedBy CreatedDate ModifiedBy ModifiedDate
    1 Nine xx 10000 Active Nine 10/12/2011 13:00:23 Nine 01/02/2012 07:45:45

    จากตางรางด้านบน จะเหมาะสำหรับข้อมูลที่เราให้ความสำคัญของการตรวจสอบครับ

    ข้อดีคือ

    • เก็บข้อมูลแค่ผู้สร้างและแก้ไขล่าสุด
    • ใช้พื้นที่ในการเก็บไม่เยอะมาก ข้อเสีย
    • ไม่ได้เก็บข้อมูลที่ถูกแก้ไขไป และไม่สามารถเรียกดูย้อนหลังได้
    • อาจจะต้องมีการบันทึกข้อมูลกระจายไปยังที่อื่นเพื่อทำ log เพิ่มเติม

    เก็บข้อมูลที่ถูกแก้ไขทั้ง row

    ซึ่งบางระบบก็อาจจะทำเป็น log table นั้น ๆ เพิ่มมาตามจำนวน table ที่มีในระบบ เมื่อมีการ Update Table ก็จะมาทำการ insert ลงใน table นี่เพิ่ม เช่น แก้ไข Customer Table 1 row ก็จะไป insert ลงใน Customer_Log Table 1 row เป็นต้น

    ตัวอย่าง Customer Table

    ID FirstName Age Salary Status LastModifiedBy LastModifiedDate
    1 Peter 30 50000 Deleted User3 10/02/2012 08:30:49

    Customer_Log Table

    LogNo ID FirstName Age Salary Status ModifiedBy ModifiedDate
    1 1 Peter X 20 500000 Active User1 01/02/2012 07:45:45
    2 1 Peter 30 50000 Active User2 01/02/2012 19:55:50
    3 1 Peter 30 50000 Deleted User3 10/02/2012 08:30:49

    ข้อดีคือ

    • สามารถเก็บข้อมูลที่ถูกแก้ไขไว้ได้ทั้งหมด ใช้ในกรณีที่ต้องการ audit ข้อมูลอย่างละเอียด
      ข้อเสืยคือ

    • หากมี 400 table ที่ต้องการเก็บ log ก็ต้อง x2 ตามจำนวน และข้อมูล history จะเยอะมากกินพื้นที่ใน disk
    • อาจจะต้องมีการย้ายข้อมูล log ออกจาก table เป็นประจำ หรืออาจจะแยกเป็น 2 Database เก็บกันคนละที่
    • อาจจะต้องใช้ trigger เข้าช่วยในการบันทึก log เพื่อลดการเขียนโปรแกรม

    ยังมีวิธีการเก็บ log ข้อมูลอีกหลายวิธีแต่ละวิธีก็จะมีข้อดีข้อเสียแตกต่างกันไป ดังนั้นอาจจะต้องเลือกวิธีที่เหมาะสมกับควาต้องการของระบบ ซึ่งการเก็บ log ของการเปลี่ยนแแปลงข้อมูลนั้นอาจจะจำเป็นต้องใช้งานในวันข้างหน้า แต่บาง table ก็อาจจะไม่ต้องทำการเก็บบันทึกก็ได้เนื่องจากอาจจะไม่ใช่ข้อมูลสำคัญของระบบเป็นต้น

    สรุปความ

    ก็ขอจบเรื่องของ Logging เอาไว้เพียงแค่ 2 ตอนนี้หวังว่าพอจะเป็นประโยชน์กับนักพัฒนาระบบที่มีความสนใจและกำลังค้นคว้าศึกษาครับ

    Download Source Code

     http://dl.dropbox.com/u/34809954/LoggingSrc.zip


    image

    About Me:

    Chalermpon Areepong : Nine (นาย)

    Microsoft MVP Thailand ASP.NET

    ASP.NET & MVC Developers Thailand Group : http://www.facebook.com/groups/MVCTHAIDEV/

    Greatfriends.biz Community Leader : http://greatfriends.biz

    Email : nine_biz-talk.net at hotmail dot com

    Blog : https://nine69.wordpress.com

    15/03/2012

    Application Design : Logging 1

    Filed under: C#, Core System — Tags: , — Nine MVP @ 2:58 am

    ตอนที่2
    https://nine69.wordpress.com/2012/04/21/application-design-logging-2/

    หายไปนาน กลับมากับหัวข้อที่ว่าด้วยเรื่องของการซับพอทโปรแกรมและระบบที่เรากำลังจะสร้างกัน เพราะคงน้อยมากที่นักพัฒนาหลังจากเขียนโปรแกรมเสร็จแล้ว จะหายไปไม่ต้องสนใจโปรแกรมของตนอีกเลย หลังจากมีผู้ใช้งานเริ่มใช้งานระบบนั้น ๆ  เราเรียกว่าการซัพพอทหลังการพัฒนาระบบ ไม่ว่าจะเป็น bug, human error, system failed, system down, system maintenance เมื่อเกิดขึ้นแล้ว ปัญหาจะวิ่งกลับมายังผู้พัฒนาหรือบุคคลที่ต้องเป็นแพะ (admin support) หากไม่ได้ออกแบบส่วนนี้ไว้หรือทำได้ไม่ดีพอ  เราจะได้เห็นฝ่าย IT เจ้าของระบบนั้นๆ นั่งทำงานคิ้วขมวดทั้งวันทั้งคืนเป็นแน่

     

    ปัญหาหากโปรแกรมขาดการเก็บ Log 

    ในระบบที่มีการใช้งานจากผู้ใช้ในระบบจำนวนมาก หลากหลายฝ่าย หลายตำแหน่ง ระดับการทำงานแตกต่างกัน และมีการเข้าใช้งานโปรแกรมที่เราได้พัฒนาไว้  บ่อยครั้งที่เกิดการทำงานที่ผิดพลาดไม่ว่าจะเกิดจากตัวระบบเอง หรือเกิดจากผู้ใช้งาน  ซึ่งหากเราไม่ได้ทำการเก็บบันทึกข้อมูลของปัญหาที่เกิดขึ้นไว้แล้ว  ยากที่จะทำการตรวจสอบและแก้ไขให้สะดวกและรวดเร็วได้

    เนื่องจากต้องไปหาสาเหตุจากต้นตอของปัญหา ไม่ว่าจะเกิดจากผู้ใช้หรือระบบ, หน้าจอไหน, ข้อมูลใด, กลุ่มคลาสหรือเมดธอดอะไร ข้อมูลเหล่านี้มีความจำเป็นในการตรวจสอบ ซึ่งจะช่วยให้ผู้พัฒนาทำการทดสอบระบบด้วยกรณีเดียวกันได้เพื่อให้ทราบถึงปัญหา   ซึ่งโปรแกรมที่เราๆใช้กันอยู่ไม่ว่าจะเป็น Windows 7, Office, หรืออื่น ๆ ต่างก็มีการบันทึก log การทำงานทุกอย่างเพื่อให้ผู้ใช้งานสามารถเข้าไปดูเพื่อวิเคราะห์และแก้ไขปัญหานั่นเอง

    สำหรับนักพัฒนาหน้าใหม่ อาจจะไม่ได้ดักจับ error ไว้ในโปรแกรมเลย หรือไม่ก็อาจจะใช้ MessageBox.Show(); พวกข้อความที่ error บอกผู้ใช้ระบบไปตรงๆ       ซึ่งผู้ใช้งานระบบคงไม่เข้าใจว่าเกิดอะไรขึ้น  ก็ต้อง print screen ส่งมาบอกผู้พัฒนาด้วยตัวเอง และบอกว่าทำอะไรไป ทำหน้าไหน ใส่ข้อมูลอะไร กดอะไรไป  

    ถ้าเราเป็นผู้ใช้งานเองจะรุ้สึกยังไงกับโปรแกรมนี้? ยุ่งยาก มีปัญหา ไม่มีความน่าเชื่อถือ แถมยังต้องมานั่งอธิบายโปรแกรมเมอร์ โดนซักถามเหมือนทำความผิด   เจอผุ้ใช้แบบไม่สนใจไม่แคร์บอกไม่ขอใช้งานระบบ ตีกลับมาก็คงมีเคืองกันอีก ดูไม่เป็น professional เอาเสียเลย

    ดังนั้นผู้พัฒนาอย่างเราๆ จึงจำเป็นที่จะต้องออกแบบระบบการเก็บ log การทำงานของโปรแกรมให้รองรับปัญหาที่จะเกิดขึ้นด้วย  

     

    เราควรเก็บ Log อะไรบ้าง?

    การบันทึก log นั้น อยู่ที่วัตถุประสงค์ของแต่ระบบที่ได้ออกแบบและตกลงกันไว้ แต่วัตถุประสงค์หลัก ๆ ของการเก็บ log นั้นมีอยู่ 2 ส่วนคือ

    1. System Support เช่น การบันทึก Error, Information, System Status เป็นต้น

    2. Audit Support กรณีที่่ต้องคอยให้ข้อมูลเพื่อการตรวจสอบการทำงานของผุ้ใช้ หรือตัวระบบเอง เช่นไม่ว่าจะ login, logout, access page, access service, approved, commit task เป็นต้น

    โดยข้อมุลที่ควรจะถูกจัดเก็บอาจจะมีข้อมูลคร่าว ๆ ดังนี้

    1. Id (auto gen id) อาจจะเป็น bigint, long, guid เป็นต้น
    2. DateTime : วันที่และเวลาที่ทำการบันทึก log (ใช้เวลาที่ error จริง ๆ ใน Application)
    3. LogLevel : อ่านด้านล่าง
    4. Priority : อ่านด้านล่าง
    5. Title : หัวข้อที่จะบันทึก
    6. Application : กรณีมีใช้งานสถานที่เก็บ log รวมกันเช่น windows event log, database table เป็นต้น
    7. Module : ใช้บ่งบอกว่าเป็นโมดูลการทำงานส่วนไหนภายในโปรแกรม เช่น Member Register เป็นต้น
    8. Action : ใช้บ่งบอกว่าเป็นการทำงานอะไร เช่น Create New Register เป็นต้น
    9. Data : อาจจะเป็นข้อมูลที่ต้องเอาไว้ใช้ตรวจสอบ หรืออ้างอิงถึงเช่น Id ของ register user หรืออาจจะเป็น OrderNumber
    10. Message : เป็น message ของ error ที่เกิดขึ้น
    11. Trace : เป็น StackTrace ของ error ที่เกิดขึ้น
    12. SupportNo : โปรแกรมอาจจะมี troubleshooting document link แนบไว้ให้กรณีที่มีคำแนะนำให้ผู้ support ระบบ
    13. Host : อาจจะเป็น computer name, ip address ของ server นั้น ๆ ที่ Application ติดตั้งอยู่
    14. ClientIPAddress : เป็น ip address จริงของ user ที่เข้าใช้งาน application
    15. UserId : อาจจะเป็น username, user id, domain account ของผู้ใช้ที่ทำการ login ในตอนนั้น

    Log Level: ซึ่งนิยมใช้งานกันดังนี้

    1. Fatal\Critical : เป็นความผิดพลาดของระบบที่เกิดขึ้นเอง เช่น OS เกิดปัญหา, executable file corrupt, Hardware ระบบเสียหาย
    2. Error : การบันทึกเมื่อระบบเกิดปัญหาขึ้นเช่น Exception ในโปรแกรม
    3. Warning : การบันทึกเพื่อเตือนว่าอาจจะมีการทำงานผิดพลาดเกิดขึ้นหลังจากนี้
    4. Audit : การบันทึกเพื่อตรวจสอบการทำงานของผุ้ใช้ต่าง ๆ
    5. Information : การบันทึกเก็บข้อมูลบางอย่างเพื่อใช้เป็นการอ้างอิง
    6. Debug : การบันทึกเพื่อใช้ในการตรวจสอบเขียนโปรแกรม
    7. Trace : บันทึกการทำงาน ณ จุดต่าง ๆ ของโปรแกรมตั้งแต่ต้นจนจบ

    Priority: ระดับความสำคัญในการแก้ปัญหา

    1. High: เป็นระดับความสำคัญสูงสุด ซึ่งต้องต้องรีบตรวจสอบหรือแก้ไขปัญหาในทันที เช่น ไม่สามารถบันทึกข้อมูลลงในระบบได้ ทำให้ user ไม่สามารถทำงานต่อไปได้
    2. Medium: เป็นปัญหาที่มีความสำคัญ แต่ระบบหลักยังคงทำงานได้ เพียงแต่อาจจะไม่สมบูรณ์ในบางโมดูล เช่น feed ข่าวจากเว็บมาแสดงไม่ได้ เป็นต้น
    3. Low: เป็นปัญหาที่กระทบต่อการทำงานของผู้ใช้ และควรจะแก้ไขใน released ต่อไปเช่น เกิด exception ใน loop แต่เรา try ข้ามไปและทำงานต่อได้ถูกต้อง เป็นต้น

    เราสามารถบันทึก Log ต่าง ๆ เก็บไว้ที่ไหนได้บ้าง

    • File การบันทุึกเก็บลงไฟล์นั้น

    มีข้อดี

    • สามารถสร้าง method ในการเขียนไฟล์ได้เลย
    • บันทึกข้อมูลได้รวดเร็ว

    มีข้อเสีย

    • เรื่องการกำหนดขนาดไฟล์ไม่ให้ใหญ่มาก และการจัดเก็บไฟล์ให้เป็นระบบ
    • มีโอกาส file corrupt และ read/write locked
    • รวมไปถึงการเข้ามาอ่าน log file ทั้งเรื่องรูปแบบของไฟล์ สถานที่เก็บไฟล์
    • Database การบันทึกลง table ใน database

    มีข้อดี

    • ในด้านการจัดการ โดยสามารถลดการกระจัดกระจายของ log โดยรวมไว้ที่เดียว
    • สามารถเข้าถึงและอ่าน log ได้ง่าย

    ข้อเสีย

    • จะกินเนื้อในการเก็บข้อมูลจำนวนมาก
    • มี cost ที่เพิ่มขึ้นเช่น CPU time, Network bandwidth ของ DB Server
    • Windows Event Log

    ข้อดี

    • เก็บไว้ในที่เป็นมาตรฐานของ OS
    • สามารถเรียกดูได้โดย remote event viewer หรือผ่านหน้าเครื่องตรงๆ

    ข้อเสีย

    • มีผลต่อประสิทธิภาพของ OS
    • มีพื้นที่จำกัดในการเก็บบันทึก

    และยังมีที่เก็บอีกมากมายแล้วแต่ความต้องการไม่ว่าจะเป็น Email, ยิง TCP, ส่งไปเข้า MSMQ เป็นต้น ซึ่งก็แล้วแต่ว่าเราจะเลือกสถานที่จัดเก็บเพื่อความสะดวกและเหมาะสม

     

    รู้จักกับ Error ที่เกิดขึ้นในการเขียนโปรแกรม (Exception)

    โค้ดจำนวนมากผู้พัฒนาได้เขียนออกไป กรณีหากเกิดการทำงานที่ผิดพลาดขึ้น ในตอน Run time ระบบจะทำการโยน (Throw) ชุดคำสั่งมีการทำงานที่ผิดพลาดกลับมายังโปรแกรมในรูปของ Exception ซึ่งอาจจะทำให้ระบบแฮ้งค้าง เกิดไดอะล็อกเตือน ไปจนหยุดการทำงานของโปรแกรม 

    กรณีที่เราไม่ต้องการให้โปรแกรมหยุดการทำงาน และตรวจจับปัญหาของชุดคำสั่งได้นั้น แต่ละภาษาก็จะมีชุดคำสั่งในการดักจับ Error ที่เรียกว่า Try…Catch Block  ซึ่งเขียนได้ในรูปนี้

    Code 1:
    1. Person person1 = null;
    2. try
    3. {
    4.     //person1 = new Person();
    5.     person1.FullName = "call null object";
    6.     
    7. }
    8. catch (Exception ex)
    9. {
    10.     MessageBox.Show(ex.ToString());
    11. }
    12. finally
    13. {
    14.     person1 = null;
    15. }

     

    จาก code ตัวอย่างด้านบนจะเห็นได้ว่า

    (line8-11) มีการ catch error ลง Exception Class เมื่อเกิด error ขึ้นใน try block ด้านบน (line 2-7)

    ทำให้โปรแกรมเข้าไปทำงานต่อบล็อกของ catch พร้อมได้รายละเอียดของ error เพื่อนำไปจัดการปัญหาที่เกิดขึ้นต่อไป ในตัวอย่างแสดงแค่แสดง messagebox เท่านั้น

    เมื่อทำการ  Watch ex object ดูก็จะเห็นข้อมูลดังนี้

    Image 1: image 

    Exception Class เป็นเบสคลาสของ exception class อื่นๆ ซึ่งพบบ่อยว่ามักใช้ในการดักจับ error ทุกประเภทไม่ว่าจะ IO , Network , Permission , COM ซึ่งค่อนข้างใช้งานได้กว้างขวาง โดยโครงสร้างของคลาสจะมี property ของข้อมูลพื้นฐาน ให้ใช้งานดังนี้

    Property Name

    Description

    Data จะบอกข้อมูลของ Data ที่เกี่ยวข้องกับ Error นั้น
    HelpLink เป็น link ไปยัง document เพื่อช่วยอธิบายปัญหา หาก exception นั้นมีใส่ไว้
    HResult เป็น number ที่กำหนดให้ error นั้น
    InnerException เป็น exception ที่เป็นสาเหตุให้เกิด exception นี้
    Message ข้อความของ error
    Source ชื่อของโปรแกรมที่ error
    StackTrace เป็นข้อมูลที่เรียงลำดับการ call จาก Main Method ไปจนถึง line number ที่เกิด error
    TargetSite ชื่อ Main Method ที่โยน Exception

    ซึ่งข้อที่ควรสนใจคือ Exception Class ไม่ควรใช้งานเป็นคลาสหลัก เพราะเป็นเบสคลาสซึ่งจะทำให้เสียข้อมูลในส่วนของ exception ที่ควรจะได้ไม่ครบถ้วนของปัญหาที่เกิดขึ้น เช่น SqlException ที่จะมี Number property ของ Database แจ้งออกมาด้วยเป็นต้น แต่ถ้าคิดไม่ออกจริง ๆ ว่า try..catch block นี้จะเกิด exception ตัวไหนบ้างก็รอง catch สุดท้ายไว้ด้วย Exception Class ก็ได้ครับ

    Exception Class ได้ถูกกำหนดให้เป็น Based class ซึ่งถูกนำไปใช้โดยแยกออกตามส่วนของระบบดังนี้

    1. SystemException Class  เป็นคลาสได้ที่กำหนดไว้แล้วใน Common Language Runtime Class ซึ่งจะใช้เป็น Base Class อีกครั้งสำหรับสร้าง exception class ที่แยกย่อยออกไปตามการทำงานเช่น NullReferenceException, ArithmaticException, IOException, SqlException เป็นต้น
    2. ApplicationException Class  เป็นคลาสที่อนุญาตให้ผู้พัฒนานำไปใช้เป็น base class สำหรับใช้สร้าง Exception class ที่จะใช้โปรแกรมนั้น เช่น InvalidBusinessRuleException เป็นต้น

      ลองดูโค้ดชุดนี้ที่มีการสร้าง Exception ต่างๆ ในแต่ละกรณีตัวอย่าง

      Code 2:
      1. try
      2. {
      3.     //Case 1: NullReferenceException
      4.     Person person1 = null;
      5.     person1.FullName = "call null object";
      6.  
      7.     //Case 2: ArithmeticException
      8.     int i = 5;
      9.     int x = 0;
      10.     var res = i / x;
      11.  
      12.     //Case 3: ApplicationException
      13.     throw new ApplicationException("My Error");
      14.  
      15. }
      16. catch (NullReferenceException ex) //Case1
      17. {
      18.     MessageBox.Show(ex.ToString());
      19. }
      20. catch (ArithmeticException ex) //Case2
      21. {
      22.     MessageBox.Show(ex.ToString());
      23. }
      24. catch (ApplicationException ex)  //Case3
      25. {
      26.     MessageBox.Show(ex.ToString());
      27. }
      28. catch (SystemException ex) //Case1, Case2
      29. {
      30.     MessageBox.Show(ex.ToString());
      31. }
      32. catch (Exception ex) //Case1, Case2, Case3
      33. {
      34.     MessageBox.Show(ex.ToString());
      35. }

    Line 5:  จะเกิด error เนื่องจาก person1 ยังไม่ได้ทำการกำหนดค่าเริ่มต้น new Person(); ซึ่งจะวิ่งไปที่ Line 16: ซึ่งดักด้วย NullReferenceException  กรณีที่อ้างอิง object ที่เป็น null

    Line 10: จะเกิด error เนื่องจากเป็นการหารด้วย 0  ซึ่งจะวิ่งไปทำงานที่ Line 20: ซึ่งจับด้วย ArithmeticException กลุ่มคณิต

    Line 13: จะเกิด error เนื่องจากเป็นการสร้าง ApplicationException แล้ว throw ให้โปรแกรมเกิด error  จะวิ่งไปทำงานที่ Line 24: คือตรงตัว class

    ส่วน Line 28:  หากลบโค้ดตั้งแต่ Line 16 – 27 ออก  Line 5 และ 10  จะวิ่งมาทำงานที่นี่เพราะเป็น base class ที่สืบสอดมาจาก Exception Class ใช้งานในกลุ่มของ CLR Exception ทั้งหมด

     

    สำหรับ .NET App เราสามารถบันทึก Log ด้วยอะไรได้บ้าง?

    Custom Log

    โดยเป็นการเขียนโค้ดขึ้นมาเอง โดยอาจจะมี static method เอาไว้ใช้งานโดย ให้บันทึกลง File, ยิงเข้า StoreProcedure ลง Table, ส่ง Email เป็นต้น ซึ่งต้องเขียนจัดการเองทั้งหมด ซึ่งหากเขียนไว้ใช้เองก็จะพอดีกับงาน  แต่ค่อนข้างไม่ยืดหยุ่นแล้วมีข้อจำกัด รวมไปถึงมีความเสี่ยงในการจัดการของตัว Log ที่เขียนขึ้นเอง

    3rd Party Library

    การใช้กลุ่ม logging open source ถือว่าน่าสนใจมากกว่าเมื่อเปรียบเทียบข้อดีข้อเสียแล้ว  เพราะ library เหล่านี้ถูกพัฒนาขึ้นมาและใช้งานจากกลุ่มนั้น ๆ มีการพัฒนาและแก้ไขปรับปรุงโค้ดต่อเนื่อง รวมไปถึงความสามารถที่ช่วยลดการเกิดปัญหาเกี่ยวกับตัว Log เองเช่น การทำ file rolling, file size limit, various target source, multiple target source, Alternate Source,  write buffer, etc.  ผมขอแนะนำที่น่าสนใจ

    1. Enterprise Library 5.0: Logging Block จาก Microsoft เอง ก็น่าสนใจตัวนึง มีการพัฒนาต่อเนื่อง และมี Document/Lab ให้เอาไปทดลองทำกันได้

    2. Log4Net  เป็นการพัฒนาต่อยอดมาจาก Log4J มีการใช้งานกันอย่างกว้างขวาง แต่ก็ไม่เห็นมี update version มาซักระยะแล้ว

    3. NLog  เป็นตัวที่จะนำมาแนะนำในบทความตอนต่อไปครับ

       

    ส่งท้าย

    ในตอนนี้พยายามชี้ให้เห็นถึงปัญหาของการซัพพอทระบบหรือโปรแกรม  ที่เรากำลังจะส่งต่อไปให้ผุ้ใช้งานและผุ้ดูแลระบบ  ให้เข้าใจถึงความสำคัญว่าทำไมเราต้องเก็บ log ข้อมูลเอาไว้   ทั้งได้แนะนำข้อมูล log เบื้องต้นและการจัดการ exception ที่เกิดขึ้นใน .NET Application

    ในตอนต่อไปจะแนะนำการใช้งาน NLog และแนะนำการเก็บบันทึกข้อมูลจาก Application ที่แตกต่างกันครับ

     


     

    Chalermpon Areepong Nine (นาย)

    Microsoft MVP Thailand ASP.NET

    email : nine_biz-talk.net at hotmail dot com

    16/05/2011

    ASP.NET 4.0 : High Scalable ASP.NET Session and Cache with Windows Server AppFabric Caching vol.2

    Filed under: ASP.NET, Core System — Tags: , — Nine MVP @ 1:58 am
    ตอนที่ 1 (Part 1)
    ตอนที่ 2 (Part 2)

     

    Programming Level:

    • Intermediate

    Computer Skills:

    1. ASP.NET 4.0
    2. C#

    Development Tool and Library

    1. OS: Windows 7 or Windows Server 2008 or later
    2. Visual Studio 2010 or later
    3. Windows Server AppFabric Caching (download for x86, for x64)
    4. ASP.NET 4 Providers for Windows Server AppFabric Caching (download)

    Agenda

    • Introduce
    • Basic of ASP.NET Session and Cache
    • Sample ASP.NET Web Application with InProc Mode
    • Case Study: Problem of ASP.NET Web Application with InProc Mode
    • Solution: Implement Cache Server
    • Create and Setting AppFabric Cache for ASP.NET Web Application
    • Using AppFabric Cache within ASP.NET Web Application
    • Test Run ASP.NET Web Application and Monitoring Cache
    • Conclusion

    Introduce

    จากตอนที่แล้วผมได้กล่าวถึง Session State ใน Mode ต่าง ๆ  โดยเราจะมาทำความเข้าใจเกี่ยวกับหน่วยความจำภายในของ ASP.NET กัน และดูตัวอย่างเว็บที่ใช้งาน Session และ Cache ของ ASP.NET ด้วยค่าเริ่มต้นของ web.config

    ต่อด้วยทำความรู้จักกับปัญหาของ ASP.NET Web Application ที่ออกแบบไว้โดยสถาปัตยกรรมแบบง่ายๆ ที่มีข้อจำกัดในหลาย ๆ ด้าน รวมไปถึงผลกระทบอื่น ๆ ซึ่งเราจะมาแก้ปัญหาเหล่านี้ด้วยการใช้ AppFabric Caching มาช่วยในการแก้ปัญหา

     

    ASP.NET Session and Cache

    เรามาทำความรู้จักกับหน่วยความจำที่ของ ASP.NET คร่าว ๆ กันก่อนครับ

    Session

    System.Web.HttpContext.Current.Session หรือ Session เป็นหน่วยความจำที่สามารถโปรแกรมเมอร์สามารถเก็บข้อมูลของ user แต่ละคนโดยแยกจากกัน ไม่สามารถใช้ร่วมกันได้ ซึ่งเซสชั่นจะยังมีอายุคงอยู่จนกว่าจะ timeout หรือสั่งทำลายโดยโปรแกรม

    Session[“SessionName”] = null;

    Session.Remove(“session name”);

    Session.Abandon();

    Cache มี 3 ชนิดครับ

    Data Caching เป็น Programmatically สามารถเรียกใช้โดยอ้างถึง HttpContext.Current.Cache หรือ Cache ซึ่งเป็นหน่วยความจำที่เก็บข้อมูลคล้ายกับเซสชั่น แต่แคชสามารถแชร์กันใช้งานกันภายใน Web Application โดยทุกเซสชั่นสามารถเข้าถึงข้อมูลของแคชได้ สามารถจัดเก็บได้โดยโปรแกรมเมอร์เอง และการสร้างแคชจะต้องกำหนดอายุุของแคชเสมอ

    var expiredDT = DateTime.Now.AddMinutes(10);
    Cache.Insert("AllCustomers",custs, null, expiredDT, TimeSpan.Zero, CacheItemPriority.Default, null);

    Output Caching เป็น Automatic Cache ของ Page โปรแกรมเมอร์ไม่สามารถสั่งเก็บค่าหรือเรียกมาใช้งานได้ การเก็บแคชจะกระทำโดย ASP.NET โดยเก็บข้อมูลตามค่า Vary Option ที่ตั้งไว้ และจะทำลายแคชตามอายุที่กำหนดไว้ โดยสามารถกำหนด directive tag ใน aspx page ไว้ประมาณนี้

    <%@ OutputCache Duration="30" Location="Any" VaryByParam="none" %>

    Fragment Caching เป็น Automatic Cache ของ user control มีลักษณะเหมือนกับ Output Caching แต่จะจัดเก็บแคชของบางส่วนใน Page เช่น user control เป็นต้น การใช้งานก็สามารถเพิ่ม directive tag ในหน้า ascx ดังนี้

    <%@ OutputCache Duration="30" Location="Any" VaryByParam="none" %>

    ข้อมูลที่จะสามารถเก็บไว้ใน Session และ Cache ได้คือข้อมูลที่สามารถ Serializable ได้เท่านั้น เช่น Primitive data type, POCO, XML เป็นต้น

    เราก็ได้รู้จักกับ Session, Cache กันไปแล้ว ต่อไปเราจะไปดูการเรียกใช้งานในเว็บโปรแกรมกันครับ

     

    ตัวอย่าง: ASP.NET Web Application with InProc Mode (Default Mode)

    Download Code Sample Here

    InProc Mode จะเป็นการเก็บข้อมูลเซสชั่นและแคชทั้งหมดเอาที่หน่วยความจำของเครื่อง Web Server โดยตัวอย่างเว็บนี้จะมีหน้า default.aspx เป็นส่วนที่ใช้ทำการทดสอบครับ ซึ่งจะมีการเรียกใช้งานหน่วยความจำของ ASP.NET ทั้ง Session, Cache Data, OutputCache ตามปกติดังนี้

    image

    image

    ในส่วนที่ 1 ไว้สำหรับทดสอบ OutputCache ของ Page ซึ่งผมได้วาง @ OutputCahce เอาไว้ในหน้า default.aspx

    <%@ OutputCache Duration="1" Location="Any" VaryByParam="none" %>

    ปล. เอา tag ออกเพื่อทดสอบกรณีที่ไม่ใช้ OutputCache หรือกำหนดค่า 1 จะใกล้เคียงกับไม่เก็บแคช

    GetDate Button
    1. protected void btnGetDate_Click(object sender, EventArgs e)
    2. {
    3.     lblShowDate.Text =  DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss");
    4. }

    ทดสอบ 1 Duration=1 เมื่อกด Get Date Time button เพื่อดึงเวลาจะเห็นว่าเวลาจะเปลี่ยนแปลงตลอดทุกครั้งที่กดปุ่มเนื่องจาก กำหนดค่าไว้ต่ำสุดที่ 1 วินาที (แต่ถ้าไวพอ 1วิ กด2คลิ๊ก ก็ไม่เปลี่ยนจ้า)

    ทดสอบ 2 Duration=15 ASP.NET จะเก็บแคชของหน้านั้นเอาไว้ 15 วินาทีโดยไม่ต้องกลับไปทำงานใน CodeBehind เพื่อโหลดข้อมูลกลับมาใหม่ สังเกตุได้ว่าเวลาจะไม่เปลี่ยนไปจนกว่าจะครบ 15 วินาที

    ส่วนที่ 2 จะ load data มาจาก database และนำไปเก็บ ไว้ใน Session และ Cache

    Load Data Button
    1. protected void btnLoadDataToSession_Click(object sender, EventArgs e)
    2. {
    3.     using( var db = new NorthwindEntities())
    4.     {
    5.         db.ContextOptions.LazyLoadingEnabled = false;
    6.         var custs = db.Customers.ToList();
    7.         var orders = db.Orders.ToList();
    8.        
    9.         // Stored to Session
    10.         // System.Web.HttpContext.Current.Session
    11.         Session["AllCustomers"] = custs;
    12.         Session["AllOrders"] = orders;
    13.  
    14.         // Stored to Cache
    15.         // System.Web.HttpContext.Current.Cache
    16.         var expiredDT = DateTime.Now.AddMinutes(10);
    17.         Cache.Insert("AllCustomers",custs, null,
    18.             expiredDT, TimeSpan.Zero, CacheItemPriority.Default, null);
    19.         Cache.Insert("AllOrders", orders, null,
    20.             expiredDT, TimeSpan.Zero, CacheItemPriority.Default, null);
    21.  
    22.         DropDownList1.Items.Clear();
    23.         DropDownList1.DataSource = Session.Keys;
    24.         DropDownList1.DataBind();
    25.         DropDownList1.Items.Insert(0, "");
    26.         DropDownList1.SelectedIndex = 0;
    27.  
    28.         DropDownList2.Items.Clear();
    29.         DropDownList2.DataSource = Cache.GetEnumerator().ForLinq().Select(pair => pair.Key);
    30.         DropDownList2.DataBind();
    31.         DropDownList2.Items.Insert(0, "");
    32.         DropDownList2.SelectedIndex = 0;
    33.  
    34.  
    35.     }
    36. }

    line 3-7 ทำการดึงข้อมูลของ Customer, Order ขึ้นมาทั้งหมด

    line 11-12 เก็บข้อมูล Customer, Order ลงใน Session ทั้งสองตัว

    line 16-20 เก็บข้อมูล Customer, Order ลงใน Cache และกำหนดอายุของแคชไว้ที่ 10 นาที

    line 22-32 ทำการผูกคีย์ของ Session และ Cache กับ Dropdownlist ทั้ง 2 เพื่อเอาไว้ใช้ในการดึงข้อมูล

    และเราจะทำการดักจับไอเท็มของ Session และ Cache ไว้เพื่อทดสอบ scope การใช้งาน ว่าแตกต่างกันอย่างไร

    Page Load Event
    1. protected void Page_Load(object sender, EventArgs e)
    2. {
    3.     if (!IsPostBack)
    4.     {
    5.         DropDownList1.Items.Clear();
    6.         DropDownList1.DataSource = Session.Keys;
    7.         DropDownList1.DataBind();
    8.         DropDownList1.Items.Insert(0, "");
    9.         DropDownList1.SelectedIndex = 0;
    10.  
    11.         DropDownList2.Items.Clear();
    12.         DropDownList2.DataSource = Cache.GetEnumerator().ForLinq().Select(pair => pair.Key);
    13.         DropDownList2.DataBind();
    14.         DropDownList2.Items.Insert(0, "");
    15.         DropDownList2.SelectedIndex = 0;
    16.     }
    17. }

    ส่วนที่ 3 ใน dropdownlist ทั้งสองจะมี Key ที่ใช้ในการดึงข้อมูลออกมาจาก Session และ Cache เพื่อที่จะเลือกและผูกข้อมูลเข้ากับ DataGrid เพื่อแสดงผล เมื่อเลือก item ใน dropdownlist จะ postback กลับไปเพื่อดึงข้อมูลจาก session, cache ที่ต้องการ

    Dropdown IndexChanged Code
    1. // Get Data From Session
    2. protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
    3. {
    4.     List<Order> orders = null;
    5.     List<Customer> custs = null;
    6.     if (!string.IsNullOrEmpty(DropDownList1.SelectedValue))
    7.     {
    8.         if (DropDownList1.SelectedValue == "AllCustomers")
    9.         {
    10.             custs = Session[DropDownList1.SelectedValue] as List<Customer>;
    11.             GridView1.DataSource = custs;
    12.             GridView1.DataBind();
    13.         }
    14.         else if (DropDownList1.SelectedValue == "AllOrders")
    15.         {
    16.             orders = Session[DropDownList1.SelectedValue] as List<Order>;
    17.             GridView1.DataSource = orders;
    18.             GridView1.DataBind();
    19.         }
    20.     }
    21. }
    22.  
    23. //Get Data From Cache
    24. protected void DropDownList2_SelectedIndexChanged(object sender, EventArgs e)
    25. {
    26.     List<Order> orders = null;
    27.     List<Customer> custs = null;
    28.     if (!string.IsNullOrEmpty(DropDownList2.SelectedValue))
    29.     {
    30.         if (DropDownList2.SelectedValue == "AllCustomers")
    31.         {
    32.             custs = Cache.Get(DropDownList2.SelectedValue) as List<Customer>;
    33.             GridView1.DataSource = custs;
    34.             GridView1.DataBind();
    35.         }
    36.         else if (DropDownList1.SelectedValue == "AllOrders")
    37.         {
    38.             orders = Cache.Get(DropDownList2.SelectedValue) as List<Order>;
    39.             GridView1.DataSource = orders;
    40.             GridView1.DataBind();
    41.         }
    42.     }
    43. }

    line 8-18 เป็นการดึงค่าโดยใช้ key AllCustomers, AllOrders ไปดึงค่าที่เก็บอยู่ใน Session และผูกข้อมูลเข้ากับ Gridview เพื่อแสดงค่า

    line 30-40 เป็นการดึงค่าโดยใช้ key AllCustomers, AllOrders ไปดึงค่าที่เก็บอยู่ใน Cache และผูกข้อมูลเข้ากับ Gridview เพื่อแสดงค่า

    และสุุดท้ายก็จะเป็น web.config ที่เป็น ASP.NET4 ของเว็บนี้ครับ (โล่งๆ ไม่มีอะไรเลย)

    web.config
    1. <?xml version="1.0"?>
    2. <configuration>
    3.   <connectionStrings>
    4.     <add name="NorthwindEntities" connectionString="metadata=res://*/NorthwindDB.csdl|res://*/NorthwindDB.ssdl|
    5.          res://*/NorthwindDB.msl;provider=System.Data.SqlClient;provider connection string=&quot;
    6.          data source=.;initial catalog=Northwind;integrated security=True;multipleactiveresultsets=True;App=EntityFramework&quot;"
    7.          providerName="System.Data.EntityClient" />
    8.   </connectionStrings>
    9.  
    10.   <system.web>
    11.     <compilation debug="true" targetFramework="4.0" />
    12.   </system.web>
    13.  
    14.   <system.webServer>
    15.      <modules runAllManagedModulesForAllRequests="true"/>
    16.   </system.webServer>
    17. </configuration>

     

    Case Study : ตัวอย่างปัญหาจากตัวอย่างเว็บด้านบน (Problem of ASP.NET Session and Cache with InProc Mode)

    ในกรณีตัวอย่างนี้ ตัว web application วิเคราะห์และทดสอบการจำเป็นในการใช้ Session, Cache, OutputPage  ในส่วนที่เหมาะสมของเว็บแล้ว แต่ว่ายังใช้หน่วยความจำของ Web Server ในการเก็บข้อมูลเหล่านั้นตรง ๆ ก็คือ Session = InProc Mode และ default Cache Provider ที่มีมาให้นั่นเอง

    เมื่อเราพัฒนาเว็บแอ๊พพลิเคชั่นผ่านการทดสอบในส่วนของบิสซิเนสเรียบร้อยแล้ว ก็จะทำเทสในเรื่อง Load Test เพื่อหาค่าความสามารถในการรองรับ concurrent user ที่จะเข้ามาใช้งานระบบ ซึ่งในตัวอย่างได้สมมติเอาว่าผ่านการทำ load test มาแล้ว ซึ่งทั้งระบบ Web Server และ Database นั้น รองรับจำนวน user อยู่ที่ 200 concurrent โดยใช้งานปกติจะมีจำนวน concurrent ประมาณ 80-150 คน

    image

    เมื่อถึงเวลาหนึ่งทางกิจการได้เติบโตขึ้น ทำให้จำนวนผู้เข้าใช้งานเว็บมีจำนวนมากขึ้นเป็นลำดับ ซึ่งอาจจะเป็นช่วงเวลาเช่นช่วงเที่ยง เย็น และวันหยุด พบว่าหลายครั้งที่ Web Server Down เพราะต้องบริการข้อมูลยูสเซอร์ที่เข้าใช้งานพร้อมกันจำนวน 300 user concurrents ซึ่งเกินจากที่ระบบจะรองรับได้ ดังภาพด้านล่าง

    image

    ผลคือระบบล่ม ทุกอย่างจะเริ่มต้นได้ใหม่ก็จนกว่าจะ restart Web Site/Database กันใหม่ แบบนี้ทำให้ธุรกิจเสียหายแน่ ๆ ครับ

    ปัญหาและสาเหตุมีดังนี้

    Client : เนื่อง user แต่ละคนจะต้องสร้าง session ขึ้นเป็นของตัวเอง และการกดเพื่อสร้าง request กลับไปที่ web server ทุกครั้ง และจำเป็นจะต้องเข้าเว็บเซอร์เวอร์เดิมทุกรีเควส หากเว็บเซอร์เวอร์ตัวนั้นล่มไป เซสชั่นทุกอย่างก็จะหายไปหมดเช่นกัน

    Web Server : มีการเก็บ Session, Cache แยกจากกันในแต่ละเว็บเซอร์เวอร์ ซึ่งไม่สามารถที่จะแชร์ข้ามเครื่องกันได้ ทำให้ข้อมูลบางตัวที่ควรจะแชร์กันได้ต้องถูกสร้างขึ้นใหม่ทุกครั้งที่มี user เข้ามาใช้งาน

    Database : มีการใช้งาน Disk อย่างหนัก เพราะทุก request ที่ส่งเข้ามาเกือบทั้งหมดจะต้องเข้าถึงข้อมูลตลอดเวลา

    ก่อนที่เราจะเลือกทางแก้ปัญหาโดยการลงทุนเพิ่ม Web Server, Upgrade Database Server เหล่านั้น หากพิจารณากันให้ดี  ปัญหาที่สำคัญก็คือ

    1. เกิดข้อจำกัดของ Web Server ในส่วนของ Memory สำหรับเก็บข้อมูลพวก Session, Cache โดยแยกไปตามขนาดของ RAM ที่ติดตั้งในแต่ไว้ใน Server

    2. เกิดข้อจำกัดของ User Process ในการทำงาน โดยจะทำงานได้เพียงบน Web Server ตัวเดียวเท่านั้น

    3. มีการเข้าถึง Database ตลอดเวลาเพื่อดึงข้อมูลที่ซ้ำๆกันทุกครั้ง ที่ผู้ใช้ร้องขอบริการเดิม ๆ

    4. Web Server ใน Farm ทุกตัวควรจะเห็น Session ของ User คนเดิม เมื่อเกิดปัญหากรณี Web Server ตัวใด ๆ ที่ User ใช้งานอยู่เกิดล่ม ก็สามารถที่จะยังทำงานต่อด้วย web server ตัวอื่นได้ทัทีโดยข้อมูลปัจจุบันยังคงอยู่

    ซึ่งปัญหาเหล่านี้แก้ได้ครับ

     

    Solution : Implement Cache Server (AppFabric Caching)

    จากตอนที่ 1 นั้นผมได้แนะนำตัว AppFabric Cache Service ไปแล้ว ซึ่งเราจะนำเข้ามาใช้แก้ไขปัญหาที่เกิดขึ้นข้างต้น โดยก่อนที่จะเข้าถึง Database เราก็วาง Cache Server เอาไว้ให้เป็นตัวบริการเก็บข้อมูลทั้ง Session, Cache ตามรูปดังนี้

    image

    จากโมเดลด้านบนนี้ เราใช้ Cache Server มาวางโดยเอาไว้แก้ไขปัญหาของ Web Server ดังนี้

    1. เพิ่มขนาดของ Cache บน Web Server  โดยขนาดจะขึ้นอยู่กับหน่วยความจำของ Cache Server

    2. เอาไว้เก็บ User Session แทนการเก็บบน Web Server ป้องกันปัญหากรณี web server ที่ user ใช้งานอยู่ขณะนั้นเกิดปัญหา ทำให้ Web Server อีกตัวสามารถทำงานแทน web server ตัวที่ล่มไปได้ทันที

    3. เป็นข้อมูลที่ถูกเรีกยใช้บ่อย และข้อมูลนั้น อาจจะเป็น Static Data หรือมีการเปลี่ยนแปลงของข้อมูลน้อย  ลดภาระของ Database ในการดึงข้อมูลส่งให้ Web Server บ่อย ๆ

    ต่อไปเข้าสู่ขั้นตอนการสร้างและนำ AppFabric Cache ไปใช้ใน ASP.NET กันครับ

     

    Create and Setting AppFabric Cache for ASP.NET Web Application

    ต่อไปเราจะทำการสร้างแคชดาต้าเบส และตั้งค่าเอาไว้ใช้งานกับ asp.net web application ของเราครับ

    โดยจะสร้างแคชเอาไว้ 2 ตัวโดยให้ชือ่ว่า ASPNETSessionCache เอาไว้เก็บข้อมูลที่เป็นเซสชั่นและ ASPNETOutputCache เอาไว้เก็บข้อมูลแคช ทำตามขึ้นตอนดังนี้

    1. เรียกหน้าต่าง Caching Administration Windows Powershell ออกมาใช้งาน

    2. พิมพ์

    Use-CacheCluster

    3. สั่งสตาร์ท service ด้วยคำสั่ง

    Start-CacheCluster

    4. เพิ่ม user สำหรับเข้าใช้งานแคช ให้ Add Current user สำหรับ Debug

    เลือก 1 ชุดคำสั่งตาม windows ที่ใช้ครับ

    – กรณีใช้ service account  (all windows edition)

    Grant-CacheAllowedClientAccount –Account “ComputerName\UserName”

    – กรณีใช้ Network Server Account (win03, win03r2, win08, vista)

    grant-cacheallowedclientaccount -Account "NETWORK SERVICE"

    – ใช้ ASPNET User account ใน Windows 7/WS08R2:

    grant-cacheallowedclientaccount -Account "IIS AppPool\ASP.NET v4.0"

    5. สร้างแคชสำหรับ asp.net ไว้เก็บเซสชั่นชื่อ ASPNETSessionCache และ ASPNETOutputCache

    New-Cache –CacheName ASPNETSessionCache –Eviction None –TimeToLive 60

    New-Cache –CacheName ASPNETOutputCache –Eviction None –TimeToLive 60

    6. เรียกดู Cache DB ที่สร้างไว้ทั้งสองก้อนว่าสำเร็จหรือไม่ด้วยคำสั่ง

    Get-Cache

    image

    7. ตรวจสอบดูว่าแคชทั้ง 2 ว่าตั้งค่าไว้อย่างไรบ้าง

    Get-CacheConfig ASPNETSessionCache

    Get-CacheConfig ASPNETOutputCache

    image

    7. ตรวจสอบค่า Staticstics ว่ามีสถานะปัจจุบันอย่างไรบ้าง

    Get-CacheStatistics ASPNETSessionCache

    Get-CacheStatistics ASPNETOutputCache

    image

    แค่นี้ AppFabric Cache ก็พร้อมใช้งานแล้วครับ ต่อไปเราจะไปดูการตั้งค่าและเรียกใช้งานภายใน asp.net กัน

     

    Using AppFabric Cache within ASP.NET Web Application

    Download Code Sample Here

    ในขั้นตอนนี้เราจะย้าย Session และ Cache จากหน่วยความจำภายในเครื่องไปเก็บไว้ใน AppFabric Cache

    การเรียกใช้ AppFabric Cache ภายใน Web Application นั้น ในตอนนี้ผมขอเลือกใช้ Library ตัวนึงซึ่งมีความสามารถเยอะกว่า Cache Client ที่ไมโครซอฟต์มีมาให้ตั้งแต่ติดตั้ง AppFabric

    การนำไปใช้งานนั้นมี 2 วิธีคือ ทำผ่าน web.config และ เขียนโค้ด

    ในขั้นตอนแรก  ดาวน์โหลด ASP.NET 4 Providers for AppFabric Caching จาก CodePlex มาใช้งาน ให้ unzip ออกและมองหา “Microsoft.Web.DistributedCache.dll” โดยตัวนี้จะเป็น Custom Provider ที่เรียกใช้ Microsoft.ApplicationServer.Caching.Client.dll ของ AppFabric อีกทีนึง

    Setting Method 1: Edit web.config

    เปิด Web Application ขึ้นมาแก้ไข web.config ดังนี้

    – เพิ่มค่า configSection สำหรับ Cache Client ของ Microsoft เพื่อให้รู้จัก dataCachcClient Section

    web.config: configSections
    1. <section name="dataCacheClient"
    2.     type="Microsoft.ApplicationServer.Caching.DataCacheClientSection,
    3.         Microsoft.ApplicationServer.Caching.Core, Version=1.0.0.0,
    4.         Culture=neutral, PublicKeyToken=31bf3856ad364e35"
    5.     allowLocation="true"
    6.     allowDefinition="Everywhere"/>

    – เพิ่ม dataCacheClient Section เพื่อกำหนดที่อยู่ของ AppFabric Host และ Port

    web.config: dataCacheClient
    1. <dataCacheClient>
    2.   <hosts>
    3.     <host name="Nine-NB" cachePort="22233" />
    4.   </hosts>
    5. </dataCacheClient>

    – ตั้งค่าการใช้ Cache ของ ASP.NET ไปที่ AppFabric โดยกำหนดเพิ่มเติมใน <system.web>

    web.config: <sessionState>
    1. <sessionState mode="Custom" customProvider="DistributedSessionAspSessionProvider">
    2.   <providers>
    3.     <!– specify the named cache for session data –>
    4.     <!–<add name="AppFabricCacheSessionStoreProvider"
    5.       type="Microsoft.ApplicationServer.Caching.DataCacheSessionStoreProvider"
    6.       cacheName="ASPNETSession"
    7.       sharedId="ASPNETSession"/>–>
    8.     <add name="DistributedSessionAspSessionProvider"
    9.          type="Microsoft.Web.DistributedCache.DistributedCacheSessionStateStoreProvider,
    10.          Microsoft.Web.DistributedCache"
    11.         cacheName="ASPNETSessionCache"
    12.           applicationName="ASPNETWeb"
    13.           useBlobMode="false" />
    14.   </providers>
    15. </sessionState>

    line 8  ตั้งค่าชื่อของ provider ที่เราต้องการจะเพิ่มเติม

    line 9 กำหนด type ของ dll ที่เรานำมาใช้

    line11-13  เป็นการะบุ Cache โดยอ้างถึง ASPNETSession ที่สร้างไว้ใน AppFabric Cache, กำหนด ApplicationName ที่จะเข้าใช้แคชก้อนดังกล่าว และระบุไม่ใช่ Blob Mode

    line – 1 กำหนด mode=”Custom” และเลือกใช้ customProivder=”DistributedSessionAspSessionProvider” ตามที่ได้ตั้งค่าไว้

    – ตั้งค่าการใช้ Page Output Cache ของ ASP.NET ไปที่ AppFabric โดยกำหนดเพิ่มเติมใน <system.web>

    web.config: <caching>
    1. <caching>
    2.   <outputCache defaultProvider="DistributedCache">
    3.     <providers>
    4.       <add name="DistributedCache"
    5.            type="Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider,
    6.            Microsoft.Web.DistributedCache" cacheName="ASPNETOutputCache" applicationName ="ASPNETWeb" />
    7.     </providers>
    8.   </outputCache>
    9. </caching>

    line 4 กำหนดชื่อของ Cache ที่เราใช้อ้างอิง

    line 5 ใส่ type ของ dll ที่จะใช้ในการทำ page output cache

    line 6 cacheName กำหนดให้ใช้แคชที่ชื่อ ASPNEToutputCache และกำหนดชื่อ applicationName เป็น ASPNETWeb

    line 1 ที่ defaultProvider กำหนดให้ใช้ DistributedCache name ที่เราได้สร้างไว้

    Setting Method 2: Cache with Programmatically

    เพิ่มโค้ดใน Global.asax.cs ดังนี้

    Code Snippet
    1. void Application_Start(object sender, EventArgs e)
    2. {
    3.     DistributedCacheSessionStateStoreProvider.CacheConnecting += DistributedCacheSessionStateStoreProvider_CacheConnecting;
    4.     DistributedCacheOutputCacheProvider.CacheConnecting += DistributedCacheOutputCacheProvider_CacheConnecting;
    5. }
    6.  
    7. void DistributedCacheOutputCacheProvider_CacheConnecting(object sender, CacheConnectingEventArgs e)
    8. {
    9.     e.CacheFactoryConfiguration = new DataCacheFactoryConfiguration()
    10.             {
    11.                 Servers = new DataCacheServerEndpoint[] {new DataCacheServerEndpoint("Nine-NB", 22233)}
    12.             };
    13.     e.CacheName = "ASPNETOutputCache";
    14. }
    15.  
    16. void DistributedCacheSessionStateStoreProvider_CacheConnecting(object sender, CacheConnectingEventArgs e)
    17. {
    18.     e.CacheFactoryConfiguration = new DataCacheFactoryConfiguration()
    19.         {
    20.             Servers = new DataCacheServerEndpoint[] { new DataCacheServerEndpoint("Nine-NB", 22233) }
    21.         };
    22.     e.CacheName = "ASPNETSessionCache";
    23. }

    line 3-4 ทำการผูก event ให้ CacheSession และ OutputCache Provider เมื่อมีการร้องขอให้ทำการ connect ไปยัง Cache Server ก็ให้ไปทำ event Connecting ทั้งสอง

    line 7-14 เป็น event ของ Output Cache โดยทำการ add host, port number และกำหนดชื่อของ Cache Name ที่จะใช้

    line 16-23 เป็น event ของ Cache Session โดยทำการ add host, port number และกำหนดชื่อของ Cache Name ที่จะใช้

     

    Test Run ASP.NET Web Application and Monitoring Cache

    เริ่มแรกให้ทำการตรวจสอบว่า Cache ของ ASPNETSessionCache และ ASPNETOutputCache นั้นยังมีสถานะก่อนใช้งานเป็นดังนี้

    image

    ยังไม่มีการเก็บข้อมูลใด ๆ ลงใน Cache ทั้งสองก้อน    จากนั้นเราจะทำการ Run Web Site ด้วย Visual Studio 2010 ด้วยการกด F5 ได้ผลขึ้นดังนี้

    image

    เนื่องจากมี page output cache เกิดขึ้น ดงันั้นเราจะไปตรวจสอบที่ ASPNETOutputCache จะพบได้ว่ามีการเก็บ object ลงไปใน Cache เพิ่มดังนี้

    image

    ที่เห็นนี้จะเป็น Automatic Cache และ Session สำหรับ System ในการทำงานของ ASP.NET Web Application ซึ่งจะเกิดขึ้นทุกครั้งที่ User เข้ามาทำงานในหน้า Default.aspx

    ต่อไปเราจะทำการ เก็บค่าลง Session และ Cache ด้วยการกด button ในหัวข้อที่ 2 Load Data

    เมื่อ response กลับมา ลองไปคลิ๊กที่ downdown ทั้งสองจะพบว่ามี key ของทั้ง Session และ Cache ที่เราเก็บค่าไว้ใน AppFabric Caching นั่นเอง

    ทีนี้เรากลับไปดูความเปลี่ยนแปลงที่เกิดขึ้นใน Cache ทั้งสองตัวกันครับ

    image

    ก็จะพบว่ามีจำนวนของ Item ที่เก็บเพิ่มขึ้นอันเนื่องมาจากการเก็บข้อมูลลงไปนั่นเอง

     

    Conclusion

    หวังว่าพอจะมองเห็นประโยชน์จากดีไซน์นี้ หากต้องการที่จะ scale ระบบ web server ให้ทำงานได้สมบูรณ์และมีประสิทธิภาพสูงสุดนั้น บทความนี้ก็เป็นอีกหนึ่งแนวทางในการนำไปสู่ผลสำเร็จนั้นครับ

    ในตอนต่อไป ผมจะพูดถึงการนำ AppFabric Caching ไปใช้ใน MVC, EF, NHibernate เท่าที่จะพอนึกออกครับ และหากมีโอกาสผมจะทำการทดสอบในส่วนของการทำ Cache Cluster, Fault Torrelance Testing, Performance Tesing ต่อไปด้วยครับ


    Download Code Sample Here

    Chalermpon Areepong Nine (นาย)

    Microsoft MVP Thailand ASP.NET

    email : nine_biz-talk.net at hotmail dot com

    20/04/2011

    Add a Reference to the Microsoft.ApplicationServer.Caching.Client Assembly

    Filed under: ASP.NET, Core System — Nine MVP @ 1:02 am

    ขอ copy มาแปะไว้ ref กันลืมแหะๆ 

    When writing code to leverage the Windows Server AppFabric caching capabilities you will need to set a reference to the caching client classes, which are located in Microsoft.ApplicationServer.Caching.Client.dll.  Within Visual Studio 2010 this process is a bit different than how you normally approach adding a .NET Framework library reference. Usually you click the project and select to add a reference.  However, due to the AppFabric installation process, the procedure for adding the caching client reference differs.

    To add a reference to Microsoft.ApplicationServer.Caching.Client

    1. Right-click your project and select Add Reference.
    2. Click the Browse tab.
    3. Enter the following in the file name and then click Enter.
      • 64bit Windows: %windir%\Sysnative\AppFabric
      • 32bit Windows: %windir%\System32\AppFabric
    4. Locate and select both Microsoft.ApplicationServer.Caching.Client and Microsoft.ApplicationServer.Caching.Core
    For more information see the official documentation in Preparing the Development Environment for Cache Client Development

    17/04/2011

    ASP.NET 4.0 : High Scalable ASP.NET Session and Cache with Windows Server AppFabric Caching vol.1

    Filed under: ASP.NET, Core System — Tags: , — Nine MVP @ 1:10 am
    Part 1
    Part 2

    Programming Level:

    • Intermediate

    Computer Skills:

    1. ASP.NET 4.0

    Development Tool and Library

    1. OS: Windows 7 or Windows Server 2008 R2
    2. Windows Server AppFabric Caching (download for x86, for x64)

    Agenda

    • Introduce
    • ASP.NET Session Problem
    • ASP.NET Session Mode
    • Solution for Large Session State Problem
    • Advantages of AppFabric Caching
    • AppFabric Caching Architecture
    • Install And Config Windows Server AppFabric Caching (Non-Cluster)
    • Using Caching Administration Windows PowerShell
    • Summary

    Introduce

    หลายๆครั้งที่มีการถามถึงประสิทธิภาพการทำงานของ ASP.NET ในเรื่องการความเร็วตั้งแต่กด Request เข้าไปยัง Server จนกระทั้ง Response ข้อมูลออกมายัง Browser ของผู้ใช้งาน     ซึ่งมีหลายปัจจัยทีเดียวที่จะต้องออกแบบและปรัปปรุงขั้นตอนการทำงานเพื่อให้ตอบสนองผู้ใช้ได้อย่างรวดเร็วไม่ว่าจะเป็นในส่วนของการ Tuning Database เพิ่มความเร็วในการ Query Data, การใช้ paging query, เขียน code logic ให้มีประสิทธิภาพ, ออกแบบหน้า html, image ให้มีสัดส่วนที่เหมาะสม ขนาดเล็ก, การบีบอัดข้อมูลจาก Web Server ไปยัง browser ของผู้ใช้  รวมไปถึงการทำ Network Load Balance(NLB) เป็นต้น

    ซึ่งวิธีการเหล่านี้ก็เป็นส่วนสำคัญในการสร้างระบบที่มีการทำงานที่รวดเร็วโดยทั้งหมด  แต่ปัจจัยที่สำคัญมากอีกตัวก็คือหน่วยความจำสำหรับระบบนั้นเอง โดยส่วนใหญ่มักจะมีปัญหาในการใช้งานเมื่อจำนวนยูสเซอร์มีจำนวนมากขึ้น โดยระบบหน่วยความจำที่สำคัญนั้นคือการใช้ Session, Internal Cache แม้จะมีหลายท่านพยายามหนีการใช้เซสชั่นแต่มั่นใจได้ครับ ไม่ทุกระบบที่จะหลีกเลี่ยงได้ หากเจอข้อจำกัดในการ load data และเงื่อนไขที่รัดตัว

    ASP.NET Session Problem

    สำหรับงานเว็บของ ASP.NET นั้น หลายๆระบบต่างไม่ได้ให้ความสำคัญในการกำหนด physical memory สำหรับใช้เก็บเซสชั่น โดยส่วนใหญ่จะใช้ค่า default ที่ Visual Studio สร้าง web.config มาให้ หากคุณใช้เครื่อง Web Server ที่มีเสป็คสูงก็อาจจะไม่ต้องกังวล เช่น มี RAM 8-16 GB เป็นต้น  แต่หาก web server ต้องติดตั้ง web app มากกว่า 1 ระบบแล้วนั้น มีโอกาสที่จะทำให้เกิดปัญหาเรื่องหน่วยความจำไม่พอ ซึ่งเอกชนส่วนใหญ่จะใช้การติดตั้งลักษณะนี้เนื่องจากประหยัดค่าใช้จ่าย

    ในการทำงานบ่อยครั้งก็มีความจำเป็นในการโหลดข้อมูลจาก Database เข้ามาเก็บในเซสชั่น หลายๆครั้งนั้นมีความจำเป็นที่เลี่ยงไม่ได้ที่จะต้องโหลดข้อมูลจำนวนมาก ๆ เข้ามาเก็บไว้ เช่น Global Data สำหรับแชร์ให้ทุกเซสชั่น, ข้อมูลเพื่อรองรับการทำงานของยูสเซอร์กำลังใช้งานเว็บ เมื่อจำนวนยูสเซอร์มีการเข้าใช้งานในประมาณที่มากขึ้นจึงทำให้ IIS process มีขนาดใหญ่บางท่านอาจจะเจอว่ากิน ram ไปขนาด 4 GB. ทำให้ต้องมีการ upgrade web server อาจจะต้องเพิ่ม RAM หรือเพิ่ม server เป็นต้น

    ASP.NET Session Model

    เพื่อความเข้าใจในการแก้ปัญหาและพัฒนา ผมขออธิบายเกี่ยวกับ Session Mode ของ ASP.NET ที่มีอยู่ 5 Mode กันก่อนครับ

    1. InProc mode เป็นโหมดที่ทำงานโดยเก็บข้อมูลไว้ใน RAM ของ Web Server ซึ่งเป็นโหมดพื้นฐานที่ตั้งค่ามาให้ใช้งาน

    ข้อดี ง่ายและเป็นโหมดที่ทำงานได้เร็วทีสุด

    ข้อเสีย แต่มีข้อจำกัดในการรองรับจำนวนข้อมูลและการแชร์ session ใน Farm และเมื่อ web server restart ทุกอย่างที่เก็บไว้ก็จะหายไปทันที

    2. StateServer (OutProc) mode เป็นโหมดที่ทำงานโดยแยก Service ที่เป็นส่วนเสริมของ ASP.NET เองออกไปจาก IIS process ซึ่งมีชื่อว่า ASP.NET state service โดยจะมีติดตั้งให้ทันทีที่ลง .NET Framework ซึ่งจะอยู่ที่ “systemroot\Microsoft.NET\Framework\versionNumber\aspnet_state.exe”

    ข้อดี ด้วยตัว state server นี้แม้หากว่า web server เกิด restart ตัวเองขึ้นมาคุณก็แน่ใจได้ว่าเซสชั่นนั้นยังคงถูกเก็บไว้อยู่แน่นอน ซึ่งเหมาะที่จะใช้สำหรับ Web Server ใน Farm และมีความเร็วในการทำงานเป็นลำดับรองจาก InProc Mode อยู่ 1 เท่าตัว

    ข้อเสีย คือกิน RAM เหมือน InProc เพราะเก็บไว้ใน RAM เหมือนกับ InProc mode เพียงแต่แยก service ออกมาต่างหาก แปลว่าคุณควรจะมีเครื่องแยกออกมาและมีช่องเสียบ RAM เยอะๆ และเสียบ RAM ไว้เพื่อรองรับงานดังกล่าว แต่เมื่อ StateServer restart ทุกเซสชั่นก็จะหายไปหมดเช่นกัน

    ตัวอย่าง web.config

    <configuration>
      <system.web>
        <sessionStatemode=StateServerstateConnectionString=tcpip=SampleStateServer:42424
                      cookieless=falsetimeout=20/>
      </system.web>
    </configuration>

    3. SQLServer mode เป็นโหมดที่เก็บเซสชั่นไว้ใน Database

    ข้อดี คุณสมบัติเหมือนกับ StateServer mode ทุกอย่าง และถึงแม้ว่า SqlServer จะ restart ข้อมูลเซสชั่นก็ยังคงถูกเก็บเอาไว้ใน Database ไม่หายไป และดีกว่าที่ว่าสามารถขยายความจุของเซสชั่นได้เท่ากับพื้นที่บน HDD ที่มีอยู่ เหมาะที่ใช้กับ Web Server ใน Farm

    ข้อเสียที่ว่า ช้ากว่า InProc mode ประมาณ 3 เท่าตัว

    ตัวอย่าง web.config

    <configuration>
      <system.web>
        <sessionStatemode=SQLServersqlConnectionString=
                      Integrated Security=SSPI;data source=SampleSqlServer; />
      </system.web>
    </configuration>

    *** หากต้องการจะใช้งาน SqlServer Mode คุณต้องทำการ register database ด้วย aspnet_regsql.exe ตัวนี้ก่อน

    4. Custom mode หาตัวอื่นมาใช้ทดแทนทั้ง 3 mode ที่กล่าวไปข้างต้น โดยอาจจะเก็บไว้ใน Disk, NoSql เป็นต้น ซึ่งเราจะมาพูดคุยและทดสอบใช้งานกันในตอนนี้

    5. Off mode ไม่ใช้ Session (ฟังดูจะโหดร้ายไปหน่อย)

    Solution for Large Session State Problem

    แนวทางการการแก้ไขปัญหาเรื่อง RAM บน Web Server ไม่พอเพียงนั้น ก็มีแนวทางที่เป็น best practice ให้เห็นกันอยู่แล้วนะครับก็คือ

    1. เลือกใช้ SQLServer Mode  โดยตัวอย่างก็มีเช่น SharePoint, MS CRM  ก็ถูกพัฒนา base on ASP.NET เช่นกัน ซึ่งได้เลือกที่จะแก้ปัญหานี้ด้วยการใช้ SQLServer Mode เป็นตัวเก็บ Session ซึ่งก็จะหมดปัญหาในเรื่อง web app ที่ต้องใช้หน่วยความจำขนาดใหญ่อีกต่อไป อาจจะทำงานช้าลงบ้างแต่ก็คุ้ม

    2. เลือกใช้ Custom Mode อาจจะมองหา Distributed Cached System ที่ดีๆมาใช้งานเช่น Windows Server AppFabric Caching (velocity), MemCached, NCache เป็นต้น

    ในตอนนี้ขอเลือก Custom Mode มาใช้แก้ปัญหาของ Server Memory โดยใช้ AppFabric Caching

    Advantages of AppFabric Caching

    1. ทำงานเร็วกว่า SqlServer mode 4 เท่า

    2. ฟรีสำหรับ windows server 2008, windows 7

    3. มี Client library สำหรับ .NET ให้ใช้งาน

    4. สั่งงานได้จาก powershell และมี management tool ที่ใช้งานง่าย

    5. High Availability ทำงานแบบ cluster node ได้ (for windows server 2008 enterprise edition only)

    AppFabic Caching Architecture

    image

    Physical Architecture Diagram

    กรณีที่ต้องทำ Web Server Farm การทำ Cluster node นั้นเป็นสิ่งจำเป็น จากรูปด้านบนนี้ จะเห็นว่า Cache Server นั้นมีจำนวน 3 Nodes โดยใช้ Cluster configuration Strorage location ที่เดียวกัน (ต้องอยู่ใน AD เท่านั้นถึงจะทำ cluster ได้) และก็สามารถเพิ่ม node เข้าไปได้อีก เพื่อรองรับการร้องขอเก็บบันทึกและอ่านข้อมูล Session/Cache ตามที่ต้องการ  โดยสามารถจัดการทั้ง cluster ได้โดยผ่าน PowerShell

    image

    Logical Architecture Diagram

    จาก logical diagram ด้านบนนี้จะเห็นได้ว่าภายใน Cache Cluster นั้นมี Cache Host อยู่ 3 ตัว   และแถบเหลือง ๆ ก็คือ Cache มีไว้ใช้เก็บข้อมูลโดย Default Cache จะมีมาให้เสมอหลังติดตั้ง ส่วน Inventory และ Catalog นั้นเป็นส่วนที่สร้างเพิ่มเติม

    สังเกตุว่า cache สามารถ Replicate ไปยัง Cache Host ทั้ง 3 ตัวได้  แต่การกำหนด Data Region นั้นจะไม่สามารถ replicate ข้อมูลได้

    Install And Config Windows Server AppFabric Caching (Non-Cluster)

    ก่อนอื่นตรวจาสอบว่าในเครื่องได้ติดตั้ง IIS 7 Manager for Remote Administration แล้วหรือไม่ ถ้ายังไม่ติดตั้ง ก็ดาวโหลดมาติดตั้งเสียก่อน

    จากนั้นค่อยไป download AppFabric (for x86, for x64)

    1. เมื่อรัน *.msi ติดตั้งขั้นตอนแรก

    image

    2.  ให้กดเลือก checkbox ทั้งสอง จากนั้น monitoring provider เลือก System.Data.SqlClient และ Persistance provider ให้เลือก sqlStoreProvider และกดปุ่ม configure.. โดยทำซ้ำตามขั้นตอนถัดไปทั้ง 2 ปุ่ม

    image

    3.  จากนั้นไปสร้าง database สำหรับเก็บ Cache ของเรา ผมได้สร้าง AppFabricMonitoringDB และ AppFabricPersistanceDB ไว้ใน SQL Server ก่อนนี้แล้ว

    จากนั้นกด checkbox ทั้งสองตามรูปด้านล่างและเลือก Database ที่ได้สร้างไว้

    image

    4.  กดปุ่ม install

    a4

    5. เมื่อ install เสร็จก็จได้ภาพนี้ สังเกตุจะมี checkbox ถามว่าให้รัน configuration tool เลยหรือไม่

    จากนั้นกด Finish

    a5

    6. ก็จะได้หน้าจอของตัว Configuration Wizard มา

    a6

    7. เช็คเลือก Set Caching Service config  เปลี่ยน Service Account เป็นชื่อ user ที่ต้องการ

    ผมเลือก caching service configuration provider เป็น XML เนื่องจากติดตั้งบน Windows7 จึงไม่สามารถทำ Cluster ได้

    และกำหนด ShareFolder ชื่อว่า \\Nine-NB\AppFabricCacheXml เอาไว้เก็บ xml config file

    image

    8.  กำหนด port สำหรับ Service ต่าง ๆ จะแก้ไขตามต้องการก็ได้ (ห้ามใช้ port ซ้ำกัน)

    ตรวจเช็คว่าเครื่องตัวเองไม่ได้ติดตั้ง Firewall เพราะจะทำให้ติดต่อกับ service ไม่ได้

    a8

    9.  จบขั้นตอนการติดตั้ง

    image

    10. ก็จะ start IIS7 ขึ้นมาตามรูปและมี AppFabric Section เพิ่มเข้ามาตามภาพ

    image

    11. หลังจากติดตั้งเสร็จแล้วก็ลองมาตรวจสอบที่ Start –> Program –> Windows Server AppFabric  จะพบรายการดังนี้

    a9

    Using Caching Administration Windows PowerShell

    ไปที่ Start –> All Programs –> Windows Server AppFabric

    เลือก Caching Administration Windows PowerShell จะได้หน้าต่างตามนี้

    image

    1. Start-CacheCluster พิมพ์คำสั่งเพื่อสั่งให้ cache service เริ่มทำงาน จะได้เห็นว่า service กำลัง start

    image

    และจะพบว่า Service จะมี Status เป็น UP

    image

    2. Stop-CacheCluster  เป็นคำสั่งเพื่อ shutdown service

    3. Restart-CacheCluster เป็นคำสั่งให้ Restart service

    4. Get-CacheClusterHealth เป็นคำสั่งเพื่อตรวจดูสถานะของ service ว่าปัจจุบันเป็นอย่างไร

    image

    5. Grant-CacheAllowedClientAccount เป็นคำสั่ง Add Client Account เพื่อเข้าใช้งานระบบ cache

    image

    6. Get-Cache จะลิสรายการ cache ออกมาแสดงทั้ง cluster

    image

    7. New-Cache เป็นคำสั่งสร้าง cache

    image

    8. Get-CacheConfig  เป็นคำสั่งในการเรียกดูค่าคอนฟิกของ cache แต่ละตัว (ระวัง cache name เป็น case sensitive)

    image

    9. Set-CacheConfig เป็นคำสั่งในการตั้งค่าคอนฟิกให้ cache

    10 Get-CacheStatistics เป็นคำสั่งในการดูค่าการทำงานที่ผ่านมาของ cache ตัวนั้น ๆ

    image

    11. Remove-Cache  เป็นคำสั่งในการลบ cache ตัวที่ต้องการ

    image

    *** get more information : Cache Administration with Windows PowerShell (Windows Server AppFabric Caching)

    Summary

    ในตอนนี้เราได้ทำความรู้จักกับปัญหาของเซสชั่นและทำความรู้จักกับ AppFabric Caching รวมไปถึงการติดตั้งและการใช้คำสั่งในการทำงานกับตัว Cache Cluster ในตอนหน้าเราจะมาย้าย ASP.NET Session ไปเก็บลงใน AppFabric Caching กันครับ


    Chalermpon Areepong Nine (นาย)

    Microsoft MVP Thailand ASP.NET

    email : nine_biz-talk.net at hotmail dot com

    Create a free website or blog at WordPress.com.