VS2010

ScottGu เปิดเผยความสามารถ VS2010 ขึ้นเรื่อยๆแล้วแฮะ ใช้ลงแบบ Side-By-Side กับ Visual Studio 2003 – 2008 ได้ด้วย อยากรู้รายละเอียดเพิ่มลองอ่านได้ที่ Blog ของเค้า คาดว่าเค้าจะเขียนซีรี่ส์ VS2010 กับ .NET 4.0 นี้ไปอีกซักพัก

ที่แปลกใจคือจำได้ว่าอาทิตย์ก่อนลองสั่ง Compatibility Check สำหรับ Windows 7 ดู ปรากฏว่า Visual Studio 2005 กับ Visual Studio 2008 มันไม่ผ่านทดสอบ นี่ยังไม่ได้ลองกับ Visual Studio 2003 เลย ถ้าเกิดมันไม่ผ่านแบบนี้แล้วจะเอามารัน Side-By-Side ใน Windows 7 ยังไงหว่า หรือว่าต้องใช้ Windows XP Mode แต่ถ้าใช้ XP Mode ก็เอามาทดสอบของใหม่ๆที่เอาไว้ใช้กับ Vista ไม่ได้สิ หรือว่า MS จะออก service pack หรือ compatibility pack เหมือนตอน VS2005 กับ Vista หรือว่าก็ใช้ๆไปเถอะ ยังไงก็ไม่น่ามีปัญหาหว่า

เคยคิดมานานว่าถ้ามี Multi-Target Support แล้ว คงไม่ต้องใช้แบบ Side-by-side ล่ะมั้งสำหรับงาน dev ทั่วๆไป แต่ก็ไม่รู้เหมือนกันเพราะไม่เคยมีงานเข้ามาตอนเวลาคาบเกี่ยวแบบนี้เลย ถึงจะมีจริงก็คงจะใส่ไว้ทั้งคู่เพราะถึงจะทำ multi target ตอน compile time ได้แต่ว่าตัว project setting มันก็ดันใช้ข้ามรุ่นกันไม่ได้อีก เมื่อไหร่มันจะทำให้ข้ามรุ่นได้น้า

ส่วนเรื่อง clean web.config สำหรับ ASP.NET นี่ท่าทางจะพึ่งสำนึกว่าไฟล์ config มันใหญ่แล้วน่ากลัวมาก เห็นของใหม่แล้วท่าทางจะเรียบง่ายดี

Joining array of strings in Java

จาก tweet ของ @veer66 เลยอยากรู้ว่าทำไมเลยลองหาดู ดีที่สุดได้แค่นี้

Java

String[] s = "Hello World".split(" ");
StringBuffer sb = new StringBuffer();
for (int i=0;i<s.length;i++){
     sb.append(s[i]);
     if (i != s.length-1)
        sb.append(" ");
}
System.out.println(sb.toString());

ถ้าภาษาอื่นล่ะ

Python (ผ่าน interactive mode)

>>> " ".join("hello world".split(" "))
'hello world'

Ruby (ผ่าน irb)

irb(main):001:0> "Hello World".split(' ').join(' ')
=> "Hello World"

C#

Console.WriteLine(String.Join(" ","Hello World".Split(' ')));

Ruby เท่สุดแฮะรู้สึกว่ามันเป็นธรรมชาติมาก

ตอนที่เขียน Python ใหม่ๆก็รู้สึกอยู่ว่ามันขัดๆ พอเริ่มคิดได้ว่า C# มันก็ไม่มี join ตรงๆเหมือนกัน ถึงนึกออกว่าตอนเขียน C# มันก็รู้สึกแปลกๆเหมือนกัน

อะ แถมด้วยโค้ดตอบ tweet นี้

irb(main):002:0> print 'คิดถึง'*99

Trim leading and trailing silence in wave file

ผมต้องมาทำงานกับ Wave File อีกแล้วล่ะ ทีนี้ปัญหาคือ Wave file ที่ได้จาก SAPI มันมีเสียงเงียบอยู่ตรงทางหัวและท้าย ดังตัวอย่างข้างล่างเป็น wave form ของคำว่า united states ซึ่งไม่เข้าใจว่ามันเป็นเฉพาะ Microsoft Anna รึเปล่า ทำให้ทางหัวมันจะเป็นเสียงเงียบอยู่ซัก 0.05 วินาที ส่วนตอนท้ายจะมีเสียงเงียบอยู่ 0.1 – 0.3 วินาที เวลาเอามาต่อกันหลายๆส่วนแล้วจะฟังเป็นเสียงเงียบไปนานมาก จึงจำเป็นเลยต้องตัดมันออก

united_state


ใน .NET นั้นเราสามารถแทนข้อมูลแบบไบนารีด้วยอาเรย์ของ byte ได้ ผมเอาข้อมูลของ wave ที่ต้องการออกมาดูพบว่าช่วงที่เป็นเสียงเงียบนั้นมีค่าเป็น 0 ตลอด ผมก็เลยจัดการเขียนโค้ดสำหรับ trim ขึ้นมา

    private static byte[] TrimStartTrailSilence(byte[] bb, out int end, out int start)
    {
        byte[] target;            
        // Trim trailing silence
        end = bb.Length -1 ;
        while (bb[end--] == 0);
        start = 0;
        while (bb[start++] == 0);
        target = new byte[end - start + 1];
        Array.Copy(bb,start, target, 0, end-start +1 );
        return target;
    }

