Nine MVP's Blog

20/12/2006

ถามเกี่ยวกับ webservice และ transaction

Filed under: Computers and Internet — Nine MVP @ 5:27 pm

ถามเกี่ยวกับ webservice และ transaction

คือสมมติว่า ผมมี webservice อยู่ 2 ตัว และ database server อยู่ 2 ตัว โดย webservice1 จะติดต่อกับ DB1 และ
webservice2 จะติดต่อกับ DB2
จากนั้นผมก็มี application อยู่ตัวนึงซึ่งทำการเรียก webservice1
จากนั้น webserice1 ก็จะทำการ query data อะไรบางอย่างจาก DB1 แล้วส่งไปให้ webservice2
จากนั้น webservie2 ก็จะทำการ insert ข้อมูลลง DB2 แล้วส่งค่าอะไรบางอย่างกลับไปให้ webservice1
จากนั้น webservice1 ก็จะทำการ update status ตามที่ได้รับจาก webservice2

ดังภาพข้างล่าง

 
  
 
application call –> Webservice1DB1              
                                                          ———————->>>    ส่ง data ไป insert
                                                                                                Webervice2DB2
                                                          <<<———————-    ส่ง data กลับไปเพื่อ update status  
                            Webservice1 — DB1  ถ้าเกิด error ตรงนี้
app <—-  รับ message return
 
คำถาม
1. เราสามารถทำการ Rollback สิ่งต่างๆ ที่เราทำไปทั้งใน DB1 และ DB2 ได้หรือไม่
2. ถ้าทำได้ใช้วิธีการอย่างไร

รบกวนหน่อยครับ  ( เหตุการณ์นี้ ยังไม่เกิด ขึ้นจริง แต่ผมกลัวว่า ไม่นานมันจะต้องเกิด เลยมาถาม )

 

  LaLaLa  
 

1. ทำได้ครับ

2. ทั้ง 2 WebService ต้อง ใช้งาน WS-Transaction, WS-Coordination
    ซึ่งสำหรับ MS Plateform ไม่ง่ายเท่าไหร่นัก  = =’ ไว้จะพยายามทำ example มาให้ดูครับ รอก่อนนะ หุหุ

  Nine (นาย)  
ตอบคุณ มี่ นะครับ
คือผมต้องการที่จะควบคุม ความถูกต้องของข้อมูลครับ  ไม่เกี่ยงวิธี 
ขอให้ง่าย performance ดี คือผม ไม่ค่อยจะมีความรู้เท่าไหร่อ่ะ แบบว่ารู้น้อย
ซึ่งปกติแล้ว ผมก็ใช้
 
try
{
   BeginTransaction()
   —————– code————-
   Commit()
}
catch(Exception ex)
{
  RolllBack()
}
 
ผมเลยเรียกมันว่า Transaction

ยังงัยก็รบกวนด้วยนะครับ ^^"

 
 

  LaLaLa  

ถามเพิ่ม

1. WS อยู่บน server เครื่องเดียวกันหรือว่าแยกเครื่อง
2. DB ——————-"—————————–
3. หาก ws แยก server กันอยุ่ แล้ว Network แยกจากกันหรือไม่

  Nine (นาย)  
ทุกอย่าง ถูกแยกออกจากกัน หมดเลยครับ

เหมือนเป็นการ ส่งต่อ project อ่ะ พี่เชน (phase 2 phase 3 คงพอนึกออกนะครับ)


  LaLaLa  
REPLY #6 (30728)

งั้นก็พอจะบอกได้เลยว่า Client ที่เรียก -> WS1 Transaction ไม่สามารถ cover ไปถึง WS2 นะ
เพราะ WebService โดย nature ของมันคือเป็นแบบ StateLess  ทำอะไรไปแล้วก็จำไม่ได้ เป็นปลาทอง
ต้องทำให้ WS1, WS2 ใช้ WS-TX, WS-Coor. ตามที่บอกไปข้างบนนั่นหละครับ
 
แต่จะทดสอบ TransactionScope ให้ก่อนนะ
โดยการเรียก WS1 ที่ Server1 และ WS1 ไปเรียก WS2 ที่ Server2 อย่างที่บอกมา
ได้ผลไงจะมาเล่าให้ฟังครับ

  Nine (นาย)  

ผลมาละ

จากการที่ทดสอบ เป็นไปตามที่คาดไว้คือ
 
WS1 มีการใช้ TransactionScope  และภายในมีการเรียกใช้ WS2 อีกครั้งหนึ่ง
หลังจาก ผ่าน method ส่วนที่ Insert Data ไปแล้ว สั่งให้ Throw Exeception ขึ้นเพื่อยกเลิก TX ที่ทำทั้งหมด
 
DB ที่ WS1 ได้ทำการ rollback ออกหมด
แต่ DB ที่ WS2 ไม่สามารถ Rollback ออกได้ 
 
 
Code ที่ใช้ทดสอบ
 
 

// ใช้ TransactionScope

using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))

{

 

    //เรียก WS2 เพื่อทำการ Insert Data

    isdmcdev.Service sv = new WSGFSolution.isdmcdev.Service();

    sv.InsertMultiDB(Name, Age, Salary);
 

 

    // ใส่ ServerName เลือก DB Name

    string constrServer2 = @"Server=SQL1;Initial Catalog=TestDB;User Id=sa;password=pass";

    // Insert ลง local DB

    InsertMethod(constrServer1, Name, Age, Salary);

 

    throw new Exception("ยกเลิก TX"); //จุดวาง Breakpoint

 

}

 
 
 
 
จากผลข้างบน พอจะมีทางเลือกอยู่บ้าง
1. ใช้ WS-* ที่ post ไปก่อนหน้านี้ ใช้ใน WS ฝั่งที่มีถูกการอ้างถึง
2. ใช้การควบคุมการ Rollback ค่าใน DB เอาเองโดยใช้ WS เขียนMethod  หากเกิด Error ขึ้นก็สั่งให้ rollback คำสั่ง sql ทั้งหมด
ถ้า update อะไรไปก็ให้ update ค่าเก่ากลับ ลบอะไรไปก็ insert กลับ
3. ใช้ WCF ทดแทน WS ทั้งหมด เพราะมีความสามารถในเรื่องการทำ statefull
 
 

  Nine (นาย)
Advertisements

Asynchronous VS Synchronous อันไหนจะเร็วกว่า ???

Filed under: Computers and Internet — Nine MVP @ 5:25 pm
คือว่าผมได้ทำทดสอบเกี่ยวกับเรื่องความเร็วของ Web Services  ที่มีการเขียน Process ใน Web Services เป็นแบบ Synchronous กับ แบบ Asynchronous
 
แบบ Synchronous
รายละเอียดใน Web Services   สร้าง Connection ให้ 3 Server 
 
คำสั่ง Insert Into Test Values (‘X’) 1000 ครั้ง   ที่  Server 1  
รอจนกว่า Server 1 เสร็จ
 
คำสั่ง Insert Into Test Values (‘X’) 1000 ครั้ง   ที่  Server 2
รอจนกว่า Server 2 เสร็จ
 
คำสั่ง Insert Into Test Values (‘X’) 1000 ครั้ง   ที่  Server 3
รอจนกว่า Server 3 เสร็จ
 
จบการทำ Process Web Services
 
 
แบบ Asynchronous
รายละเอียดใน Web Services   สร้าง Connection ให้ 3 Server 
 
คำสั่ง Insert Into Test Values (‘X’) 1000 ครั้ง   ที่  Server 1  
ไม่มีการรอให้ทำ Server1 เสร็จทำ Server2 เลย
 
คำสั่ง Insert Into Test Values (‘X’) 1000 ครั้ง   ที่  Server 2 
ไม่มีการรอให้ทำ Server2 เสร็จทำ Server3 เลย
 
คำสั่ง Insert Into Test Values (‘X’) 1000 ครั้ง   ที่  Server 3 
ไม่มีการรอให้ทำ Server3
 
วนลูปรอจนกว่า Server1 , Server2 , Server3 ทำเสร็จจากคำสั่ง .IsComplete
 
ทำเสร็จหมด ก็จบการทำ Process Web Services
 
 
เมื่อเปรียบเทียบเวลาแล้ว  ปรากฏว่า  Synchronous  ดัน  เร็วกว่า Asynchronous 
ซึ่งจริงๆ แล้ว Synchronous น่าจะช้ากว่าด้วยซ้ำ  
 
ผมก็เลยสงสัยว่าจริงๆ แล้ว Asynchronous ดีอย่างไร มาสามารถทำงานได้เร็วกว่าหรือไม่
 
ใครเคยทำการทดสอบเรื่องเวลาการประมวลผล ระหว่าง 2 วิธีนี้บ้าง   รบกวนทีนะครับ
 

DFox
 
 
 

ตอบ :
 
จริง ๆ คุณต้องคิดให้ถูกก่อนนะครับ

การทำงานแบบ Multi-Thread นั้น ใช้ทรัพยากรของเครื่องพอสมควร
ยิ่งคุณแบ่ง Thread ออกมากเท่าไหร่ ทั้ง Memory ทั้ง CPU Time ก็จะถูกแบ่งกระจายออกมาไปมากเท่านั้น
หากงานไม่มีจำนวนมาก ๆ ไม่ได้ใช้เวลาทำงานนานก็ไม่น่าจะใช้งาน Multi-Thread
 
ดังนั้นควรจะใช้ให้ถูกวิธี และลองคิดแบบตั้งสมมติฐาน บนพื้นฐานความจริงกัน บวกกับปัจจัยต่าง ๆ ที่ต้องคำนึงถึง
 
ตัวอย่าง เรากำลังจะเปรียบเทียบ การทำงานแบบเน้นจำนวนงาน เพื่อหาผลลัพธ์ของเวลาที่ทำงานได้ในทั้ง 2 วิธี ต่อไปนี้
 
 
อย่างตัวอย่างของคุณ DFox   เวลาที่ใช้ในแต่ละงานนั้น เป็นเวลาในการทำงานสั้น ๆ จำนวนงานน้อย งานไม่หนัก ไม่ค้างรอผลลัพธ์นาน
 
ถ้างานที่ติดต่อกับ 3 DB แยกกันอยู่ 3 Server
มี 1 task ต่อ 1 DB
มี Process Time ประมาณ 1 วินาที
 
วิธีแบบ synchronous (1 Thread)
    – เวลาที่ใช้ในการ process tasks รวมกันก็ ไม่เกิน 3 วินาที
    – มีการ share memory ด้วยกัน ใช้ environment ของ thread เดียวกัน
    – CPU Time ใช้เต็มที่ 100% ของเวลาที่จัดสรรมาได้จาก OS
 
วิธีแบบ Asynchronous ( 3 Threads)
    – เวลาที่ใช้ในการ Process Tasks รวมกัน ไม่เกิน 1 วินาที
    – เวลาการสร้าง Thread ทั้ง 3 Threads ใช้เวลา x3 เวลา ไม่แน่ใจว่าเท่าไหร่
    – มีการจองเพื่อใช้ Memory เพิ่มขึ้น 1- 2  เท่า ใช้เวลาในการจองพื้นที่ x2 เวลา ไม่แน่ใจว่าเท่าไหร่
    – CPU Time (time slice) ที่ได้มา 100% จะถูกหาร 3 แบ่งเวลาไปให้แต่ละ Thread ใช้ทำงาน 
 
คุณจะเห็นได้ว่าคุณใช้ Asynchronous (Multi-Thread) กับงานนี้ไม่ค่อยเหมาะสมเท่าไหร่
 
 
 
มาลองดูตัวอย่างงานที่ใช้ Asynchronous (Multi-Thread) แล้วน่าจะทำงานได้เหมาะกว่า
 
 
ถ้างานที่ติดต่อกับ 3 DB แยกกันอยู่ 3 Server
มี 20 tasks ต่อ 1 DB
มี Process Time ที่ต้องค้างรอ ต่อ 1 task ประมาณ 5-10 วินาที ( คิดเฉลี่ยที่ 7.5 ละกัน)
 
 
วิธีแบบ synchronous (1 Thread)
    – เวลาที่ใช้ในการ process tasks รวมกันก็ ไม่เกิน 20 tasks  x  3 db x 7.5 วิ = 450 วินาที
    – มีการ share memory ด้วยกัน ใช้ environment ของ thread เดียวกัน
    – CPU Time ใช้เต็มที่ 100% ของเวลาที่จัดสรรมาได้จาก OS
 
วิธีแบบ Asynchronous ( 3 Threads)
    – เวลาที่ใช้ในการ Process Tasks รวมกัน ไม่เกิน 20 tasks x 1(พร้อมกัน) x 7.5 วิ = 150 วินาที

    – เวลาการสร้าง Thread ทั้ง 3 Threads ใช้เวลา x3 ไม่แน่ใจว่าเท่าไหร่
    – มีการจองเพื่อใช้ Memory เพิ่มขึ้น 1- 2  เท่า ใช้เวลาในการจองพื้นที่ x2 เวลา ไม่แน่ใจว่าเท่าไหร่
    – CPU Time (time slice) ที่ได้มา 100% จะถูกหาร 3 แบ่งเวลาไปให้แต่ละ Thread ใช้ทำงาน 

 

จะเห็นได้ว่างานที่มีจำนวนมาก และมีเวลาที่ไม่คงที่ผันเปลี่ยนไปตามค่าปัจจัยต่าง ๆ และมีแนวโน้มว่าจะ long run จริง ๆ แล้ว
ซึ่งคิดว่าน่าจะมีความเหมาะสมที่ใช้ Multi-thread มาช่วยในการทำงาน ซึ่งจะช่วยลดเวลาได้จริงครับ
 
 
 
ยังมีอีกหลายงานที่เราใช้ การทำงานแบบ Asynchronous มาช่วยอีกมากมาย
ทั้งใน User Interface เพื่อแยกการแสดงผล กับ process บางตัวที่ long run เพื่อช่วยให้ มีการตอบสนองการทำงานที่รวดเร็ว ไม่ต้องค้างรอ
เช่น msn รับ msg จากเพื่อนที่คุยมา show ตลอด และเราก็สามารถที่จะคุยโต้ตอบได้ทันทีโดยไม่ต้องรอ เป็นต้น
 
 
ก็ขอให้อ่านทำความเข้าใจ บวกกับทำทดลองให้เกิดความจริง
เพื่อที่จะใช้ technique, feature ของ programming ต่าง ๆ ได้ถูกต้องกับงานครับผม
 
 
ปล. ถ้าว่างเมื่อไหร่จะทำ ตัวอย่างจับเวลามาให้ดูครับ
 

question : เฝ้าระวัง Folder หากมีไฟล์ใดๆ เข้ามาให้โวยวาย. (FlashTaskBar)

Filed under: Computers and Internet — Nine MVP @ 5:21 pm

เฝ้าระวัง Folder หากมีไฟล์ใดๆ เข้ามาให้โวยวาย.

 

 
แนวความคิด
 
              มีโฟล์เดอร์หนึ่ง  (  \\computername\myfolder$\ )  หากมีไฟล์ใดๆเข้ามาที่โฟเดอร์ นี้
ให้โปรแกรมกระพริบ แป๊ป ๆๆๆๆๆ ที่ทากบาร์  (โปรแกรม ICQ ที่มีคนทัก  ครับผม)
ขอตัวอย่างด้วยนะครับ
 
 
——————————————–
 
ขอแสดงความนับถือทุกท่าน

 


Answer : เอา C# code ไปเลยนะ ทำ form กระพริบ

[DllImport("user32.dll")]

static extern Int16 FlashWindowEx(ref FLASHWINFO pwfi);

//Stop flashing. The system restores the window to its original state.

public const UInt32 FLASHW_STOP = 0;

//Flash the window caption.

public const UInt32 FLASHW_CAPTION = 1;

//Flash the taskbar button.

public const UInt32 FLASHW_TRAY = 2;

//Flash both the window caption and taskbar button.

//This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.

public const UInt32 FLASHW_ALL = 3;

//Flash continuously, until the FLASHW_STOP flag is set.

public const UInt32 FLASHW_TIMER = 4;

//Flash continuously until the window comes to the foreground.

public const UInt32 FLASHW_TIMERNOFG = 12;

 

[StructLayout(LayoutKind.Sequential)]

public struct FLASHWINFO

{

    public UInt16 cbSize;

    public IntPtr hwnd;

    public UInt32 dwFlags;

    public UInt16 uCount;

    public UInt32 dwTimeout;

}
 

public static bool FlashWindowEx(IntPtr hWnd)

{

    FLASHWINFO fInfo = new FLASHWINFO();

    fInfo.cbSize = (

ushort)Marshal.SizeOf(fInfo);

    fInfo.hwnd = hWnd;

    fInfo.dwFlags = FLASHW_ALL | FLASHW_TIMERNOFG | FLASHW_STOP | FLASHW_TIMER;

    fInfo.uCount =

UInt16.MaxValue;

    fInfo.dwTimeout = 0;

    return (FlashWindowEx(ref fInfo) == 0);

}
 
//เอา method นี้ไปใช้เมื่ออยากให้กระพริบที่ taskbar

private void form_blink()

{

    if (!FlashWindowEx(this.Handle)) { }

}

 
 

  

C# Code การใช้งานตามที่คุณ Jo’ ขอมา
ใช้ FileSystemWatcher + กับ ให้ Blink เตือนเมื่อมีการ Created / Modified / Deleted File ใน ShareFolder ที่ระบุไว้
พร้อมทั้งแจ้งใน show detail ต่าง ๆใน Textbox
 

public Form1()

{

    InitializeComponent();

    initFSW();

}
 

System.IO.FileSystemWatcher fileSystemWatcher1;

 

private void initFSW()

{

    fileSystemWatcher1 = new System.IO.FileSystemWatcher();

    fileSystemWatcher1.Path = "\\\\isdmcdev\\d$\\_Shared";

    fileSystemWatcher1.EnableRaisingEvents = true;

    fileSystemWatcher1.SynchronizingObject = this;

    fileSystemWatcher1.Created += new System.IO.FileSystemEventHandler(fileSystemWatcher1_Created);

    fileSystemWatcher1.Changed += new System.IO.FileSystemEventHandler(fileSystemWatcher1_Changed);

    fileSystemWatcher1.Deleted += new System.IO.FileSystemEventHandler(fileSystemWatcher1_Deleted);

}
 

void fileSystemWatcher1_Deleted(object sender, System.IO.FileSystemEventArgs e)

{

    textBox1.AppendText(e.Name + " deleted.\n");

    if (!FlashWindowEx(this.Handle))

    { }

}
 

private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)

{

    textBox1.AppendText(e.Name + " created.\n" );

    if (!FlashWindowEx(this.Handle))

    { }

}
 

private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e)

{

    textBox1.AppendText(e.Name + " modified.\n");

    if (!FlashWindowEx(this.Handle))

    { }

}


21/08/2006

ผมต้องการแปลง code utf8 ให้เป็นภาษาไทยทำไงครับ

Filed under: Computers and Internet — Nine MVP @ 12:14 am

ผมต้องการแปลง code utf8 ให้เป็นภาษาไทยทำไงครับ

เช่น
มันมีรหัส
0x0e2a0x0e270x0e310x0e2a0x0e140x0e140x0e350x0e040x0e230x0e310x0e1a0x0e0a0x0e320x0e270x0e420x0e250x0e01
 
มันแปลว่าอะไรครับ
ช่วย convert ให้หน่อยได้ไหมครับ
 
ของ โปรแกรม code ด้วยก็ดีนะครับ
ขอบคุณมากครับ
 
 
 
ตอบ :
 
ผมลองเขียนมาให้ มี 2 Function ทำงานร่วมกันครับ
 
1. เอาไว้แบ่งอักษรที่เป็น 0xXXXXX ออกจากกันก่อน เพื่อจะได้ Convert ได้
อันนี้ไว้ spilt ด้วยชุด String ปกติ C# 1.0 จะไม่มี 
 

private string[] SplitString(string testString, string split)

{

    int offset = 0;

    int index = 0;

    int[] offsets = new int[testString.Length + 1];

    while (index < testString.Length)

    {

        int indexOf = testString.IndexOf(split, index);

        if (indexOf != -1)

        {

            offsets[offset++] = indexOf;

            index = (indexOf + split.Length);

        }

        else

        {

            index = testString.Length;

        }

    }

    string[] final = new string[offset + 1];

    if (offset == 0)

    {

        final[0] = testString;

    }

    else

    {

        offset–;

        final[0] = testString.Substring(0, offsets[0]);

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

        {

            final[i + 1] = testString.Substring(offsets[i] + split.Length, offsets[i + 1] – offsets[i] – split.Length);

        }

        final[offset + 1] = testString.Substring(offsets[offset] + split.Length);

    }

    return final;

}

 
 
2. เอาไว้ Convert UTF charecter ใน Array ที่ได้จากการ Split แล้ว
 

private string getStringFromUTF8(string[] str)

{

    string strResult = "";

    for (int i = 0; i < str.Length – 1; i++)

    {

        if ((str[i].Length > 0) && (str[i] != string.Empty) && (str[i] != null))

        {

            int utfcode = Convert.ToInt32("0x" + str[i].ToString(), 16);

            strResult += (string)char.ConvertFromUtf32(utfcode);

        }

    }

    return strResult;

} 

 
 
 
 
 
How To Use:
 

//ข้อมูลจากตัวอย่างที่ให้มา

string str = "0x0e2a0x0e270x0e310x0e2a0x0e140x0e140x0e350x0e040x0e230x0e310x0e1a0x0e0a0x0e320x0e270x0e420x0e250x0e01";

 
//ตัวแปรที่ต้องใช้รับค่า

string[] aStr;

string decodeStr;

// ทำการแบ่งชุดข้อความด้วย "0x " เพราะเป็น Prefix ที่แน่นอน เช่น 0x0e2a ก็จะได้ 0e2a

aStr = SplitString(str.Trim(), "0x");

//จากนั้นก็ทำการ pass array ที่ได้เข้า Function getStringFromUTF8() ก็จะได้ string ทั้งหมดกลับออกมา

decodeStr = getStringFromUTF8(aStr);

 

MessageBox.Show(decodeStr);

 
***************************************************************************
 
จาก
0x0e2a0x0e270x0e310x0e2a0x0e140x0e140x0e350x0e040x0e230x0e310x0e1a0x0e0a0x0e320x0e270x0e420x0e250x0e01
ผลลัพธ์ที่ได้คือ
สวัสดีชาวโล
 

22/06/2006

การ Assign ค่าให้กับ member ใน class (C#) ระหว่าง Class

Filed under: Computers and Internet — Nine MVP @ 8:12 am
คำถาม

คือว่าผมมี class อยู่ 2 class ซึ่งทั้งสอง class นี้ถูก generate มาจาก schema (.xsd)

ซึ่งทั้งสอง class นี้ก็จะมี member ที่ชื่อเหมืนอกัน ยกตัวอย่างเช่น
A.CustomerID,B.CustomerID เป็นต้น
คือผมอยากเขียน function ที่ทำหน้ากำหนดค่าในคลาส A ที่มีชื่อ member เหมือนกันกับในคลาส B  
A.CustomerID = B.CustomerID แบบนี้ อ่ะครับ
ส่วนชื่อสมาชิกใน class ตัวไหนไม่เหมือนกัน ก็ไม่ต้องทำอะไร
คือว่ามันเยอะมากผมไม่อยากมานั่งพิมพ์เองเวลาเขียนโปรแกรมก็เลยอยากทำเป็น function ขึ้นมา
ไม่ทราบว่าต้องทำอย่างไรบ้างครับ ขอบคุณล่างหน้าครับ
 
 
ตอบ
 

รู้สึกข้อนี้จะต้องการ Function ที่หาชื่อของ Field Member ในแต่ละ Class มา assign ค่า จาก object ต้นทาง ไป object ปลายทาง ถ้าใช่ก็ให้ลองดู System.Reflection นะครับ

ทำตัวอย่างมาให้ดูนะ
 

class A

{

    public string mFName;

    public string mLName;

}

class B

{

    public string mFName;

    public string mLName;

}

 

Public Class AA

{

public void AA()

{

    A aa = new A();

    aa.mFName =

"ทดสอบ1";

    aa.mLName = "ทดสอบ2";

    B bb = new B();

    CloneField(aa, bb);

}

public bool CloneField(object objMaster, object objCopy)

{

    foreach (Reflection.FieldInfo om in objMaster.GetType.GetFields)

    {

        foreach (Reflection.FieldInfo oc in objCopy.GetType.GetFields)

        {

            if (om.Name == oc.Name & om.IsPublic & oc.IsPublic)

            {

                Type.GetType.InvokeMember(om.Name, Reflection.BindingFlags.SetField, null, objCopy, new object[] { om.GetValue(objMaster) });

            }

        }

    }

}

}

 

จะป้องกันการซ้ำกันของ MDI Form ใน VS 2003 ทำยังงัยดี

Filed under: Computers and Internet — Nine MVP @ 8:08 am
ลอง demo ง่าย ๆ นะ

เวลาใช้ก็แค่ 2 บรรทัดครับ
 
Class FormManager
 
 Public Class FormManager

    Private fMDI As Form

    ‘ส่ง MDI Form เข้ามา

    Public Sub New(ByVal mdiF As Form)

        fMDI = mdiF

    End Sub

    ‘สั่ง active form ที่ต้องการ

    Public Function ActiveForm(ByVal af As Form) As Boolean

        ‘หา form ที่ active อยู่ใน MDI

        For Each f As Form In fMDI.MdiChildren

            ‘ถ้าเจอ type เดียวกันเปิดอยุ่

            If f.GetType Is af.GetType Then

                ‘ให้ active ขึ้นมาโชว์

                f.Activate()

                GC.ReRegisterForFinalize(af)

                Return True

            End If

        Next

        ‘ถ้าไม่เจอ ให้ส่งเข้าไปเป็น child ของ MDI และ show ขึ้นมา

        af.MdiParent = fMDI

        af.Show()

        Return False

    End Function

End Class

 

HowTo Use
 
ที่ MDI Form ใส่ code นี้ จะเป็นการสร้าง instance ของ FormManager พร้อมทั้งส่ง MDI ที่จะทำงานเข้าไป

Private fm As New FormManager(Me)

 

และที่ปุ่ม menu ตอนจะเรียก form เช่น เราต้องการจะเรียก ProductForm จาก Menu Product ก็สั่งแค่ นี้ครับ

fm.ActiveForm(New ProductForm)

27/03/2006

จะทำ combobox แสดงชื่อ SQL Server ที่มีอยู่ใน Network ตอนนั้นทำงัยอ่า

Filed under: Computers and Internet — Nine MVP @ 6:13 pm
เรามาดูวิธีการหา Instance Name ของ SQLServer กัน

งานนี้แนะกันไว้ก่อน พระเอกคือ SQLDMO.dll หุหุ แจ่มครับ สำหรับ MSDE, MSSQL verion 7.0 – 2000

ก่อนอื่นเลย คุณต้องไป add Reference dll เจ้า SQLDMO มาก่อน
โดยเข้าไปที่ tab com

ดังรูปข้างล่าง

Add มันเข้ามาครับ ถ้าหาก หาไม่เจอแย่แล้ว แต่ก็ไม่แย่มาก 
คุณต้อง register ตัว SQLDMO.dll นี้ด้วยตัวเอง

ไปดูวิธีที่นี่ครับ
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sqldmo/dmoref_con01_8eun.asp

มาต่อกัน ด้วยการ Code เพื่อเรียก Instance Name ของ SQL Server ที่ Active อยู่ใน Network (นึกถึง มหาเวทย์ดูดดาวยังไงไม่รู้แฮะ)
 

‘ใช้ namespace ของ sqldmo
Imports SQLDMO

‘ตอน Form load
‘เรา จะ get all available SQL Servers   คับ

  
Dim sqlApp As New SQLDMO.ApplicationClass()
‘ค้นหา Instance ของ MSSQL ที่ Active
Dim sqlServers As SQLDMO.NameList = sqlApp.ListAvailableSQLServers()

‘เอามาใส่ ComboBox
Dim i As Integer
For i = 0 To sqlServers.Count – 1
   Dim srv As Object = sqlServers.Item((i + 1))
   If Not (srv Is Nothing) Then
      Me.cboServers.Items.Add(srv)
   End If
Next i

If Me.cboServers.Items.Count > 0 Then
   Me.cboServers.SelectedIndex = 0
Else
   Me.cboServers.Text = "<ไม่พบ SQL Servers>"
End If

จบการนำเสนอครับ

จะเปลี่ยนภาษาบน KeyBoard กะ .Net

Filed under: Computers and Internet — Nine MVP @ 6:08 pm
ใครที่บอกว่า VB6 นั้นเก่าโบราณ ผมคิดว่าเขาดูถูกบรรพบุรุษของ VB ค่อนข้างมาก เพราะว่าความรู้เก่าใน VB6 นั้นสามารถนำมาใช้งานกับ VB.NET ได้เป็นอย่างดี หุหุ (นอกเรื่องละ)

มาดูกันครับ ผมไปหา WIN API ผิดตัวตั้งนาน โชคดีที่ได้ผู้แนะนำ คุณ jib ต้องขอบคุณอีกครั้ง
 
Imports System.Runtime.InteropServices

‘ประกาศ API Function ไว้ใช้งาน

Private
Declare Function ActivateKeyboardLayout Lib "user32" (ByVal HKL As Long, ByVal flags As Long) As Long

‘ที่นี้ตอนใช้ก็เรียก

Dim resultLanguageKeyBoard As Long

resultLanguageKeyBoard  = ActivateKeyboardLayout(1, 0&)

‘ตอนที่จะเทียบค่า

 8975933078306161694 ‘ค่าที่ return ออกมาว่าเป็น ThaiKeyBoard

 8975933078304785417 ‘ค่าที่ return ออกมาว่าเป็น EngKeyBoard

rrrrrrrrrrrrrr

อ่ะนั่นแน มาเขียนโปรแกรมเปลี่ยนวันเวลาของเครื่องคอมเรากันเถอะ

Filed under: Computers and Internet — Nine MVP @ 5:46 pm
หลายคนสงสัยมานาน ๆ ๆ ๆ แล้วว่าเราจะแก้ไขเวลาเครื่องได้ยังงัย โดย Programmatic มาถึงเวลนี้ ผมเลยเสนอ appdominizer ตัวใหม่ ที่จะช่วยให้ท่านแก้ไขวันเวลาในเครื่องได้ดั่งใจหวัง แน่นอน งานนี้หนีไม่พ้น Win32 API อีกแล้ว
โฮ่มาเริ่มกันเลย
 
 
มาดู Class ที่ผมดัดแปลงมาจาก MS กันดีกว่า  (download code ด้านล่าง)
SystemTimes.cs
using System;

using System.Globalization;

using

System.Runtime.InteropServices;

namespace

SystemTimes

{

/// <summary>

/// Summary description for SystemTime.

/// </summary>

public class SystemTime

{

[DllImport("kernel32.dll",SetLastError=

true)]

private extern static void GetSystemTime(ref SYSTEMTIME lpSystemTime);

[DllImport("kernel32.dll",SetLastError=true) ]

private extern static uint SetSystemTime(ref SYSTEMTIME lpSystemTime);


public
SystemTime()

{}

private struct SYSTEMTIME

{

public ushort wYear;

public ushort wMonth;

public ushort wDayOfWeek;

public ushort wDay;

public ushort wHour;

public ushort wMinute;

public ushort wSecond;

public ushort wMilliseconds;

}

 

private SYSTEMTIME sysTime = new SYSTEMTIME();


///
<summary>

/// ใช้สำหรับตั้งค่าเวลาของเครื่อง

/// </summary>

/// <param name="dt"> วันเวลาที่ต้องการตั้งค่าใหม่ </param>

public void setDateTime(DateTime dt)

{

//แปลง TimeZone ให้เป็น UTC

dt = dt.ToUniversalTime();

sysTime.wYear = (

ushort)dt.Year;

sysTime.wMonth = (

ushort)dt.Month;

sysTime.wDayOfWeek = (ushort)dt.DayOfWeek;

sysTime.wDay = (

ushort)dt.Day;

sysTime.wHour = (

ushort)dt.Hour;

sysTime.wMinute = (ushort)dt.Minute;

sysTime.wSecond = (

ushort)dt.Second;

sysTime.wMilliseconds = (

ushort)dt.Millisecond;

//ตั้งเวลาใหม่

SetSystemTime(

ref sysTime);

}


///
<summary>

/// ใช้สำหรับ รับค่าเวลาของระบบ

/// </summary>

/// <returns></returns>

public DateTime GetDateTime()

{

GetSystemTime(

ref sysTime);

DateTime newDateTime =

new DateTime(sysTime.wYear,sysTime.wMonth,sysTime.wDay,

sysTime.wHour,sysTime.wMinute,sysTime.wSecond,sysTime.wMilliseconds);

//แปลง UTC จาก machine ไปเป็น TimeZone ณ ปัจจุบัน

newDateTime = newDateTime.ToLocalTime();

return newDateTime;

}

}

}

ตอนเรียกใช้  Code vb.net

Imports SystemTimes

Private systime As SystemTime

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    systime = New SystemTime

End Sub

Private Sub GetTime_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GetTime.Click

    DateTimePicker1.Value = systime.GetDateTime()

End Sub

Private Sub SetTime_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SetTime.Click

    systime.setDateTime(DateTimePicker2.Value)

    MsgBox("Now = " + Now + vbCrLf + "systime.GetDateTime() =" + systime.GetDateTime())

End Sub

มาดูผลการทำงานกัน

1. เปิดโปรแกรมขึ้นมาเทียบ กับ Date and Time Property ของ Windows

2. ต่อมาจะทำการตั้งค่าโดยใส่ วันที่ ๆ ต้องการลงไป ใน DateTimePicker ตัวล่าง โดยใส่ค่า 01/01/2550 01:00:00
และเวลาปัจจุบันตอนนี้คือ 25/03/2549 09:53:25

3. หลังกดปุ่ม Set DateTime ก็จะได้ผลลัพธ์ตามรูปข้างล่าง

สามารถ Dowload Code ของ Project Test นี้ ได้ที่ 
http://www.filelodge.com/files/hdd2/17512/Test_SystemTime.rar

Tip&Trick เพิ่มประสิทธิภาพการทำงานของ Windows Forms Apps ของคุณ

Filed under: Computers and Internet — Nine MVP @ 5:42 pm
สืบเนื่องจากว่า ภาษาอังกฤษของบางคนไม่ค่อยแข็งแรงเท่าไหร่
เลยปล่อยปะละเลยบทความดี ๆ ที่ MS ได้ตีพิมพ์ให้เหล่าโปรแกรมเมอร์ได้ไปอ่านเพิ่มเติมความรู้กัน
นั้นก็คือ MSDN, MSDN Magazine

ผมจึงหยิบบทความเรื่อง Practical Tips For Boosting The Performance Of Windows Forms Apps
ที่อยู่ใน MSND Magazine เดือน March 2006 มาทดลองดูว่าจริงหรือไม่อย่างไร

ก่อนอื่นหลายคนเคยใช้ การ Binding DataSource ต่าง ๆ ไม่ว่าจะเป็น DataSet, ArrayList, Array เข้าไปใน Windows Control

ตัวอย่าง เช่น  Binding DataSet ให้ ComboBox ตัว code ที่เราใช้กันจนแพร่หลายก็คือ  

combobox1.DataSoruce = dataset1.tables["test"];
combobox1.ValueMember = "col1";
combobox1.DisplayMember = "col2";

ซึ่งวิธีนี้ผมเองก็ใช้อยุ่ประจำ แต่ก็รู้สึกได้ว่าdelayค่อนข้างมาก
หากมี combobox ที่ต้อง binding ขณะที่ form_load เป็นจำนวนมาก ๆ ใน Form นั้น

จนได้มาอ่านบทความนี้ของ MS ก็ได้สงสัยว่ามันจะจริงเหรอ ที่ว่าเร็วกว่ามาก ด้วย code ข้างล่างนี้

combobox1.ValueMember = "col1";
combobox1.DisplayMember = "col2";

combobox1.DataSoruce = dataset1.tables["test"];

ผมจึงทดลองด้วยการจับเวลาของการทำงาน ในแต่ละ logic ว่าแบบไหนทำงานได้รวดเร็วกว่ากัน
โดยจะไป get ค่าเวลามาจาก CPU โดยตรง (class ที่ใช้จับเวลา http://www.greatfriends.biz?13622 )

Code Test

// ขณะที่ Form1_Load() ทำงาน

//เอาไว้จับเวลา

HiPerfTimer pf = new HiPerfTimer();


string
constr = "Data Source=(local);Initial Catalog=Northwind;User ID=sa;password=;";

string sql = "select CustomerID, CompanyName from Customers";


DataSet
ds = new DataSet();


//ใช้ข้อมุลจาก Northwind

SqlDataAdapter da = new SqlDataAdapter(sql , new SqlConnection(constr));

da.Fill(ds,

"test");


//จับเวลา การ binding แบบที่เรานิยมใช้กัน

pf.Start();

comboBox1.DataSource = ds.Tables[0];

comboBox1.ValueMember = "CustomerID";

comboBox1.DisplayMember = "CompanyName";

pf.Stop();

label3.Text = pf.Duration.ToString();


//จับเวลา การ binding แบบที่ MS เขาแนะนำมา

pf.Start();

comboBox2.ValueMember =

"CustomerID";

comboBox2.DisplayMember =

"CompanyName";

comboBox2.DataSource = ds.Tables[0];

pf.Stop();

label4.Text = pf.Duration.ToString();


//หาผลต่างของเวลา ทั้ง 2 วิธี

label5.Text = Convert.ToString(Convert.ToDouble(label3.Text) – Convert.ToDouble(label4.Text));

ภาพผลลัพธ์

จะเห็นได้ว่า
Code ที่เราใช้กันประจำ ทำเวลาได้ 0.173930764943589
Code ที่ MS แนะนำ     ทำเวลาได้ 0.0376771349431283
logic ที่เราใช้กันประจำช้ากว่าถึง    0.136253630000461    

ทำไมถึงช้ากว่า 5.6 เท่า น่าสงสัยทีเดียว

ผมอธิบายง่าย ๆ ว่ามีการ Binding DataSource ซ้ำซ้อนเกิดขึ้น ใน Code ที่เราใช้กันเป็นประจำ ทั้ง 3 บรรทัด
แต่ code ของ MS มีการ Bind เกิดขึ้นเพียงครั้งเดียวคือ บรรทัดสุดท้าย

จากบทความนี้ของ MS ช่วยให้เรา ได้คิดกันว่า control ที่เรากำลังใช้ ๆ กันอยู่
มันทำงานข้างในเป็นอย่างไรนั้น หากไม่ศึกษาให้ละเอียดก่อนจะนำมาใช้งาน ก็อาจจะไม่ได้วิธีการทำงานที่ดีที่สุด
ซึ่งก็อาจจะเป็นการเพิ่ม Cost ขึ้นมาโดยไม่รู้ตัวก็เป็นได้

ยังมีอีกหลาย ๆ วิธีครับ ที่จะช่วยให้การทำงานของโปรแกรมของคุณนั้นทำงานได้รวดเร็วขึ้น
ยังงัยก็ลองไปหา download อ่านกันได้ที่นี่ครับ
http://msdn.microsoft.com/msdnmag/htmlhelp.aspx

Older Posts »

Create a free website or blog at WordPress.com.