หลักการก็คือดูจากทางหัวและท้าย แล้วตัดเอาข้อมูลมาเมื่อเจอไบต์ที่ค่าเริ่มไม่เป็นศูนย์ ไปจนถึงไบต์ที่มีค่าเริ่มเป็นศูนย์ไปจนจบ (จริงๆแล้วเราไม่ต้องคัดลอกข้อมูลลงในอาเรย์ใหม่ก็ได้เพราะเรารู้ตำแหน่งของข้อมูลจากพารามิเตอร์แล้ว) ผมลองเอาเมธอดนี้ไปใช้ดู ลองให้ SAPI สร้างเสียงออกมาต่อๆกันดู เสร็จแล้วก็มานั่งฟังผลงาน

โอ้วเยี่ยม หูแตกครับท่านผู้อ่าน พอลองเปิดไฟล์ผลลัพธ์ดูก็พบว่าหูผมไม่ได้เพี้ัยน

bang

ลองดูใหม่อีกรอบผมก็พบว่าไม่น่าแปลกใจที่กราฟมันจะโด่งได้ขนาดนี้ เพราะในช่วงที่กราฟตีโด่งเยอะๆเป็นรอยต่อระหว่างหลายๆไฟล์ และในไบต์ที่ 81, 82, .. ซึ่งเป็นไบต์ที่เริ่มมีค่าไม่ใช่ 0 ของไฟล์ที่เอามาต่อนั้นมีค่า 252 251 253, … ตอนแรกผมโยนความผิดให้ SAPI ไปครึ่งตัวแล้ว อีกครึ่งตัวที่เหลือก็ได้แต่ถามตัวเองว่า เราทำอะไรผิด พอมาลองฟังแบบยังไม่เอามาต่อพบว่ามันก็ปกติ ผมพบคนร้ายแล้ว

นั่งงงอยู่ 10 นาที สุดท้ายด้วยผลกรรมดีที่เคยทำด้วยการเขียนบล็อกเรื่อง header ของไฟล์ wave ก็ชี้นำให้ระลึกได้ว่าไฟล์ Wave มันเก็บข้อมูลเป็น Sample แล้วมันก็มีการกำหนด Sampling rate ดังนั้นเราต้องทำการเลื่อนมันให้ถูกตาม Sampling rate และ จำนวน Channel ของเราด้วย ในกรณีของผมมันเป็น Mono ซึ่งใช้ Sampling rate เป็น 8000 Hz และมีค่า Bits/Sample เป็น 16 ดังนั้นผมจึงใช้

    private static byte[] TrimStartTrailSilence(byte[] bb, out int end, out int start)
    {
        byte[] target;            
        // Trim trailing silence
        end = bb.Length;
        end--;
        while (bb[end--] == 0);
        if (end % 2 > 0)
        {
            end ++;
        }

        start = 0;
        while (bb[start++] == 0);
        if (start % 2 > 0)
        {
            start --;
        }
        target = new byte[end - start + 1];
        Array.Copy(bb,start, target, 0, end-start +1 );
        return target;
    }

แค่นี้ก็ใช้ได้เรียบร้อย

ASP.NET MVC : Controller Overview

เนื่องในโอกาสที่ ASP.NET MVC 1.0 ออกตัวเต็มมาเป็นที่เรียบร้อยแล้ว เราก็ได้โอกาสเขียนถึงเจ้า ASP.NET MVC อย่างจริงๆจังซักที แถมหลังๆมาก็ไม่ได้ใช้ ASP.NET MVC เลย คราวนี้ขอเขียนแบบ Back to basic เพื่อจะช่วยให้เห็นอะไรที่ไม่เคยเห็นบ้าง

MVC ย่อมาจาก Model-View-Controller สำหรับคนที่ยังไม่รู้ว่ามันคืออะไร ใน Wikipedia อธิบายว่า

Model–View–Controller (MVC) is an architectural pattern used in software engineering. In MVC, the model represents the information (the data) of the application; the view corresponds to elements of the user interface such as text, checkbox items, and so forth; and the controller manages the communication of data and the business rules used to manipulate the data to and from the model.

ถ้าให้เห็นรูปอย่างง่ายๆ ความสัมพันธ์ระหว่าง Model-View-Controller จะเป็นดังรูป

Controller คืออะไร

Controller เป็นส่วนที่ใช้ควบคุม จัดการและ”คิด”ว่าถ้าผู้ใช้ทำอะไรซักอย่าง แล้วโปรแกรมจะต้องทำงานอย่างไรต่อไป ซึ่งต่างจาก View เพราะในแง่ของ MVC แล้ว View จะทำหน้าที่แสดงข้อมูลที่ได้รับมาจาก Controller (ซึ่งอาจจะได้ข้อมูลมาจาก Model อีกทอด) ลองดูรูปอีกครั้งถ้าไม่เข้าใจ

ใน ASP.NET MVC คลาสที่จะทำหน้าที่เป็น Controller ได้จะต้องสืบทอดมาจากคลาส Controller และต้องมีชื่อคลาสที่ลงท้ายด้วย Controller ด้วย ยกตัวอย่างเช่น ProductController ก็จะหมายถึง Controller ชื่อ Product เป็นต้น

Controller Action

Controller Action คือเมธอดที่จะให้ทำงานซึ่งปกติแล้วจะถูกเรียกเมื่อผู้ใช้เข้ามาใน URL ที่ route เอาไว้ โดยเมธอดที่จะเป็น Controller Action ได้จะ

  • ต้องเป็น public
  • ไม่ใช่เมธอด static
  • ห้าม overload ห้ามชื่อซ้ำ จุดนี้ไม่ใช่ปัญหาเราใช้ Routing เข้ามาช่วยได้
  • ต้องมี Return type เป็น ActionResult เสมอ (ถ้าไม่ใช่มันจะถูกบังคับให้เป็น ContentResult เสมอ มันคืออะไรอ่านต่อไปเรื่อยๆ)

ส่วน Parameter ของ Action จะเป็นอะไรก็ได้

Action Result

ActionResult เป็นผลของการทำงาน Action ที่จะส่งคืนให้กับผู้ใช้ ยกตัวอย่างเช่น HTML ที่ได้จากการเรนเดอร์, ข้อความ, ไฟล์ไบนารีต่าง หรือแม้กระทั่งสั่งให้ Redirect ไปหน้าอื่นๆ เป็นต้น ใน ASP.NET MVC นั้นมีคลาสลูกของ ActionResult สำหรับผลลัพธ์แบบทั่วๆไปเตรียมไว้ให้ดังนี้

  • ViewResult – ผลลัพธ์เป็น HTML
  • EmptyResult – ผลลัพธ์คือไม่มีผลลัพธ์(งงป่าว??)
  • RedirectResult – redirect ไปที่หน้าอื่น
  • JsonResult – คืนเป็น JSON
  • JavaScriptResult – คืนเป็น Javascript
  • ContentResult – คืนเป็นข้อความ
  • FileContentResult – คืนเป็นไฟล์
  • FilePathResult – คืนเป็นไฟล์ (แต่มีชื่อไฟล์ให้ด้วย)
  • FileStreamResult – คืนเป็น stream ของไฟล์

สำหรับ action ที่มี return type ที่ไม่ใช่ Action Result ระบบจะทำการแปลงให้เป็น ContentResult เอง

ส่วนใหญ่แล้ว Result แบบต่างๆนั้นก็ต่างกันตรง Content-type Header นั่นแหละ การมี ActionResult แบบต่างๆก็จะทำให้การควบคุม content-type และการส่งข้อมูลง่ายขึ้นด้วย

ตอนนี้ลองสร้าง MVC Web Project ขึ้นมา จะเห็นว่าจะมี Controller ให้สอง Controller คือ Account และ Home ซึ่งเราจะลองมาเล่นกับ HomeController โดยลองแก้โค้ดของ Action About ซึ่งจากเดิมจะเรียก View() ซึ่งจะทำให้เกิด ViewResult เป็น

    public DateTime About()
    {
        return DateTime.Now;
    }

แล้วลองเปิด ~/Home/About ดู จะเห็นว่าผลลัพธ์เป็นเวลาปัจจุบัน

Content Result

แล้วเกิดเราเปลี่ยนเป็นโค้ดด้านล่างล่ะ

    public ActionResult About()
    {
        return RedirectToAction("Index");
    }

ถ้าเราลองเปิด ~/Home/About ด้วย wget ดู ได้ผลดังด้านล่าง

D:\Util\usr\local\wbin>wget  --verbose http://localhost:45746/Home/About
--18:25:39--  http://localhost:45746/Home/About
           => `About'
Resolving localhost... done.
Connecting to localhost[127.0.0.1]:45746... connected.
HTTP request sent, awaiting response... 302 Found
Location: / [following]
--18:25:39--  http://localhost:45746/
           => `index.html'
Connecting to localhost[127.0.0.1]:45746... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1,204 

100%[====================================>] 1,204         83.98K/s    ETA 00:00

18:25:39 (83.98 KB/s) - `index.html' saved [1204/1204]

จะเห็นว่าเกิดการ Redirect ไปที่ ~/ และในทำนองเดียวกัน เราสามารถคืนผลลัพธ์เป็น Json ได้ด้วยคำสั่ง Json() เช่นกัน

    public ActionResult About()
    {
        return Json(new {name="wiennat", url="http://onedd.net"});
    }

Json result

สรุป

Controller ใน ASP.NET MVC มีหน้าที่ควบคุม Flow การทำงานรวมไปถึงเลือก View ที่เหมาะสมเพื่อส่งผลลัพธ์ให้กับผู้ใช้ ซึ่งอาจจะไม่ใช่ HTML แต่เพียงอย่างเดียวก็ได้

%d bloggers like this: