<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Nine MVP&#039;s Blog</title>
	<atom:link href="http://nine69.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://nine69.wordpress.com</link>
	<description>Go to the future..</description>
	<lastBuildDate>Mon, 14 Nov 2011 08:23:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='nine69.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Nine MVP&#039;s Blog</title>
		<link>http://nine69.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://nine69.wordpress.com/osd.xml" title="Nine MVP&#039;s Blog" />
	<atom:link rel='hub' href='http://nine69.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Fix for &#8221; Web Standards Update for Microsoft Visual Studio 2010 SP1&#8243; remove validate SP1</title>
		<link>http://nine69.wordpress.com/2011/06/23/fix-for-web-standards-update-for-microsoft-visual-studio-2010-sp1-remove-validate-sp1/</link>
		<comments>http://nine69.wordpress.com/2011/06/23/fix-for-web-standards-update-for-microsoft-visual-studio-2010-sp1-remove-validate-sp1/#comments</comments>
		<pubDate>Thu, 23 Jun 2011 12:17:18 +0000</pubDate>
		<dc:creator>Nine MVP ASP.NET</dc:creator>
				<category><![CDATA[Visual Studio 2010]]></category>

		<guid isPermaLink="false">http://nine69.wordpress.com/?p=331</guid>
		<description><![CDATA[สำหรับใครที่ไม่สามารถติดตั้งตัว Web Standards Update for Microsoft Visual Studio 2010 SP1 (support HTML5, CSS3) ได้เนื่องจาก ตัว setup ถามหา SP1 ทั้ง ๆ ที่ติดตั้งไปแล้ว หากใครเกิดปัญหาเดียวกับผมก็ดาวน์โหลดตัว patch ของผมไปติดตั้งทดแทนได้ครับ ปล. ทดสอบติดตั้งแล้วผ่านฉลุย แก้ Link ให้ครับ รวม link download ให้ใหม่ มีหลายให้เลือก http://www.multiupload.com/XB2YYYD7Z9 &#160; หรือจะเข้าไปใน SkyDrive ของผมแล้วหา file นี้ download ไปก็ได้ที่นี่  My SkyDrive<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=331&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>สำหรับใครที่ไม่สามารถติดตั้งตัว Web Standards Update for Microsoft Visual Studio 2010 SP1 (support HTML5, CSS3) ได้เนื่องจาก ตัว setup ถามหา SP1 ทั้ง ๆ ที่ติดตั้งไปแล้ว</p>
<p>หากใครเกิดปัญหาเดียวกับผมก็ดาวน์โหลดตัว patch ของผมไปติดตั้งทดแทนได้ครับ</p>
<p>ปล. ทดสอบติดตั้งแล้วผ่านฉลุย</p>
<p><strong>แก้ Link ให้ครับ</strong></p>
<p>รวม link download ให้ใหม่ มีหลายให้เลือก</p>
<p><a href="http://www.multiupload.com/XB2YYYD7Z9">http://www.multiupload.com/XB2YYYD7Z9</a></p>
<p>&nbsp;</p>
<p>หรือจะเข้าไปใน SkyDrive ของผมแล้วหา file นี้ download ไปก็ได้ที่นี่  <a href="https://skydrive.live.com/?wa=wsignin1.0&amp;cid=dadd0b92d4b7b2a3#cid=DADD0B92D4B7B2A3&amp;id=DADD0B92D4B7B2A3%21382"><strong>My SkyDrive</strong></a></p>
<p><strong><br />
</strong></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nine69.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nine69.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nine69.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nine69.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nine69.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nine69.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nine69.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nine69.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nine69.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nine69.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nine69.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nine69.wordpress.com/331/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nine69.wordpress.com/331/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nine69.wordpress.com/331/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=331&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nine69.wordpress.com/2011/06/23/fix-for-web-standards-update-for-microsoft-visual-studio-2010-sp1-remove-validate-sp1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/8c2f25a91e95ddd2e418090794711d24?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">nine69</media:title>
		</media:content>
	</item>
		<item>
		<title>ASP.NET 4.0 : High Scalable ASP.NET Session and Cache with Windows Server AppFabric Caching vol.2</title>
		<link>http://nine69.wordpress.com/2011/05/16/asp-net-4-0-high-scalable-asp-net-session-and-cache-with-windows-server-appfabric-caching-vol-2/</link>
		<comments>http://nine69.wordpress.com/2011/05/16/asp-net-4-0-high-scalable-asp-net-session-and-cache-with-windows-server-appfabric-caching-vol-2/#comments</comments>
		<pubDate>Sun, 15 May 2011 18:58:00 +0000</pubDate>
		<dc:creator>Nine MVP ASP.NET</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Core System]]></category>
		<category><![CDATA[AppFabric Caching]]></category>

		<guid isPermaLink="false">https://nine69.wordpress.com/?p=299</guid>
		<description><![CDATA[ตอนที่ 1 (Part 1) ตอนที่ 2 (Part 2) &#160; Programming Level: Intermediate Computer Skills: ASP.NET 4.0 C# Development Tool and Library OS: Windows 7 or Windows Server 2008 or later Visual Studio 2010 or later Windows Server AppFabric Caching (download for x86, for x64) ASP.NET 4 Providers for Windows Server AppFabric Caching (download) Agenda Introduce [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=299&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h5><a href="http://nine69.wordpress.com/2011/04/17/asp-net-4-0-high-scalable-asp-net-session-state-with-windows-server-appfabric-cache-vol-1/" target="_blank">ตอนที่ 1 (Part 1)</a></h5>
<h5>ตอนที่ 2 (Part 2)</h5>
<p>&#160;</p>
<h4>Programming Level:</h4>
<ul>
<li>Intermediate </li>
</ul>
<h4>Computer Skills:</h4>
<ol>
<li>ASP.NET 4.0 </li>
<li>C# </li>
</ol>
<h4>Development Tool and Library</h4>
<ol>
<li>OS: Windows 7 or Windows Server 2008 or later </li>
<li>Visual Studio 2010 or later </li>
<li>Windows Server AppFabric Caching (download <a href="http://www.microsoft.com/downloads/info.aspx?na=46&amp;SrcFamilyId=467E5AA5-C25B-4C80-A6D2-9F8FB0F337D2&amp;SrcDisplayLang=en&amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f1%2fA%2fD%2f1ADC8F3E-4446-4D31-9B2B-9B4578934A22%2fWindowsServerAppFabricSetup_x86_6.1.exe" target="_blank"><strong>for x86</strong></a>, <a href="http://www.microsoft.com/downloads/info.aspx?na=46&amp;SrcFamilyId=467E5AA5-C25B-4C80-A6D2-9F8FB0F337D2&amp;SrcDisplayLang=en&amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f1%2fA%2fD%2f1ADC8F3E-4446-4D31-9B2B-9B4578934A22%2fWindowsServerAppFabricSetup_x64_6.1.exe" target="_blank"><strong>for x64</strong></a>) </li>
<li>ASP.NET 4 Providers for Windows Server AppFabric Caching (<a href="http://aspnet.codeplex.com/releases/view/46576#DownloadId=138395" target="_blank"><strong>download</strong></a>) </li>
</ol>
<h4>Agenda</h4>
<ul>
<li>Introduce </li>
<li>Basic of ASP.NET Session and Cache </li>
<li>Sample ASP.NET Web Application with InProc Mode </li>
<li>Case Study: Problem of ASP.NET Web Application with InProc Mode </li>
<li>Solution: Implement Cache Server </li>
<li>Create and Setting AppFabric Cache for ASP.NET Web Application </li>
<li>Using AppFabric Cache within ASP.NET Web Application </li>
<li>Test Run ASP.NET Web Application and Monitoring Cache </li>
<li>Conclusion </li>
</ul>
<h4>Introduce</h4>
<p>จากตอนที่แล้วผมได้กล่าวถึง Session State ใน Mode ต่าง ๆ&#160; โดยเราจะมาทำความเข้าใจเกี่ยวกับหน่วยความจำภายในของ ASP.NET กัน และดูตัวอย่างเว็บที่ใช้งาน Session และ Cache ของ ASP.NET ด้วยค่าเริ่มต้นของ web.config</p>
<p>ต่อด้วยทำความรู้จักกับปัญหาของ ASP.NET Web Application ที่ออกแบบไว้โดยสถาปัตยกรรมแบบง่ายๆ ที่มีข้อจำกัดในหลาย ๆ ด้าน รวมไปถึงผลกระทบอื่น ๆ ซึ่งเราจะมาแก้ปัญหาเหล่านี้ด้วยการใช้ AppFabric Caching มาช่วยในการแก้ปัญหา</p>
<p>&#160;</p>
<h4>ASP.NET Session and Cache</h4>
<p>เรามาทำความรู้จักกับหน่วยความจำที่ของ ASP.NET คร่าว ๆ กันก่อนครับ</p>
<h5>Session</h5>
<p>System.Web.HttpContext.Current.Session หรือ Session เป็นหน่วยความจำที่สามารถโปรแกรมเมอร์สามารถเก็บข้อมูลของ user แต่ละคนโดยแยกจากกัน ไม่สามารถใช้ร่วมกันได้ ซึ่งเซสชั่นจะยังมีอายุคงอยู่จนกว่าจะ timeout หรือสั่งทำลายโดยโปรแกรม</p>
<blockquote><p>Session[“SessionName”] = null;</p>
<p>Session.Remove(“session name”);</p>
<p>Session.Abandon();</p>
</blockquote>
<h5></h5>
<h5>Cache มี 3 ชนิดครับ</h5>
<p><strong><span style="text-decoration:underline;">Data Caching</span></strong> เป็น Programmatically สามารถเรียกใช้โดยอ้างถึง HttpContext.Current.Cache หรือ Cache ซึ่งเป็นหน่วยความจำที่เก็บข้อมูลคล้ายกับเซสชั่น แต่แคชสามารถแชร์กันใช้งานกันภายใน Web Application โดยทุกเซสชั่นสามารถเข้าถึงข้อมูลของแคชได้ สามารถจัดเก็บได้โดยโปรแกรมเมอร์เอง และการสร้างแคชจะต้องกำหนดอายุุของแคชเสมอ</p>
<blockquote><p>var expiredDT = DateTime.Now.AddMinutes(10);     <br />Cache.Insert(&quot;AllCustomers&quot;,custs, null, expiredDT, TimeSpan.Zero, CacheItemPriority.Default, null);</p>
</blockquote>
<p><strong><span style="text-decoration:underline;">Output Caching</span></strong> เป็น Automatic Cache ของ Page โปรแกรมเมอร์ไม่สามารถสั่งเก็บค่าหรือเรียกมาใช้งานได้ การเก็บแคชจะกระทำโดย ASP.NET โดยเก็บข้อมูลตามค่า Vary Option ที่ตั้งไว้ และจะทำลายแคชตามอายุที่กำหนดไว้ โดยสามารถกำหนด directive tag ใน aspx page ไว้ประมาณนี้</p>
<blockquote><p>&lt;%@ OutputCache Duration=&quot;30&quot; Location=&quot;Any&quot; VaryByParam=&quot;none&quot; %&gt;</p>
</blockquote>
<p><strong><span style="text-decoration:underline;">Fragment Caching</span></strong> เป็น Automatic Cache ของ user control มีลักษณะเหมือนกับ Output Caching แต่จะจัดเก็บแคชของบางส่วนใน Page เช่น user control เป็นต้น การใช้งานก็สามารถเพิ่ม directive tag ในหน้า ascx ดังนี้</p>
<blockquote><p>&lt;%@ OutputCache Duration=&quot;30&quot; Location=&quot;Any&quot; VaryByParam=&quot;none&quot; %&gt;</p>
</blockquote>
<blockquote><p><strong>ข้อมูลที่จะสามารถเก็บไว้ใน Session และ Cache ได้คือข้อมูลที่สามารถ Serializable ได้เท่านั้น เช่น Primitive data type, POCO, XML เป็นต้น</strong></p>
</blockquote>
<h5></h5>
<h4></h4>
<p>เราก็ได้รู้จักกับ Session, Cache กันไปแล้ว ต่อไปเราจะไปดูการเรียกใช้งานในเว็บโปรแกรมกันครับ</p>
<p>&#160;</p>
<h4>ตัวอย่าง: ASP.NET Web Application with InProc Mode (Default Mode)</h4>
<p><a href="http://cid-dadd0b92d4b7b2a3.office.live.com/self.aspx/%E0%B8%AA%E0%B8%B2%E0%B8%98%E0%B8%B2%E0%B8%A3%E0%B8%93%E0%B8%B0/ASPNETSessionWithAppFabricCaching.zip" target="_blank"><strong>Download Code Sample Here</strong></a></p>
<p>InProc Mode จะเป็นการเก็บข้อมูลเซสชั่นและแคชทั้งหมดเอาที่หน่วยความจำของเครื่อง Web Server โดยตัวอย่างเว็บนี้จะมีหน้า default.aspx เป็นส่วนที่ใช้ทำการทดสอบครับ ซึ่งจะมีการเรียกใช้งานหน่วยความจำของ ASP.NET ทั้ง Session, Cache Data, OutputCache ตามปกติดังนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/05/image.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb.png?w=544&#038;h=346" width="544" height="346" /></a></p>
<p><a href="http://nine69.files.wordpress.com/2011/05/image1.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb1.png?w=546&#038;h=347" width="546" height="347" /></a></p>
<p><strong>ในส่วนที่ 1</strong> ไว้สำหรับทดสอบ OutputCache ของ Page ซึ่งผมได้วาง @ OutputCahce เอาไว้ในหน้า default.aspx</p>
<pre>&lt;%@ OutputCache Duration=&quot;1&quot; Location=&quot;Any&quot; VaryByParam=&quot;none&quot; %&gt;</pre>
<p>ปล. เอา tag ออกเพื่อทดสอบกรณีที่ไม่ใช้ OutputCache หรือกำหนดค่า 1 จะใกล้เคียงกับไม่เก็บแคช</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:32879848-e6c5-43c8-9dec-bdfa27c02e9f" class="wlWriterEditableSmartContent">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">GetDate Button</div>
<div style="background:#ddd;max-height:300px;overflow:auto;">
<ol style="background:#ffffff;margin:0 0 0 2em;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">protected</span> <span style="color:#0000ff;">void</span> btnGetDate_Click(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">{</li>
<li>    lblShowDate.Text =  <span style="color:#2b91af;">DateTime</span>.Now.ToString(<span style="color:#a31515;">&quot;dd/MM/yyyy hh:mm:ss&quot;</span>);</li>
<li style="background:#f3f3f3;">}</li>
</ol>
</div>
</div>
</div>
<p>ทดสอบ 1<strong> </strong>Duration=1 เมื่อกด Get Date Time button เพื่อดึงเวลาจะเห็นว่าเวลาจะเปลี่ยนแปลงตลอดทุกครั้งที่กดปุ่มเนื่องจาก กำหนดค่าไว้ต่ำสุดที่ 1 วินาที (แต่ถ้าไวพอ 1วิ กด2คลิ๊ก ก็ไม่เปลี่ยนจ้า)</p>
<p>ทดสอบ 2 Duration=15 ASP.NET จะเก็บแคชของหน้านั้นเอาไว้ 15 วินาทีโดยไม่ต้องกลับไปทำงานใน CodeBehind เพื่อโหลดข้อมูลกลับมาใหม่ สังเกตุได้ว่าเวลาจะไม่เปลี่ยนไปจนกว่าจะครบ 15 วินาที</p>
<p><strong>ส่วนที่ 2</strong> จะ load data มาจาก database และนำไปเก็บ ไว้ใน Session และ Cache</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:6302d539-3c24-4e29-a1f1-d1b95960a268" class="wlWriterEditableSmartContent">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">Load Data Button</div>
<div style="background:#fff;overflow:auto;">
<ol style="background:#ffffff;margin:0;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">protected</span> <span style="color:#0000ff;">void</span> btnLoadDataToSession_Click(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">{</li>
<li>    <span style="color:#0000ff;">using</span>( <span style="color:#0000ff;">var</span> db = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">NorthwindEntities</span>())</li>
<li style="background:#f3f3f3;">    {</li>
<li>        db.ContextOptions.LazyLoadingEnabled = <span style="color:#0000ff;">false</span>;</li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">var</span> custs = db.Customers.ToList();</li>
<li>        <span style="color:#0000ff;">var</span> orders = db.Orders.ToList();</li>
<li style="background:#f3f3f3;">       </li>
<li>        <span style="color:#008000;">// Stored to Session </span></li>
<li style="background:#f3f3f3;">        <span style="color:#008000;">// System.Web.HttpContext.Current.Session</span></li>
<li>        Session[<span style="color:#a31515;">&quot;AllCustomers&quot;</span>] = custs;</li>
<li style="background:#f3f3f3;">        Session[<span style="color:#a31515;">&quot;AllOrders&quot;</span>] = orders; </li>
<li>&nbsp;</li>
<li style="background:#f3f3f3;">        <span style="color:#008000;">// Stored to Cache</span></li>
<li>        <span style="color:#008000;">// System.Web.HttpContext.Current.Cache</span></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">var</span> expiredDT = <span style="color:#2b91af;">DateTime</span>.Now.AddMinutes(10);</li>
<li>        Cache.Insert(<span style="color:#a31515;">&quot;AllCustomers&quot;</span>,custs, <span style="color:#0000ff;">null</span>,</li>
<li style="background:#f3f3f3;">            expiredDT, <span style="color:#2b91af;">TimeSpan</span>.Zero, <span style="color:#2b91af;">CacheItemPriority</span>.Default, <span style="color:#0000ff;">null</span>);</li>
<li>        Cache.Insert(<span style="color:#a31515;">&quot;AllOrders&quot;</span>, orders, <span style="color:#0000ff;">null</span>,</li>
<li style="background:#f3f3f3;">            expiredDT, <span style="color:#2b91af;">TimeSpan</span>.Zero, <span style="color:#2b91af;">CacheItemPriority</span>.Default, <span style="color:#0000ff;">null</span>);</li>
<li>&nbsp;</li>
<li style="background:#f3f3f3;">        DropDownList1.Items.Clear();</li>
<li>        DropDownList1.DataSource = Session.Keys;</li>
<li style="background:#f3f3f3;">        DropDownList1.DataBind();</li>
<li>        DropDownList1.Items.Insert(0, <span style="color:#a31515;">&quot;&quot;</span>);</li>
<li style="background:#f3f3f3;">        DropDownList1.SelectedIndex = 0;</li>
<li>&nbsp;</li>
<li style="background:#f3f3f3;">        DropDownList2.Items.Clear();</li>
<li>        DropDownList2.DataSource = Cache.GetEnumerator().ForLinq().Select(pair =&gt; pair.Key);</li>
<li style="background:#f3f3f3;">        DropDownList2.DataBind();</li>
<li>        DropDownList2.Items.Insert(0, <span style="color:#a31515;">&quot;&quot;</span>);</li>
<li style="background:#f3f3f3;">        DropDownList2.SelectedIndex = 0;</li>
<li>&nbsp;</li>
<li style="background:#f3f3f3;">&nbsp;</li>
<li>    }</li>
<li style="background:#f3f3f3;">}</li>
</ol>
</div>
</div>
</div>
<p>line 3-7 ทำการดึงข้อมูลของ Customer, Order ขึ้นมาทั้งหมด</p>
<p>line 11-12 เก็บข้อมูล Customer, Order ลงใน Session ทั้งสองตัว</p>
<p>line 16-20 เก็บข้อมูล Customer, Order ลงใน Cache และกำหนดอายุของแคชไว้ที่ 10 นาที</p>
<p>line 22-32 ทำการผูกคีย์ของ Session และ Cache กับ Dropdownlist ทั้ง 2 เพื่อเอาไว้ใช้ในการดึงข้อมูล</p>
<p>และเราจะทำการดักจับไอเท็มของ Session และ Cache ไว้เพื่อทดสอบ scope การใช้งาน ว่าแตกต่างกันอย่างไร</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:d30b5ed8-f4fe-4eaf-9f27-e785b2c0aff4" class="wlWriterEditableSmartContent">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">Page Load Event</div>
<div style="background:#fff;overflow:auto;">
<ol style="background:#ffffff;margin:0;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">protected</span> <span style="color:#0000ff;">void</span> Page_Load(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">{</li>
<li>    <span style="color:#0000ff;">if</span> (!IsPostBack)</li>
<li style="background:#f3f3f3;">    {</li>
<li>        DropDownList1.Items.Clear();</li>
<li style="background:#f3f3f3;">        DropDownList1.DataSource = Session.Keys;</li>
<li>        DropDownList1.DataBind();</li>
<li style="background:#f3f3f3;">        DropDownList1.Items.Insert(0, <span style="color:#a31515;">&quot;&quot;</span>);</li>
<li>        DropDownList1.SelectedIndex = 0;</li>
<li style="background:#f3f3f3;">&nbsp;</li>
<li>        DropDownList2.Items.Clear();</li>
<li style="background:#f3f3f3;">        DropDownList2.DataSource = Cache.GetEnumerator().ForLinq().Select(pair =&gt; pair.Key);</li>
<li>        DropDownList2.DataBind();</li>
<li style="background:#f3f3f3;">        DropDownList2.Items.Insert(0, <span style="color:#a31515;">&quot;&quot;</span>);</li>
<li>        DropDownList2.SelectedIndex = 0;</li>
<li style="background:#f3f3f3;">    }</li>
<li>}</li>
</ol>
</div>
</div>
</div>
<p><strong>ส่วนที่ 3 </strong>ใน dropdownlist ทั้งสองจะมี Key ที่ใช้ในการดึงข้อมูลออกมาจาก Session และ Cache เพื่อที่จะเลือกและผูกข้อมูลเข้ากับ DataGrid เพื่อแสดงผล เมื่อเลือก item ใน dropdownlist จะ postback กลับไปเพื่อดึงข้อมูลจาก session, cache ที่ต้องการ</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:48dd2467-9539-4180-b0ff-32b68a2c063b" class="wlWriterEditableSmartContent">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">Dropdown IndexChanged Code</div>
<div style="background:#fff;overflow:auto;">
<ol style="background:#ffffff;margin:0;padding:0 0 0 5px;">
<li><span style="color:#008000;">// Get Data From Session</span></li>
<li style="background:#f3f3f3;"><span style="color:#0000ff;">protected</span> <span style="color:#0000ff;">void</span> DropDownList1_SelectedIndexChanged(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li>{</li>
<li style="background:#f3f3f3;">    <span style="color:#2b91af;">List</span>&lt;<span style="color:#2b91af;">Order</span>&gt; orders = <span style="color:#0000ff;">null</span>;</li>
<li>    <span style="color:#2b91af;">List</span>&lt;<span style="color:#2b91af;">Customer</span>&gt; custs = <span style="color:#0000ff;">null</span>;</li>
<li style="background:#f3f3f3;">    <span style="color:#0000ff;">if</span> (!<span style="color:#0000ff;">string</span>.IsNullOrEmpty(DropDownList1.SelectedValue))</li>
<li>    {</li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">if</span> (DropDownList1.SelectedValue == <span style="color:#a31515;">&quot;AllCustomers&quot;</span>)</li>
<li>        {</li>
<li style="background:#f3f3f3;">            custs = Session[DropDownList1.SelectedValue] <span style="color:#0000ff;">as</span> <span style="color:#2b91af;">List</span>&lt;<span style="color:#2b91af;">Customer</span>&gt;;</li>
<li>            GridView1.DataSource = custs;</li>
<li style="background:#f3f3f3;">            GridView1.DataBind();</li>
<li>        }</li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">else</span> <span style="color:#0000ff;">if</span> (DropDownList1.SelectedValue == <span style="color:#a31515;">&quot;AllOrders&quot;</span>)</li>
<li>        {</li>
<li style="background:#f3f3f3;">            orders = Session[DropDownList1.SelectedValue] <span style="color:#0000ff;">as</span> <span style="color:#2b91af;">List</span>&lt;<span style="color:#2b91af;">Order</span>&gt;;</li>
<li>            GridView1.DataSource = orders;</li>
<li style="background:#f3f3f3;">            GridView1.DataBind();</li>
<li>        }</li>
<li style="background:#f3f3f3;">    }</li>
<li>}</li>
<li style="background:#f3f3f3;">&nbsp;</li>
<li><span style="color:#008000;">//Get Data From Cache</span></li>
<li style="background:#f3f3f3;"><span style="color:#0000ff;">protected</span> <span style="color:#0000ff;">void</span> DropDownList2_SelectedIndexChanged(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li>{</li>
<li style="background:#f3f3f3;">    <span style="color:#2b91af;">List</span>&lt;<span style="color:#2b91af;">Order</span>&gt; orders = <span style="color:#0000ff;">null</span>;</li>
<li>    <span style="color:#2b91af;">List</span>&lt;<span style="color:#2b91af;">Customer</span>&gt; custs = <span style="color:#0000ff;">null</span>;</li>
<li style="background:#f3f3f3;">    <span style="color:#0000ff;">if</span> (!<span style="color:#0000ff;">string</span>.IsNullOrEmpty(DropDownList2.SelectedValue))</li>
<li>    {</li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">if</span> (DropDownList2.SelectedValue == <span style="color:#a31515;">&quot;AllCustomers&quot;</span>)</li>
<li>        {</li>
<li style="background:#f3f3f3;">            custs = Cache.Get(DropDownList2.SelectedValue) <span style="color:#0000ff;">as</span> <span style="color:#2b91af;">List</span>&lt;<span style="color:#2b91af;">Customer</span>&gt;;</li>
<li>            GridView1.DataSource = custs;</li>
<li style="background:#f3f3f3;">            GridView1.DataBind();</li>
<li>        }</li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">else</span> <span style="color:#0000ff;">if</span> (DropDownList1.SelectedValue == <span style="color:#a31515;">&quot;AllOrders&quot;</span>)</li>
<li>        {</li>
<li style="background:#f3f3f3;">            orders = Cache.Get(DropDownList2.SelectedValue) <span style="color:#0000ff;">as</span> <span style="color:#2b91af;">List</span>&lt;<span style="color:#2b91af;">Order</span>&gt;;</li>
<li>            GridView1.DataSource = orders;</li>
<li style="background:#f3f3f3;">            GridView1.DataBind();</li>
<li>        }</li>
<li style="background:#f3f3f3;">    }</li>
<li>}</li>
</ol>
</div>
</div>
</div>
<p>line 8-18 เป็นการดึงค่าโดยใช้ key AllCustomers, AllOrders ไปดึงค่าที่เก็บอยู่ใน <strong>Session</strong> และผูกข้อมูลเข้ากับ Gridview เพื่อแสดงค่า</p>
<p>line 30-40 เป็นการดึงค่าโดยใช้ key AllCustomers, AllOrders ไปดึงค่าที่เก็บอยู่ใน <strong>Cache </strong>และผูกข้อมูลเข้ากับ Gridview เพื่อแสดงค่า</p>
<h4></h4>
<p>และสุุดท้ายก็จะเป็น web.config ที่เป็น ASP.NET4 ของเว็บนี้ครับ (โล่งๆ ไม่มีอะไรเลย)</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:67a94b5f-74d5-4f35-94c2-3aeddb95fd19" class="wlWriterEditableSmartContent">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">web.config</div>
<div style="background:#fff;overflow:auto;">
<ol style="background:#ffffff;margin:0;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">&lt;?</span><span style="color:#a31515;">xml</span><span style="color:#0000ff;"> </span><span style="color:#ff0000;">version</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">1.0</span>&quot;<span style="color:#0000ff;">?&gt;</span></li>
<li style="background:#f3f3f3;"><span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">configuration</span><span style="color:#0000ff;">&gt;</span></li>
<li>  <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">connectionStrings</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">    <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">add</span><span style="color:#0000ff;"> </span><span style="color:#ff0000;">name</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">NorthwindEntities</span>&quot;<span style="color:#0000ff;"> </span><span style="color:#ff0000;">connectionString</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">metadata=res://*/NorthwindDB.csdl|res://*/NorthwindDB.ssdl|</span></li>
<li>         <span style="color:#0000ff;">res://*/NorthwindDB.msl;provider=System.Data.SqlClient;provider connection string=</span><span style="color:#ff0000;">&amp;quot;</span></li>
<li style="background:#f3f3f3;">         <span style="color:#0000ff;">data source=.;initial catalog=Northwind;integrated security=True;multipleactiveresultsets=True;App=EntityFramework</span><span style="color:#ff0000;">&amp;quot;</span>&quot;<span style="color:#0000ff;"> </span></li>
<li>         <span style="color:#0000ff;"></span><span style="color:#ff0000;">providerName</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">System.Data.EntityClient</span>&quot;<span style="color:#0000ff;"> /&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">connectionStrings</span><span style="color:#0000ff;">&gt;</span></li>
<li>&nbsp;</li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">system.web</span><span style="color:#0000ff;">&gt;</span></li>
<li>    <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">compilation</span><span style="color:#0000ff;"> </span><span style="color:#ff0000;">debug</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">true</span>&quot;<span style="color:#0000ff;"> </span><span style="color:#ff0000;">targetFramework</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">4.0</span>&quot;<span style="color:#0000ff;"> /&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">system.web</span><span style="color:#0000ff;">&gt;</span></li>
<li>&nbsp;</li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">system.webServer</span><span style="color:#0000ff;">&gt;</span></li>
<li>     <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">modules</span><span style="color:#0000ff;"> </span><span style="color:#ff0000;">runAllManagedModulesForAllRequests</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">true</span>&quot;<span style="color:#0000ff;">/&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">system.webServer</span><span style="color:#0000ff;">&gt;</span></li>
<li><span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">configuration</span><span style="color:#0000ff;">&gt;</span></li>
</ol>
</div>
</div>
</div>
<h4>&#160;</h4>
<h4>Case Study : ตัวอย่างปัญหาจากตัวอย่างเว็บด้านบน (Problem of ASP.NET Session and Cache with InProc Mode)</h4>
<p>ในกรณีตัวอย่างนี้ ตัว web application วิเคราะห์และทดสอบการจำเป็นในการใช้ Session, Cache, OutputPage&#160; ในส่วนที่เหมาะสมของเว็บแล้ว แต่ว่ายังใช้หน่วยความจำของ Web Server ในการเก็บข้อมูลเหล่านั้นตรง ๆ ก็คือ Session = InProc Mode และ default Cache Provider ที่มีมาให้นั่นเอง</p>
<p>เมื่อเราพัฒนาเว็บแอ๊พพลิเคชั่นผ่านการทดสอบในส่วนของบิสซิเนสเรียบร้อยแล้ว ก็จะทำเทสในเรื่อง Load Test เพื่อหาค่าความสามารถในการรองรับ concurrent user ที่จะเข้ามาใช้งานระบบ ซึ่งในตัวอย่างได้สมมติเอาว่าผ่านการทำ load test มาแล้ว ซึ่งทั้งระบบ Web Server และ Database นั้น รองรับจำนวน user อยู่ที่ 200 concurrent โดยใช้งานปกติจะมีจำนวน concurrent ประมาณ 80-150 คน</p>
<p align="center"><a href="http://nine69.files.wordpress.com/2011/05/image2.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb2.png?w=302&#038;h=331" width="302" height="331" /></a></p>
<p>เมื่อถึงเวลาหนึ่งทางกิจการได้เติบโตขึ้น ทำให้จำนวนผู้เข้าใช้งานเว็บมีจำนวนมากขึ้นเป็นลำดับ ซึ่งอาจจะเป็นช่วงเวลาเช่นช่วงเที่ยง เย็น และวันหยุด พบว่าหลายครั้งที่ Web Server Down เพราะต้องบริการข้อมูลยูสเซอร์ที่เข้าใช้งานพร้อมกันจำนวน 300 user concurrents ซึ่งเกินจากที่ระบบจะรองรับได้ ดังภาพด้านล่าง</p>
<p align="center"><a href="http://nine69.files.wordpress.com/2011/05/image3.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb3.png?w=468&#038;h=353" width="468" height="353" /></a></p>
<p>ผลคือระบบล่ม ทุกอย่างจะเริ่มต้นได้ใหม่ก็จนกว่าจะ restart Web Site/Database กันใหม่ แบบนี้ทำให้ธุรกิจเสียหายแน่ ๆ ครับ</p>
<p><strong>ปัญหาและสาเหตุมีดังนี้</strong></p>
<p><strong>Client :</strong> เนื่อง user แต่ละคนจะต้องสร้าง session ขึ้นเป็นของตัวเอง และการกดเพื่อสร้าง request กลับไปที่ web server ทุกครั้ง และจำเป็นจะต้องเข้าเว็บเซอร์เวอร์เดิมทุกรีเควส หากเว็บเซอร์เวอร์ตัวนั้นล่มไป เซสชั่นทุกอย่างก็จะหายไปหมดเช่นกัน</p>
<p><strong>Web Server : </strong>มีการเก็บ Session, Cache แยกจากกันในแต่ละเว็บเซอร์เวอร์ ซึ่งไม่สามารถที่จะแชร์ข้ามเครื่องกันได้ ทำให้ข้อมูลบางตัวที่ควรจะแชร์กันได้ต้องถูกสร้างขึ้นใหม่ทุกครั้งที่มี user เข้ามาใช้งาน</p>
<p><strong>Database : </strong>มีการใช้งาน Disk อย่างหนัก เพราะทุก request ที่ส่งเข้ามาเกือบทั้งหมดจะต้องเข้าถึงข้อมูลตลอดเวลา</p>
<p>ก่อนที่เราจะเลือกทางแก้ปัญหาโดยการลงทุนเพิ่ม Web Server, Upgrade Database Server เหล่านั้น หากพิจารณากันให้ดี&#160; ปัญหาที่สำคัญก็คือ</p>
<p>1. เกิดข้อจำกัดของ Web Server ในส่วนของ Memory สำหรับเก็บข้อมูลพวก Session, Cache โดยแยกไปตามขนาดของ RAM ที่ติดตั้งในแต่ไว้ใน Server</p>
<p>2. เกิดข้อจำกัดของ User Process ในการทำงาน โดยจะทำงานได้เพียงบน Web Server ตัวเดียวเท่านั้น</p>
<p>3. มีการเข้าถึง Database ตลอดเวลาเพื่อดึงข้อมูลที่ซ้ำๆกันทุกครั้ง ที่ผู้ใช้ร้องขอบริการเดิม ๆ</p>
<p>4. Web Server ใน Farm ทุกตัวควรจะเห็น Session ของ User คนเดิม เมื่อเกิดปัญหากรณี Web Server ตัวใด ๆ ที่ User ใช้งานอยู่เกิดล่ม ก็สามารถที่จะยังทำงานต่อด้วย web server ตัวอื่นได้ทัทีโดยข้อมูลปัจจุบันยังคงอยู่</p>
<p>ซึ่งปัญหาเหล่านี้แก้ได้ครับ</p>
<p>&#160;</p>
<h4><strong>Solution : Implement Cache Server (AppFabric Caching)</strong></h4>
<p>จากตอนที่ 1 นั้นผมได้แนะนำตัว AppFabric Cache Service ไปแล้ว ซึ่งเราจะนำเข้ามาใช้แก้ไขปัญหาที่เกิดขึ้นข้างต้น โดยก่อนที่จะเข้าถึง Database เราก็วาง Cache Server เอาไว้ให้เป็นตัวบริการเก็บข้อมูลทั้ง Session, Cache ตามรูปดังนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/05/image4.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb4.png?w=600&#038;h=389" width="600" height="389" /></a></p>
<p>จากโมเดลด้านบนนี้ เราใช้ Cache Server มาวางโดยเอาไว้แก้ไขปัญหาของ Web Server ดังนี้</p>
<p>1. เพิ่มขนาดของ Cache บน Web Server&#160; โดยขนาดจะขึ้นอยู่กับหน่วยความจำของ Cache Server</p>
<p>2. เอาไว้เก็บ User Session แทนการเก็บบน Web Server ป้องกันปัญหากรณี web server ที่ user ใช้งานอยู่ขณะนั้นเกิดปัญหา ทำให้ Web Server อีกตัวสามารถทำงานแทน web server ตัวที่ล่มไปได้ทันที</p>
<p>3. เป็นข้อมูลที่ถูกเรีกยใช้บ่อย และข้อมูลนั้น อาจจะเป็น Static Data หรือมีการเปลี่ยนแปลงของข้อมูลน้อย&#160; ลดภาระของ Database ในการดึงข้อมูลส่งให้ Web Server บ่อย ๆ</p>
<p>ต่อไปเข้าสู่ขั้นตอนการสร้างและนำ AppFabric Cache ไปใช้ใน ASP.NET กันครับ</p>
<h4>&#160;</h4>
<h4>Create and Setting AppFabric Cache for ASP.NET Web Application</h4>
<p>ต่อไปเราจะทำการสร้างแคชดาต้าเบส และตั้งค่าเอาไว้ใช้งานกับ asp.net web application ของเราครับ</p>
<p>โดยจะสร้างแคชเอาไว้ 2 ตัวโดยให้ชือ่ว่า <span style="text-decoration:underline;"><em><strong>ASPNETSessionCache</strong></em></span> เอาไว้เก็บข้อมูลที่เป็นเซสชั่นและ <em><strong>ASPNETOutputCache</strong></em> เอาไว้เก็บข้อมูลแคช ทำตามขึ้นตอนดังนี้</p>
<p>1. เรียกหน้าต่าง Caching Administration Windows Powershell ออกมาใช้งาน</p>
<p>2. พิมพ์</p>
<blockquote>
<p><strong>Use-CacheCluster</strong></p>
</blockquote>
<p>3. สั่งสตาร์ท service ด้วยคำสั่ง</p>
<blockquote>
<p><strong>Start-CacheCluster</strong></p>
</blockquote>
<p>4. เพิ่ม user สำหรับเข้าใช้งานแคช ให้ Add Current user สำหรับ Debug</p>
<blockquote>
<p>เลือก 1 ชุดคำสั่งตาม windows ที่ใช้ครับ</p>
<p>- กรณีใช้ service account&#160; (all windows edition)</p>
<p><strong>Grant-CacheAllowedClientAccount –Account “ComputerName\UserName”</strong></p>
<p>- กรณีใช้ Network Server Account (win03, win03r2, win08, vista)</p>
<p><strong>grant-cacheallowedclientaccount -Account &quot;NETWORK SERVICE&quot;</strong></p>
<p>- ใช้ ASPNET User account ใน Windows 7/WS08R2:</p>
<p><strong>grant-cacheallowedclientaccount -Account &quot;IIS AppPool\ASP.NET v4.0&quot;</strong></p>
</blockquote>
<p>5. สร้างแคชสำหรับ asp.net ไว้เก็บเซสชั่นชื่อ ASPNETSessionCache และ ASPNETOutputCache</p>
<blockquote>
<p><strong>New-Cache –CacheName ASPNETSessionCache –Eviction None –TimeToLive 60</strong></p>
<p><strong>New-Cache –CacheName ASPNETOutputCache –Eviction None –TimeToLive 60</strong></p>
</blockquote>
<p>6. เรียกดู Cache DB ที่สร้างไว้ทั้งสองก้อนว่าสำเร็จหรือไม่ด้วยคำสั่ง</p>
<blockquote>
<p><strong>Get-Cache </strong></p>
</blockquote>
<p><a href="http://nine69.files.wordpress.com/2011/05/image5.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb5.png?w=600&#038;h=342" width="600" height="342" /></a></p>
<p>7. ตรวจสอบดูว่าแคชทั้ง 2 ว่าตั้งค่าไว้อย่างไรบ้าง</p>
<blockquote>
<p><strong>Get-CacheConfig ASPNETSessionCache</strong></p>
<p><strong>Get-CacheConfig ASPNETOutputCache</strong></p>
</blockquote>
<p><a href="http://nine69.files.wordpress.com/2011/05/image6.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb6.png?w=600&#038;h=352" width="600" height="352" /></a></p>
<p>7. ตรวจสอบค่า Staticstics ว่ามีสถานะปัจจุบันอย่างไรบ้าง</p>
<blockquote>
<p><strong>Get-CacheStatistics ASPNETSessionCache</strong></p>
<p><strong>Get-CacheStatistics ASPNETOutputCache</strong></p>
</blockquote>
<p><a href="http://nine69.files.wordpress.com/2011/05/image7.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb7.png?w=600&#038;h=304" width="600" height="304" /></a></p>
<h4></h4>
<p>แค่นี้ AppFabric Cache ก็พร้อมใช้งานแล้วครับ ต่อไปเราจะไปดูการตั้งค่าและเรียกใช้งานภายใน asp.net กัน</p>
<h4>&#160;</h4>
<h4>Using AppFabric Cache within ASP.NET Web Application</h4>
<p><a href="http://cid-dadd0b92d4b7b2a3.office.live.com/self.aspx/%E0%B8%AA%E0%B8%B2%E0%B8%98%E0%B8%B2%E0%B8%A3%E0%B8%93%E0%B8%B0/ASPNETSessionWithAppFabricCaching.zip" target="_blank"><strong>Download Code Sample Here</strong></a></p>
<p>ในขั้นตอนนี้เราจะย้าย Session และ Cache จากหน่วยความจำภายในเครื่องไปเก็บไว้ใน AppFabric Cache</p>
<p>การเรียกใช้ AppFabric Cache ภายใน Web Application นั้น ในตอนนี้ผมขอเลือกใช้ Library ตัวนึงซึ่งมีความสามารถเยอะกว่า Cache Client ที่ไมโครซอฟต์มีมาให้ตั้งแต่ติดตั้ง AppFabric</p>
<p><strong>การนำไปใช้งานนั้นมี 2 วิธีคือ ทำผ่าน web.config และ เขียนโค้ด</strong></p>
<p>ในขั้นตอนแรก&#160; ดาวน์โหลด <a href="http://aspnet.codeplex.com/releases/view/46576#DownloadId=138395" target="_blank">ASP.NET 4 Providers for AppFabric Caching</a> จาก CodePlex มาใช้งาน ให้ unzip ออกและมองหา <strong>“Microsoft.Web.DistributedCache.dll”</strong> โดยตัวนี้จะเป็น Custom Provider ที่เรียกใช้ Microsoft.ApplicationServer.Caching.Client.dll ของ AppFabric อีกทีนึง</p>
<h5>Setting Method 1: Edit web.config</h5>
<p>เปิด Web Application ขึ้นมาแก้ไข web.config ดังนี้</p>
<p>- เพิ่มค่า configSection สำหรับ Cache Client ของ Microsoft เพื่อให้รู้จัก dataCachcClient Section</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:69309a86-18e8-4423-9c5d-1f06bf1caa15" class="wlWriterEditableSmartContent">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">web.config: configSections</div>
<div style="background:#fff;overflow:auto;">
<ol style="background:#ffffff;margin:0;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">section</span><span style="color:#0000ff;"> </span><span style="color:#ff0000;">name</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">dataCacheClient</span>&quot;</li>
<li style="background:#f3f3f3;">    <span style="color:#0000ff;"></span><span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">Microsoft.ApplicationServer.Caching.DataCacheClientSection,</span></li>
<li>        <span style="color:#0000ff;">Microsoft.ApplicationServer.Caching.Core, Version=1.0.0.0, </span></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">Culture=neutral, PublicKeyToken=31bf3856ad364e35</span>&quot;</li>
<li>    <span style="color:#0000ff;"></span><span style="color:#ff0000;">allowLocation</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">true</span>&quot;</li>
<li style="background:#f3f3f3;">    <span style="color:#0000ff;"></span><span style="color:#ff0000;">allowDefinition</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">Everywhere</span>&quot;<span style="color:#0000ff;">/&gt;</span></li>
</ol>
</div>
</div>
</div>
<p>- เพิ่ม dataCacheClient Section เพื่อกำหนดที่อยู่ของ AppFabric Host และ Port</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:0ee1e451-ac3c-48f6-8dae-f2fd4e97862b" class="wlWriterEditableSmartContent">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">web.config: dataCacheClient</div>
<div style="background:#fff;max-height:500px;overflow:auto;">
<ol style="background:#ffffff;margin:0;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">dataCacheClient</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">hosts</span><span style="color:#0000ff;">&gt;</span></li>
<li>    <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">host</span><span style="color:#0000ff;"> </span><span style="color:#ff0000;">name</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">Nine-NB</span>&quot;<span style="color:#0000ff;"> </span><span style="color:#ff0000;">cachePort</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">22233</span>&quot;<span style="color:#0000ff;"> /&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">hosts</span><span style="color:#0000ff;">&gt;</span></li>
<li><span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">dataCacheClient</span><span style="color:#0000ff;">&gt;</span></li>
</ol>
</div>
</div>
</div>
<p>- ตั้งค่าการใช้ Cache ของ ASP.NET ไปที่ AppFabric โดยกำหนดเพิ่มเติมใน &lt;system.web&gt;</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:9aeb9e7d-787f-4b8e-80c5-120a7d4c8690" class="wlWriterEditableSmartContent">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">web.config: &lt;sessionState&gt;</div>
<div style="background:#fff;overflow:auto;">
<ol style="background:#ffffff;margin:0;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">sessionState</span><span style="color:#0000ff;"> </span><span style="color:#ff0000;">mode</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">Custom</span>&quot;<span style="color:#0000ff;"> </span><span style="color:#ff0000;">customProvider</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">DistributedSessionAspSessionProvider</span>&quot;<span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">providers</span><span style="color:#0000ff;">&gt;</span></li>
<li>    <span style="color:#0000ff;">&lt;!&#8211;</span><span style="color:#008000;"> specify the named cache for session data </span><span style="color:#0000ff;">&#8211;&gt;</span></li>
<li style="background:#f3f3f3;">    <span style="color:#0000ff;">&lt;!&#8211;</span><span style="color:#008000;">&lt;add name=&quot;AppFabricCacheSessionStoreProvider&quot;</span></li>
<li>      <span style="color:#008000;">type=&quot;Microsoft.ApplicationServer.Caching.DataCacheSessionStoreProvider&quot;</span></li>
<li style="background:#f3f3f3;">      <span style="color:#008000;">cacheName=&quot;ASPNETSession&quot;</span></li>
<li>      <span style="color:#008000;">sharedId=&quot;ASPNETSession&quot;/&gt;</span><span style="color:#0000ff;">&#8211;&gt;</span></li>
<li style="background:#f3f3f3;">    <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">add</span><span style="color:#0000ff;"> </span><span style="color:#ff0000;">name</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">DistributedSessionAspSessionProvider</span>&quot;</li>
<li>         <span style="color:#0000ff;"></span><span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">Microsoft.Web.DistributedCache.DistributedCacheSessionStateStoreProvider, </span></li>
<li style="background:#f3f3f3;">         <span style="color:#0000ff;">Microsoft.Web.DistributedCache</span>&quot;</li>
<li>        <span style="color:#0000ff;"></span><span style="color:#ff0000;">cacheName</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">ASPNETSessionCache</span>&quot;</li>
<li style="background:#f3f3f3;">          <span style="color:#0000ff;"></span><span style="color:#ff0000;">applicationName</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">ASPNETWeb</span>&quot;</li>
<li>          <span style="color:#0000ff;"></span><span style="color:#ff0000;">useBlobMode</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">false</span>&quot;<span style="color:#0000ff;"> /&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">providers</span><span style="color:#0000ff;">&gt;</span></li>
<li><span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">sessionState</span><span style="color:#0000ff;">&gt;</span></li>
</ol>
</div>
</div>
</div>
<p>line 8&#160; ตั้งค่าชื่อของ provider ที่เราต้องการจะเพิ่มเติม</p>
<p>line 9 กำหนด type ของ dll ที่เรานำมาใช้</p>
<p>line11-13&#160; เป็นการะบุ Cache โดยอ้างถึง ASPNETSession ที่สร้างไว้ใน AppFabric Cache, กำหนด ApplicationName ที่จะเข้าใช้แคชก้อนดังกล่าว และระบุไม่ใช่ Blob Mode</p>
<p>line – 1 กำหนด mode=”Custom” และเลือกใช้ customProivder=”DistributedSessionAspSessionProvider” ตามที่ได้ตั้งค่าไว้</p>
<p>- ตั้งค่าการใช้ Page Output Cache ของ ASP.NET ไปที่ AppFabric โดยกำหนดเพิ่มเติมใน &lt;system.web&gt;</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:b3c7d03f-e284-446e-8f3b-5c328f8602d8" class="wlWriterEditableSmartContent">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">web.config: &lt;caching&gt;</div>
<div style="background:#fff;overflow:auto;">
<ol style="background:#ffffff;margin:0;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">caching</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">outputCache</span><span style="color:#0000ff;"> </span><span style="color:#ff0000;">defaultProvider</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">DistributedCache</span>&quot;<span style="color:#0000ff;">&gt;</span></li>
<li>    <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">providers</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">      <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">add</span><span style="color:#0000ff;"> </span><span style="color:#ff0000;">name</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">DistributedCache</span>&quot;<span style="color:#0000ff;"> </span></li>
<li>           <span style="color:#0000ff;"></span><span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider, </span></li>
<li style="background:#f3f3f3;">           <span style="color:#0000ff;">Microsoft.Web.DistributedCache</span>&quot;<span style="color:#0000ff;"> </span><span style="color:#ff0000;">cacheName</span><span style="color:#0000ff;">=</span>&quot;<span style="color:#0000ff;">ASPNETOutputCache</span>&quot;<span style="color:#0000ff;"> </span><span style="color:#ff0000;">applicationName</span><span style="color:#0000ff;"> =</span>&quot;<span style="color:#0000ff;">ASPNETWeb</span>&quot;<span style="color:#0000ff;"> /&gt;</span></li>
<li>    <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">providers</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">outputCache</span><span style="color:#0000ff;">&gt;</span></li>
<li><span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">caching</span><span style="color:#0000ff;">&gt;</span></li>
</ol>
</div>
</div>
</div>
<p>line 4 กำหนดชื่อของ Cache ที่เราใช้อ้างอิง</p>
<p>line 5 ใส่ type ของ dll ที่จะใช้ในการทำ page output cache</p>
<p>line 6 cacheName กำหนดให้ใช้แคชที่ชื่อ ASPNEToutputCache และกำหนดชื่อ applicationName เป็น ASPNETWeb</p>
<p>line 1 ที่ defaultProvider กำหนดให้ใช้ DistributedCache name ที่เราได้สร้างไว้</p>
<h5>Setting Method 2: Cache with Programmatically</h5>
<p>เพิ่มโค้ดใน Global.asax.cs ดังนี้</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:52d2cec0-ef33-4e70-85fe-22181dab98c8" class="wlWriterEditableSmartContent">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">Code Snippet</div>
<div style="background:#fff;overflow:auto;">
<ol style="background:#ffffff;margin:0;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">void</span> Application_Start(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">{</li>
<li>    <span style="color:#2b91af;">DistributedCacheSessionStateStoreProvider</span>.CacheConnecting += DistributedCacheSessionStateStoreProvider_CacheConnecting;</li>
<li style="background:#f3f3f3;">    <span style="color:#2b91af;">DistributedCacheOutputCacheProvider</span>.CacheConnecting += DistributedCacheOutputCacheProvider_CacheConnecting;</li>
<li>}</li>
<li style="background:#f3f3f3;">&nbsp;</li>
<li><span style="color:#0000ff;">void</span> DistributedCacheOutputCacheProvider_CacheConnecting(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">CacheConnectingEventArgs</span> e)</li>
<li style="background:#f3f3f3;">{</li>
<li>    e.CacheFactoryConfiguration = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">DataCacheFactoryConfiguration</span>()</li>
<li style="background:#f3f3f3;">            {</li>
<li>                Servers = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">DataCacheServerEndpoint</span>[] {<span style="color:#0000ff;">new</span> <span style="color:#2b91af;">DataCacheServerEndpoint</span>(<span style="color:#a31515;">&quot;Nine-NB&quot;</span>, 22233)}</li>
<li style="background:#f3f3f3;">            };</li>
<li>    e.CacheName = <span style="color:#a31515;">&quot;ASPNETOutputCache&quot;</span>;</li>
<li style="background:#f3f3f3;">}</li>
<li>&nbsp;</li>
<li style="background:#f3f3f3;"><span style="color:#0000ff;">void</span> DistributedCacheSessionStateStoreProvider_CacheConnecting(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">CacheConnectingEventArgs</span> e)</li>
<li>{</li>
<li style="background:#f3f3f3;">    e.CacheFactoryConfiguration = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">DataCacheFactoryConfiguration</span>()</li>
<li>        {</li>
<li style="background:#f3f3f3;">            Servers = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">DataCacheServerEndpoint</span>[] { <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">DataCacheServerEndpoint</span>(<span style="color:#a31515;">&quot;Nine-NB&quot;</span>, 22233) }</li>
<li>        };</li>
<li style="background:#f3f3f3;">    e.CacheName = <span style="color:#a31515;">&quot;ASPNETSessionCache&quot;</span>;</li>
<li>}</li>
</ol>
</div>
</div>
</div>
<p>line 3-4 ทำการผูก event ให้ CacheSession และ OutputCache Provider เมื่อมีการร้องขอให้ทำการ connect ไปยัง Cache Server ก็ให้ไปทำ event Connecting ทั้งสอง</p>
<p>line 7-14 เป็น event ของ Output Cache โดยทำการ add host, port number และกำหนดชื่อของ Cache Name ที่จะใช้</p>
<p>line 16-23 เป็น event ของ Cache Session โดยทำการ add host, port number และกำหนดชื่อของ Cache Name ที่จะใช้</p>
<h4>&#160;</h4>
<h4>Test Run ASP.NET Web Application and Monitoring Cache</h4>
<p>เริ่มแรกให้ทำการตรวจสอบว่า Cache ของ ASPNETSessionCache และ ASPNETOutputCache นั้นยังมีสถานะก่อนใช้งานเป็นดังนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/05/image8.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb8.png?w=593&#038;h=296" width="593" height="296" /></a></p>
<p>ยังไม่มีการเก็บข้อมูลใด ๆ ลงใน Cache ทั้งสองก้อน&#160;&#160;&#160; จากนั้นเราจะทำการ Run Web Site ด้วย Visual Studio 2010 ด้วยการกด F5 ได้ผลขึ้นดังนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/05/image9.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb9.png?w=600&#038;h=357" width="600" height="357" /></a></p>
<p>เนื่องจากมี page output cache เกิดขึ้น ดงันั้นเราจะไปตรวจสอบที่ ASPNETOutputCache จะพบได้ว่ามีการเก็บ object ลงไปใน Cache เพิ่มดังนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/05/image10.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb10.png?w=600&#038;h=300" width="600" height="300" /></a></p>
<p>ที่เห็นนี้จะเป็น Automatic Cache และ Session สำหรับ System ในการทำงานของ ASP.NET Web Application ซึ่งจะเกิดขึ้นทุกครั้งที่ User เข้ามาทำงานในหน้า Default.aspx</p>
<p>ต่อไปเราจะทำการ เก็บค่าลง Session และ Cache ด้วยการกด button ในหัวข้อที่ 2 <strong>Load Data</strong></p>
<p>เมื่อ response กลับมา ลองไปคลิ๊กที่ downdown ทั้งสองจะพบว่ามี key ของทั้ง Session และ Cache ที่เราเก็บค่าไว้ใน AppFabric Caching นั่นเอง</p>
<p>ทีนี้เรากลับไปดูความเปลี่ยนแปลงที่เกิดขึ้นใน Cache ทั้งสองตัวกันครับ</p>
<p><a href="http://nine69.files.wordpress.com/2011/05/image11.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/05/image_thumb11.png?w=600&#038;h=300" width="600" height="300" /></a></p>
<p>ก็จะพบว่ามีจำนวนของ Item ที่เก็บเพิ่มขึ้นอันเนื่องมาจากการเก็บข้อมูลลงไปนั่นเอง</p>
<h4></h4>
<h4>&#160;</h4>
<h4>Conclusion</h4>
<p>หวังว่าพอจะมองเห็นประโยชน์จากดีไซน์นี้ หากต้องการที่จะ scale ระบบ web server ให้ทำงานได้สมบูรณ์และมีประสิทธิภาพสูงสุดนั้น บทความนี้ก็เป็นอีกหนึ่งแนวทางในการนำไปสู่ผลสำเร็จนั้นครับ</p>
<p>ในตอนต่อไป ผมจะพูดถึงการนำ AppFabric Caching ไปใช้ใน MVC, EF, NHibernate เท่าที่จะพอนึกออกครับ และหากมีโอกาสผมจะทำการทดสอบในส่วนของการทำ Cache Cluster, Fault Torrelance Testing, Performance Tesing ต่อไปด้วยครับ</p>
<hr />
<p><a href="http://cid-dadd0b92d4b7b2a3.office.live.com/self.aspx/%E0%B8%AA%E0%B8%B2%E0%B8%98%E0%B8%B2%E0%B8%A3%E0%B8%93%E0%B8%B0/ASPNETSessionWithAppFabricCaching.zip" target="_blank"><strong>Download Code Sample Here</strong></a></p>
<blockquote>
<p><a href="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png"><img border="0" alt="" src="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png?w=143" /></a></p>
</blockquote>
<blockquote>
<p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Chalermpon Areepong Nine (นาย)</a></p>
<p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Microsoft MVP Thailand ASP.NET</a></p>
<p>email : nine_biz-talk.net <strong>at</strong> hotmail <strong>dot</strong> com</p>
</blockquote>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nine69.wordpress.com/299/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nine69.wordpress.com/299/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nine69.wordpress.com/299/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nine69.wordpress.com/299/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nine69.wordpress.com/299/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nine69.wordpress.com/299/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nine69.wordpress.com/299/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nine69.wordpress.com/299/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nine69.wordpress.com/299/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nine69.wordpress.com/299/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nine69.wordpress.com/299/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nine69.wordpress.com/299/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nine69.wordpress.com/299/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nine69.wordpress.com/299/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=299&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nine69.wordpress.com/2011/05/16/asp-net-4-0-high-scalable-asp-net-session-and-cache-with-windows-server-appfabric-caching-vol-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/8c2f25a91e95ddd2e418090794711d24?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">nine69</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb1.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb2.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb3.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb4.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb5.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb6.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb7.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb8.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb9.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb10.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/05/image_thumb11.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png?w=143" medium="image" />
	</item>
		<item>
		<title>The SSO service failed to start. After installing .NET Framework v4</title>
		<link>http://nine69.wordpress.com/2011/04/21/the-sso-service-failed-to-start-after-installing-net-framework-v4/</link>
		<comments>http://nine69.wordpress.com/2011/04/21/the-sso-service-failed-to-start-after-installing-net-framework-v4/#comments</comments>
		<pubDate>Thu, 21 Apr 2011 08:19:04 +0000</pubDate>
		<dc:creator>Nine MVP ASP.NET</dc:creator>
				<category><![CDATA[BizTalk]]></category>
		<category><![CDATA[.net framework v4]]></category>
		<category><![CDATA[SSO]]></category>

		<guid isPermaLink="false">http://nine69.wordpress.com/?p=276</guid>
		<description><![CDATA[ให้มันได้อย่างนี้ ไม่มีไผบอกก่อนว่าลง .net fx v4 แล้วเดี้ยง งมหาไปเหอะ เพราะอิตา SSO นี่ไม่ได้ระบุเจาะจง .net fx ที่จะใช้รัน พอลง v4 เพิ่มเข้าไปเดี้ยงเลย เลือกไม่ถูกหลายใจจริง ๆ แก้ไขปัญหาด้วย ลง patch ตัวนี้ Update for Microsoft Enterprise Single Sign-On v4 (KB2252691)<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=276&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>ให้มันได้อย่างนี้ ไม่มีไผบอกก่อนว่าลง .net fx v4 แล้วเดี้ยง งมหาไปเหอะ<br />
เพราะอิตา SSO นี่ไม่ได้ระบุเจาะจง .net fx ที่จะใช้รัน พอลง v4 เพิ่มเข้าไปเดี้ยงเลย เลือกไม่ถูกหลายใจจริง ๆ</p>
<p>แก้ไขปัญหาด้วย ลง patch ตัวนี้<br />
<span class="Apple-style-span" style="font-size:20px;"><a title="Update for Microsoft Enterprise Single Sign-On v4 (KB2252691)" href="http://www.microsoft.com/downloads/en/details.aspx?displaylang=en&amp;FamilyID=46fa6c65-531a-4c9f-99f9-7af3fac098a6" target="_blank">Update for Microsoft Enterprise Single Sign-On v4 (KB2252691)</a></span></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nine69.wordpress.com/276/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nine69.wordpress.com/276/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nine69.wordpress.com/276/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nine69.wordpress.com/276/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nine69.wordpress.com/276/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nine69.wordpress.com/276/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nine69.wordpress.com/276/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nine69.wordpress.com/276/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nine69.wordpress.com/276/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nine69.wordpress.com/276/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nine69.wordpress.com/276/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nine69.wordpress.com/276/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nine69.wordpress.com/276/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nine69.wordpress.com/276/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=276&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nine69.wordpress.com/2011/04/21/the-sso-service-failed-to-start-after-installing-net-framework-v4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/8c2f25a91e95ddd2e418090794711d24?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">nine69</media:title>
		</media:content>
	</item>
		<item>
		<title>Add a Reference to the Microsoft.ApplicationServer.Caching.Client Assembly</title>
		<link>http://nine69.wordpress.com/2011/04/20/add-ref-appfabric-caching-client-assembly/</link>
		<comments>http://nine69.wordpress.com/2011/04/20/add-ref-appfabric-caching-client-assembly/#comments</comments>
		<pubDate>Tue, 19 Apr 2011 18:02:30 +0000</pubDate>
		<dc:creator>Nine MVP ASP.NET</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Core System]]></category>

		<guid isPermaLink="false">http://nine69.wordpress.com/?p=277</guid>
		<description><![CDATA[ขอ 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 [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=277&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h1><span class="Apple-style-span" style="font-size:13px;font-weight:normal;">ขอ copy มาแปะไว้ ref กันลืมแหะๆ </span></h1>
<h1><span class="Apple-style-span" style="font-size:13px;font-weight:normal;">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.</span></h1>
<div>
<div>
<h2><strong>To add a reference to Microsoft.ApplicationServer.Caching.Client</strong></h2>
<ol>
<li>Right-click your project and select <strong>Add Reference</strong>.</li>
<li>Click the <strong>Browse </strong>tab.</li>
<li>Enter the following in the file name and then click <strong>Enter</strong>.
<ul>
<li><strong>64bit Windows: %windir%\Sysnative\AppFabric</strong></li>
<li><strong>32bit Windows: %windir%\System32\AppFabric</strong></li>
</ul>
</li>
<li>Locate and select both <strong>Microsoft.ApplicationServer.Caching.Client</strong> and <strong>Microsoft.ApplicationServer.Caching.Core</strong></li>
</ol>
</div>
<div>For more information see the official documentation in <a href="http://msdn.microsoft.com/en-us/library/ee790876.aspx">Preparing the Development Environment for Cache Client Development</a></div>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nine69.wordpress.com/277/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nine69.wordpress.com/277/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nine69.wordpress.com/277/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nine69.wordpress.com/277/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nine69.wordpress.com/277/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nine69.wordpress.com/277/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nine69.wordpress.com/277/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nine69.wordpress.com/277/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nine69.wordpress.com/277/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nine69.wordpress.com/277/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nine69.wordpress.com/277/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nine69.wordpress.com/277/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nine69.wordpress.com/277/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nine69.wordpress.com/277/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=277&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nine69.wordpress.com/2011/04/20/add-ref-appfabric-caching-client-assembly/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/8c2f25a91e95ddd2e418090794711d24?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">nine69</media:title>
		</media:content>
	</item>
		<item>
		<title>ASP.NET 4.0 : High Scalable ASP.NET Session and Cache with Windows Server AppFabric Caching vol.1</title>
		<link>http://nine69.wordpress.com/2011/04/17/asp-net-4-0-high-scalable-asp-net-session-state-with-windows-server-appfabric-cache-vol-1/</link>
		<comments>http://nine69.wordpress.com/2011/04/17/asp-net-4-0-high-scalable-asp-net-session-state-with-windows-server-appfabric-cache-vol-1/#comments</comments>
		<pubDate>Sat, 16 Apr 2011 18:10:00 +0000</pubDate>
		<dc:creator>Nine MVP ASP.NET</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Core System]]></category>
		<category><![CDATA[AppFabric Caching]]></category>

		<guid isPermaLink="false">https://nine69.wordpress.com/2011/04/17/asp-net-4-0-scalable-asp-net-session-state-with-windows-server-appfabric-cache-vol-1/</guid>
		<description><![CDATA[Part 1 Part 2 Programming Level: Intermediate Computer Skills: ASP.NET 4.0 Development Tool and Library OS: Windows 7 or Windows Server 2008 R2 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 [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=268&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h5></h5>
<h5></h5>
<h5></h5>
<h5>Part 1</h5>
<h5>Part 2</h5>
<h4>Programming Level:</h4>
<ul>
<li>Intermediate</li>
</ul>
<h4>Computer Skills:</h4>
<ol>
<li>ASP.NET 4.0</li>
</ol>
<h4>Development Tool and Library</h4>
<ol>
<li>OS: Windows 7 or Windows Server 2008 R2</li>
<li>Windows Server AppFabric Caching (download <a href="http://www.microsoft.com/downloads/info.aspx?na=46&amp;SrcFamilyId=467E5AA5-C25B-4C80-A6D2-9F8FB0F337D2&amp;SrcDisplayLang=en&amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f1%2fA%2fD%2f1ADC8F3E-4446-4D31-9B2B-9B4578934A22%2fWindowsServerAppFabricSetup_x86_6.1.exe" target="_blank"><strong>for x86</strong></a>, <a href="http://www.microsoft.com/downloads/info.aspx?na=46&amp;SrcFamilyId=467E5AA5-C25B-4C80-A6D2-9F8FB0F337D2&amp;SrcDisplayLang=en&amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f1%2fA%2fD%2f1ADC8F3E-4446-4D31-9B2B-9B4578934A22%2fWindowsServerAppFabricSetup_x64_6.1.exe" target="_blank"><strong>for x64</strong></a>)</li>
</ol>
<h4>Agenda</h4>
<ul>
<li>Introduce</li>
<li>ASP.NET Session Problem</li>
<li>ASP.NET Session Mode</li>
<li>Solution for Large Session State Problem</li>
<li>Advantages of AppFabric Caching</li>
<li>AppFabric Caching Architecture</li>
<li>Install And Config Windows Server AppFabric Caching (Non-Cluster)</li>
<li>Using Caching Administration Windows PowerShell</li>
<li>Summary</li>
</ul>
<h4>Introduce</h4>
<p>หลายๆครั้งที่มีการถามถึงประสิทธิภาพการทำงานของ ASP.NET ในเรื่องการความเร็วตั้งแต่กด Request เข้าไปยัง Server จนกระทั้ง Response ข้อมูลออกมายัง Browser ของผู้ใช้งาน     ซึ่งมีหลายปัจจัยทีเดียวที่จะต้องออกแบบและปรัปปรุงขั้นตอนการทำงานเพื่อให้ตอบสนองผู้ใช้ได้อย่างรวดเร็วไม่ว่าจะเป็นในส่วนของการ Tuning Database เพิ่มความเร็วในการ Query Data, การใช้ paging query, เขียน code logic ให้มีประสิทธิภาพ, ออกแบบหน้า html, image ให้มีสัดส่วนที่เหมาะสม ขนาดเล็ก, การบีบอัดข้อมูลจาก Web Server ไปยัง browser ของผู้ใช้  รวมไปถึงการทำ Network Load Balance(NLB) เป็นต้น</p>
<p>ซึ่งวิธีการเหล่านี้ก็เป็นส่วนสำคัญในการสร้างระบบที่มีการทำงานที่รวดเร็วโดยทั้งหมด  แต่ปัจจัยที่สำคัญมากอีกตัวก็คือหน่วยความจำสำหรับระบบนั้นเอง โดยส่วนใหญ่มักจะมีปัญหาในการใช้งานเมื่อจำนวนยูสเซอร์มีจำนวนมากขึ้น โดยระบบหน่วยความจำที่สำคัญนั้นคือการใช้ Session, Internal Cache แม้จะมีหลายท่านพยายามหนีการใช้เซสชั่นแต่มั่นใจได้ครับ ไม่ทุกระบบที่จะหลีกเลี่ยงได้ หากเจอข้อจำกัดในการ load data และเงื่อนไขที่รัดตัว</p>
<h4>ASP.NET Session Problem</h4>
<p>สำหรับงานเว็บของ ASP.NET นั้น หลายๆระบบต่างไม่ได้ให้ความสำคัญในการกำหนด physical memory สำหรับใช้เก็บเซสชั่น โดยส่วนใหญ่จะใช้ค่า default ที่ Visual Studio สร้าง web.config มาให้ หากคุณใช้เครื่อง Web Server ที่มีเสป็คสูงก็อาจจะไม่ต้องกังวล เช่น มี RAM 8-16 GB เป็นต้น  แต่หาก web server ต้องติดตั้ง web app มากกว่า 1 ระบบแล้วนั้น มีโอกาสที่จะทำให้เกิดปัญหาเรื่องหน่วยความจำไม่พอ ซึ่งเอกชนส่วนใหญ่จะใช้การติดตั้งลักษณะนี้เนื่องจากประหยัดค่าใช้จ่าย</p>
<p>ในการทำงานบ่อยครั้งก็มีความจำเป็นในการโหลดข้อมูลจาก Database เข้ามาเก็บในเซสชั่น หลายๆครั้งนั้นมีความจำเป็นที่เลี่ยงไม่ได้ที่จะต้องโหลดข้อมูลจำนวนมาก ๆ เข้ามาเก็บไว้ เช่น Global Data สำหรับแชร์ให้ทุกเซสชั่น, ข้อมูลเพื่อรองรับการทำงานของยูสเซอร์กำลังใช้งานเว็บ เมื่อจำนวนยูสเซอร์มีการเข้าใช้งานในประมาณที่มากขึ้นจึงทำให้ IIS process มีขนาดใหญ่บางท่านอาจจะเจอว่ากิน ram ไปขนาด 4 GB. ทำให้ต้องมีการ upgrade web server อาจจะต้องเพิ่ม RAM หรือเพิ่ม server เป็นต้น</p>
<h4>ASP.NET Session Model</h4>
<p>เพื่อความเข้าใจในการแก้ปัญหาและพัฒนา ผมขออธิบายเกี่ยวกับ Session Mode ของ ASP.NET ที่มีอยู่ 5 Mode กันก่อนครับ</p>
<p><strong>1. InProc mode</strong> เป็นโหมดที่ทำงานโดยเก็บข้อมูลไว้ใน RAM ของ Web Server ซึ่งเป็นโหมดพื้นฐานที่ตั้งค่ามาให้ใช้งาน</p>
<p><strong>ข้อดี </strong>ง่ายและเป็นโหมดที่ทำงานได้เร็วทีสุด</p>
<p><strong>ข้อเสีย </strong>แต่มีข้อจำกัดในการรองรับจำนวนข้อมูลและการแชร์ session ใน Farm และเมื่อ web server restart ทุกอย่างที่เก็บไว้ก็จะหายไปทันที</p>
<p><strong>2. StateServer (OutProc) mode</strong> เป็นโหมดที่ทำงานโดยแยก Service ที่เป็นส่วนเสริมของ ASP.NET เองออกไปจาก IIS process ซึ่งมีชื่อว่า ASP.NET state service โดยจะมีติดตั้งให้ทันทีที่ลง .NET Framework ซึ่งจะอยู่ที่ <span style="text-decoration:underline;">“systemroot\Microsoft.NET\Framework\versionNumber\aspnet_state.exe”</span></p>
<p><strong>ข้อดี </strong>ด้วยตัว state server นี้แม้หากว่า web server เกิด restart ตัวเองขึ้นมาคุณก็แน่ใจได้ว่าเซสชั่นนั้นยังคงถูกเก็บไว้อยู่แน่นอน ซึ่งเหมาะที่จะใช้สำหรับ Web Server ใน Farm และมีความเร็วในการทำงานเป็นลำดับรองจาก InProc Mode อยู่ 1 เท่าตัว</p>
<p><strong>ข้อเสีย </strong>คือกิน RAM เหมือน InProc เพราะเก็บไว้ใน RAM เหมือนกับ InProc mode เพียงแต่แยก service ออกมาต่างหาก แปลว่าคุณควรจะมีเครื่องแยกออกมาและมีช่องเสียบ RAM เยอะๆ และเสียบ RAM ไว้เพื่อรองรับงานดังกล่าว แต่เมื่อ StateServer restart ทุกเซสชั่นก็จะหายไปหมดเช่นกัน</p>
<p>ตัวอย่าง web.config</p>
<blockquote>
<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:7d8cfc74-7dfb-441e-8f79-3b33fea41803" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background-color:#ffffff;overflow:auto;padding:2px 5px;"><span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">configuration</span><span style="color:#0000ff;">&gt;</span><br />
<span style="color:#0000ff;">  &lt;</span><span style="color:#a31515;">system.web</span><span style="color:#0000ff;">&gt;</span><br />
<span style="color:#0000ff;">    &lt;</span><span style="color:#a31515;">sessionState</span><span style="color:#ff0000;">mode</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">StateServer</span>&#8220;<span style="color:#ff0000;">stateConnectionString</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">tcpip=SampleStateServer:42424</span>&#8220;<br />
<span style="color:#0000ff;">                  </span><span style="color:#ff0000;">cookieless</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">false</span>&#8220;<span style="color:#ff0000;">timeout</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">20</span>&#8220;<span style="color:#0000ff;">/&gt;</span><br />
<span style="color:#0000ff;">  &lt;/</span><span style="color:#a31515;">system.web</span><span style="color:#0000ff;">&gt;</span><br />
<span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">configuration</span><span style="color:#0000ff;">&gt;</span></div>
</div>
</div>
</blockquote>
<p><strong>3. SQLServer mode </strong>เป็นโหมดที่เก็บเซสชั่นไว้ใน Database</p>
<p><strong>ข้อดี </strong>คุณสมบัติเหมือนกับ StateServer mode ทุกอย่าง และถึงแม้ว่า SqlServer จะ restart ข้อมูลเซสชั่นก็ยังคงถูกเก็บเอาไว้ใน Database ไม่หายไป และดีกว่าที่ว่าสามารถขยายความจุของเซสชั่นได้เท่ากับพื้นที่บน HDD ที่มีอยู่ เหมาะที่ใช้กับ Web Server ใน Farm</p>
<p><strong>ข้อเสีย</strong>ที่ว่า ช้ากว่า InProc mode ประมาณ 3 เท่าตัว</p>
<p>ตัวอย่าง web.config</p>
<blockquote>
<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:619ff858-5362-424e-baf5-bb8905d57e20" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background-color:#ffffff;overflow:auto;padding:2px 5px;"><span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">configuration</span><span style="color:#0000ff;">&gt;</span><br />
<span style="color:#0000ff;">  &lt;</span><span style="color:#a31515;">system.web</span><span style="color:#0000ff;">&gt;</span><br />
<span style="color:#0000ff;">    &lt;</span><span style="color:#a31515;">sessionState</span><span style="color:#ff0000;">mode</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">SQLServer</span>&#8220;<span style="color:#ff0000;">sqlConnectionString</span><span style="color:#0000ff;">=</span><br />
<span style="color:#0000ff;">                  </span>&#8220;<span style="color:#0000ff;">Integrated Security=SSPI;data source=SampleSqlServer;</span>&#8220;<span style="color:#0000ff;"> /&gt;</span><br />
<span style="color:#0000ff;">  &lt;/</span><span style="color:#a31515;">system.web</span><span style="color:#0000ff;">&gt;</span><br />
<span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">configuration</span><span style="color:#0000ff;">&gt;</span></div>
</div>
</div>
</blockquote>
<p>*** หากต้องการจะใช้งาน SqlServer Mode คุณต้องทำการ register database ด้วย <a title="aspnet_regsql.exe" href="http://msdn.microsoft.com/en-us/library/ms229862.aspx" target="_blank">aspnet_regsql.exe</a> ตัวนี้ก่อน</p>
<p><strong>4. Custom mode </strong>หาตัวอื่นมาใช้ทดแทนทั้ง 3 mode ที่กล่าวไปข้างต้น โดยอาจจะเก็บไว้ใน Disk, NoSql เป็นต้น ซึ่งเราจะมาพูดคุยและทดสอบใช้งานกันในตอนนี้</p>
<p><strong>5. Off mode </strong>ไม่ใช้ Session (ฟังดูจะโหดร้ายไปหน่อย)</p>
<h4>Solution for Large Session State Problem</h4>
<p>แนวทางการการแก้ไขปัญหาเรื่อง RAM บน Web Server ไม่พอเพียงนั้น ก็มีแนวทางที่เป็น best practice ให้เห็นกันอยู่แล้วนะครับก็คือ</p>
<p><strong>1. เลือกใช้ SQLServer Mode</strong>  โดยตัวอย่างก็มีเช่น SharePoint, MS CRM  ก็ถูกพัฒนา base on ASP.NET เช่นกัน ซึ่งได้เลือกที่จะแก้ปัญหานี้ด้วยการใช้ SQLServer Mode เป็นตัวเก็บ Session ซึ่งก็จะหมดปัญหาในเรื่อง web app ที่ต้องใช้หน่วยความจำขนาดใหญ่อีกต่อไป อาจจะทำงานช้าลงบ้างแต่ก็คุ้ม</p>
<p><strong>2. เลือกใช้ Custom Mode</strong> อาจจะมองหา Distributed Cached System ที่ดีๆมาใช้งานเช่น Windows Server AppFabric Caching (velocity), MemCached, NCache เป็นต้น</p>
<p>ในตอนนี้ขอเลือก Custom Mode มาใช้แก้ปัญหาของ Server Memory โดยใช้ AppFabric Caching</p>
<h4>Advantages of AppFabric Caching</h4>
<p>1. <strong>ทำงานเร็วกว่า SqlServer mode 4 เท่า</strong></p>
<p>2. ฟรีสำหรับ windows server 2008, windows 7</p>
<p>3. มี Client library สำหรับ .NET ให้ใช้งาน</p>
<p>4. สั่งงานได้จาก powershell และมี management tool ที่ใช้งานง่าย</p>
<p>5. High Availability ทำงานแบบ cluster node ได้ (for windows server 2008 <strong>enterprise edition</strong> only)</p>
<h4>AppFabic Caching Architecture</h4>
<p><a href="http://nine69.files.wordpress.com/2011/04/image.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb.png?w=501&#038;h=296" alt="image" width="501" height="296" border="0" /></a></p>
<h5>Physical Architecture Diagram</h5>
<p>กรณีที่ต้องทำ Web Server Farm การทำ Cluster node นั้นเป็นสิ่งจำเป็น จากรูปด้านบนนี้ จะเห็นว่า Cache Server นั้นมีจำนวน 3 Nodes โดยใช้ Cluster configuration Strorage location ที่เดียวกัน (ต้องอยู่ใน AD เท่านั้นถึงจะทำ cluster ได้) และก็สามารถเพิ่ม node เข้าไปได้อีก เพื่อรองรับการร้องขอเก็บบันทึกและอ่านข้อมูล Session/Cache ตามที่ต้องการ  โดยสามารถจัดการทั้ง cluster ได้โดยผ่าน PowerShell</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image1.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb1.png?w=502&#038;h=365" alt="image" width="502" height="365" border="0" /></a></p>
<h5>Logical Architecture Diagram</h5>
<p>จาก logical diagram ด้านบนนี้จะเห็นได้ว่าภายใน Cache Cluster นั้นมี Cache Host อยู่ 3 ตัว   และแถบเหลือง ๆ ก็คือ Cache มีไว้ใช้เก็บข้อมูลโดย Default Cache จะมีมาให้เสมอหลังติดตั้ง ส่วน Inventory และ Catalog นั้นเป็นส่วนที่สร้างเพิ่มเติม</p>
<p>สังเกตุว่า cache สามารถ Replicate ไปยัง Cache Host ทั้ง 3 ตัวได้  แต่การกำหนด Data Region นั้นจะไม่สามารถ replicate ข้อมูลได้</p>
<h4>Install And Config Windows Server AppFabric Caching (Non-Cluster)</h4>
<p>ก่อนอื่นตรวจาสอบว่าในเครื่องได้ติดตั้ง <a href="http://go.microsoft.com/fwlink/?LinkId=182018">IIS 7 Manager for Remote Administration</a> แล้วหรือไม่ ถ้ายังไม่ติดตั้ง ก็ดาวโหลดมาติดตั้งเสียก่อน</p>
<p>จากนั้นค่อยไป download AppFabric (<a href="http://www.microsoft.com/downloads/info.aspx?na=46&amp;SrcFamilyId=467E5AA5-C25B-4C80-A6D2-9F8FB0F337D2&amp;SrcDisplayLang=en&amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f1%2fA%2fD%2f1ADC8F3E-4446-4D31-9B2B-9B4578934A22%2fWindowsServerAppFabricSetup_x86_6.1.exe" target="_blank"><strong>for x86</strong></a>, <a href="http://www.microsoft.com/downloads/info.aspx?na=46&amp;SrcFamilyId=467E5AA5-C25B-4C80-A6D2-9F8FB0F337D2&amp;SrcDisplayLang=en&amp;u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f1%2fA%2fD%2f1ADC8F3E-4446-4D31-9B2B-9B4578934A22%2fWindowsServerAppFabricSetup_x64_6.1.exe" target="_blank"><strong>for x64</strong></a>)</p>
<p>1. เมื่อรัน *.msi ติดตั้งขั้นตอนแรก</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image2.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb2.png?w=290&#038;h=218" alt="image" width="290" height="218" border="0" /></a></p>
<p>2.  ให้กดเลือก checkbox ทั้งสอง จากนั้น monitoring provider เลือก System.Data.SqlClient และ Persistance provider ให้เลือก sqlStoreProvider และกดปุ่ม configure.. โดยทำซ้ำตามขั้นตอนถัดไปทั้ง 2 ปุ่ม</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image3.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb3.png?w=371&#038;h=280" alt="image" width="371" height="280" border="0" /></a></p>
<p>3.  จากนั้นไปสร้าง database สำหรับเก็บ Cache ของเรา ผมได้สร้าง <strong>AppFabricMonitoringDB</strong> และ <strong>AppFabricPersistanceDB</strong> ไว้ใน SQL Server ก่อนนี้แล้ว</p>
<p>จากนั้นกด checkbox ทั้งสองตามรูปด้านล่างและเลือก Database ที่ได้สร้างไว้</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image4.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb4.png?w=377&#038;h=316" alt="image" width="377" height="316" border="0" /></a></p>
<p>4.  กดปุ่ม install</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/a4.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="a4" src="http://nine69.files.wordpress.com/2011/04/a4_thumb.png?w=377&#038;h=284" alt="a4" width="377" height="284" border="0" /></a></p>
<p>5. เมื่อ install เสร็จก็จได้ภาพนี้ สังเกตุจะมี checkbox ถามว่าให้รัน configuration tool เลยหรือไม่</p>
<p>จากนั้นกด Finish</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/a5.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="a5" src="http://nine69.files.wordpress.com/2011/04/a5_thumb.png?w=381&#038;h=287" alt="a5" width="381" height="287" border="0" /></a></p>
<p>6. ก็จะได้หน้าจอของตัว Configuration Wizard มา</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/a6.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="a6" src="http://nine69.files.wordpress.com/2011/04/a6_thumb.png?w=381&#038;h=286" alt="a6" width="381" height="286" border="0" /></a></p>
<p>7. เช็คเลือก Set Caching Service config  เปลี่ยน Service Account เป็นชื่อ user ที่ต้องการ</p>
<p>ผมเลือก caching service configuration provider เป็น XML เนื่องจากติดตั้งบน Windows7 จึงไม่สามารถทำ Cluster ได้</p>
<p>และกำหนด ShareFolder ชื่อว่า <a href="//\\Nine-NB\AppFabricCacheXml">\\Nine-NB\AppFabricCacheXml</a> เอาไว้เก็บ xml config file</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image5.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb5.png?w=388&#038;h=292" alt="image" width="388" height="292" border="0" /></a></p>
<p>8.  กำหนด port สำหรับ Service ต่าง ๆ จะแก้ไขตามต้องการก็ได้ (ห้ามใช้ port ซ้ำกัน)</p>
<p>ตรวจเช็คว่าเครื่องตัวเองไม่ได้ติดตั้ง Firewall เพราะจะทำให้ติดต่อกับ service ไม่ได้</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/a8.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="a8" src="http://nine69.files.wordpress.com/2011/04/a8_thumb.png?w=393&#038;h=295" alt="a8" width="393" height="295" border="0" /></a></p>
<p>9.  จบขั้นตอนการติดตั้ง</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image6.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb6.png?w=393&#038;h=296" alt="image" width="393" height="296" border="0" /></a></p>
<p>10. ก็จะ start IIS7 ขึ้นมาตามรูปและมี AppFabric Section เพิ่มเข้ามาตามภาพ</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image7.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb7.png?w=401&#038;h=239" alt="image" width="401" height="239" border="0" /></a></p>
<p>11. หลังจากติดตั้งเสร็จแล้วก็ลองมาตรวจสอบที่ Start –&gt; Program –&gt; Windows Server AppFabric  จะพบรายการดังนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/a9.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="a9" src="http://nine69.files.wordpress.com/2011/04/a9_thumb.png?w=244&#038;h=230" alt="a9" width="244" height="230" border="0" /></a></p>
<h4>Using Caching Administration Windows PowerShell</h4>
<p>ไปที่ Start –&gt; All Programs –&gt; Windows Server AppFabric</p>
<p>เลือก Caching Administration Windows PowerShell จะได้หน้าต่างตามนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image8.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb8.png?w=417&#038;h=208" alt="image" width="417" height="208" border="0" /></a></p>
<p>1. <strong>Start-CacheCluster </strong>พิมพ์คำสั่งเพื่อสั่งให้ cache service เริ่มทำงาน จะได้เห็นว่า service กำลัง start</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image9.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb9.png?w=421&#038;h=211" alt="image" width="421" height="211" border="0" /></a></p>
<p>และจะพบว่า Service จะมี Status เป็น <strong>UP</strong></p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image10.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb10.png?w=427&#038;h=214" alt="image" width="427" height="214" border="0" /></a></p>
<p>2. <strong>Stop-CacheCluster</strong>  เป็นคำสั่งเพื่อ shutdown service</p>
<p>3. <strong>Restart-CacheCluster</strong> เป็นคำสั่งให้ Restart service</p>
<p>4. <strong>Get-CacheClusterHealth</strong> เป็นคำสั่งเพื่อตรวจดูสถานะของ service ว่าปัจจุบันเป็นอย่างไร</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image11.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb11.png?w=446&#038;h=223" alt="image" width="446" height="223" border="0" /></a></p>
<p>5. Grant-CacheAllowedClientAccount เป็นคำสั่ง Add Client Account เพื่อเข้าใช้งานระบบ cache</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image12.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb12.png?w=452&#038;h=105" alt="image" width="452" height="105" border="0" /></a></p>
<p>6. Get-Cache จะลิสรายการ cache ออกมาแสดงทั้ง cluster</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image13.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb13.png?w=456&#038;h=123" alt="image" width="456" height="123" border="0" /></a></p>
<p>7. New-Cache เป็นคำสั่งสร้าง cache</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image14.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb14.png?w=460&#038;h=124" alt="image" width="460" height="124" border="0" /></a></p>
<p>8. Get-CacheConfig  เป็นคำสั่งในการเรียกดูค่าคอนฟิกของ cache แต่ละตัว (ระวัง cache name เป็น case sensitive)</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image15.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb15.png?w=465&#038;h=200" alt="image" width="465" height="200" border="0" /></a></p>
<p>9. Set-CacheConfig เป็นคำสั่งในการตั้งค่าคอนฟิกให้ cache</p>
<p>10 Get-CacheStatistics เป็นคำสั่งในการดูค่าการทำงานที่ผ่านมาของ cache ตัวนั้น ๆ</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image16.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb16.png?w=479&#038;h=206" alt="image" width="479" height="206" border="0" /></a></p>
<p>11. Remove-Cache  เป็นคำสั่งในการลบ cache ตัวที่ต้องการ</p>
<p><a href="http://nine69.files.wordpress.com/2011/04/image17.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/04/image_thumb17.png?w=483&#038;h=208" alt="image" width="483" height="208" border="0" /></a></p>
<p>*** get more information : <a href="http://msdn.microsoft.com/en-us/library/ff718177.aspx" target="_blank">Cache Administration with Windows PowerShell (Windows Server AppFabric Caching)</a></p>
<h4>Summary</h4>
<p>ในตอนนี้เราได้ทำความรู้จักกับปัญหาของเซสชั่นและทำความรู้จักกับ AppFabric Caching รวมไปถึงการติดตั้งและการใช้คำสั่งในการทำงานกับตัว Cache Cluster ในตอนหน้าเราจะมาย้าย ASP.NET Session ไปเก็บลงใน AppFabric Caching กันครับ</p>
<hr />
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png"><img src="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png?w=143" alt="" border="0" /></a></p></blockquote>
<blockquote><p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Chalermpon Areepong Nine (นาย)</a></p>
<p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Microsoft MVP Thailand ASP.NET</a></p>
<p>email : nine_biz-talk.net <strong>at</strong> hotmail <strong>dot</strong> com</p></blockquote>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nine69.wordpress.com/268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nine69.wordpress.com/268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nine69.wordpress.com/268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nine69.wordpress.com/268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nine69.wordpress.com/268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nine69.wordpress.com/268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nine69.wordpress.com/268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nine69.wordpress.com/268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nine69.wordpress.com/268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nine69.wordpress.com/268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nine69.wordpress.com/268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nine69.wordpress.com/268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nine69.wordpress.com/268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nine69.wordpress.com/268/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=268&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nine69.wordpress.com/2011/04/17/asp-net-4-0-high-scalable-asp-net-session-state-with-windows-server-appfabric-cache-vol-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/8c2f25a91e95ddd2e418090794711d24?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">nine69</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb1.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb2.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb3.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb4.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/a4_thumb.png" medium="image">
			<media:title type="html">a4</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/a5_thumb.png" medium="image">
			<media:title type="html">a5</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/a6_thumb.png" medium="image">
			<media:title type="html">a6</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb5.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/a8_thumb.png" medium="image">
			<media:title type="html">a8</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb6.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb7.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/a9_thumb.png" medium="image">
			<media:title type="html">a9</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb8.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb9.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb10.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb11.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb12.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb13.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb14.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb15.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb16.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/04/image_thumb17.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png?w=143" medium="image" />
	</item>
		<item>
		<title>DI Framework Series : ออกแบบระบบให้ยืดหยุ่นด้วย Dependency Injection Framework</title>
		<link>http://nine69.wordpress.com/2011/02/21/dependencyinjection01/</link>
		<comments>http://nine69.wordpress.com/2011/02/21/dependencyinjection01/#comments</comments>
		<pubDate>Sun, 20 Feb 2011 23:48:00 +0000</pubDate>
		<dc:creator>Nine MVP ASP.NET</dc:creator>
				<category><![CDATA[Design Pattern]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Dependency Injection]]></category>
		<category><![CDATA[DI]]></category>
		<category><![CDATA[OO]]></category>

		<guid isPermaLink="false">https://nine69.wordpress.com/?p=142</guid>
		<description><![CDATA[Series DI Framework Series : ออกแบบระบบให้ยืดหยุ่นด้วย Dependency Injection Framework DI Framework Series : ออกแบบ DAL ให้รอบรับอนาคตด้วย Repositoty Pattern Programming Level: Intermediate – Advance Computer Skills: Object Oriented Programming (Interface/Abstract programing) Layer Architecture C# 3.0, LINQ ASP.NET Development Tool and Library Visual Studio 2010 Background: Application Layer Design มาถึงตอนสำคัญอีกตอนครับ สำหรับกลุ่มนักพัฒนาที่ชอบออกแบบและเขียนโปรแกรม  ในตอนนี้ผมขอเสนอเรื่องราวเกี่ยวกับการออกแบบระบบโดยใช้ PoEAA ตัวที่เรียกว่า Inversion of Control [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=142&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h4>Series</h4>
<ul>
<li><strong>DI Framework Series : ออกแบบระบบให้ยืดหยุ่นด้วย Dependency Injection Framework</strong></li>
<li>DI Framework Series : ออกแบบ DAL ให้รอบรับอนาคตด้วย Repositoty Pattern</li>
</ul>
<h4>Programming Level:</h4>
<ul>
<li>Intermediate – Advance</li>
</ul>
<h4>Computer Skills:</h4>
<ol>
<li>Object Oriented Programming (Interface/Abstract programing)</li>
<li>Layer Architecture</li>
<li>C# 3.0, LINQ</li>
<li>ASP.NET</li>
</ol>
<h4>Development Tool and Library</h4>
<ol>
<li>Visual Studio 2010</li>
</ol>
<h4>Background: Application Layer Design</h4>
<p>มาถึงตอนสำคัญอีกตอนครับ สำหรับกลุ่มนักพัฒนาที่ชอบออกแบบและเขียนโปรแกรม  ในตอนนี้ผมขอเสนอเรื่องราวเกี่ยวกับการออกแบบระบบโดยใช้ PoEAA ตัวที่เรียกว่า Inversion of Control โดยวิธี Dependecy Injection ซึ่งเป็นเทคนิคและแนวทางที่กำลังนิยมอยู่ในปัจจุบัน ซึ่งช่วยให้ระบบมีความยืดหยุ่นในการทำงานทุกอย่าง แต่ก็มีข้อแลกเปลี่ยนซึ่งเป็นข้อเสียเช่นกัน  แต่เมื่อประมาณการแล้วข้อเสียนั้นเล็กน้อยมากเมื่อแลกกับข้อดีที่ได้มาเต็ม ๆ</p>
<p>แต่ก่อนที่ผมจะเข้าสู่การอธิบาย เจ้าด้วย DI ผมขอยกเรื่องราวตัวอย่างในปัญหาการพัฒนาโปรแกรมในชีวิตจริง ของพวกเรา ๆ ที่เริ่มเขียนโปรแกรมไว้ประมาณนี้ครับ</p>
<blockquote><p>นายเอิธเป็นโปรแกรมเมอร์ที่เพิ่งเรียนจบ ตั้งใจจะรับงานฟรีแลนซ์ กะว่าทำงานคนเดียวคงรวยไม่ต้องแบ่งใคร ในเดือนแรกนายเอิธได้รับงานมาทำเป็น Windows App  ได้ไปเก็บรีไควเม้นท์ได้ ER Diagram, DB Dictionary, Screen  และ business กลับมา  จากนั้นก็เริ่มเขียนโปรแกรม โดยเริ่มจากการออกแบบดาต้าเบส  และเปิด visual studio ขึ้นมา และสร้างโปรเจ็คชื่อว่า <strong>EarthAccounting</strong> และสร้างหน้าจอสำหรับแสดงผลและบันทึกข้อมูล  โดยนายเอิธ มักจะกดดับเบิ้ลคลิ๊กปุ่มเพื่อให้เกิด click event แล้วก็เริ่มเขียนบันทึก อัพเดทข้อมูลกันภายในอีเว้นท์นั้น   นายเอิ๊กต้องทำ Form ของโปรแกรม 50 Form เลยทีเดียว  ปรากฎว่าเหนื่อยมาก  เวลาที่จะต้องส่งงานก็ใกล้เข้ามา  เงินที่ฝันไว้กำลังจะโดนหักหากส่งงานไม่ทันตามกำหนด  เนื่องจากทำอยู่คนเดียวงานจึงเสร็จล่าช้า  จึงตัดใจยอมดึงเพื่อนที่จบมาด้วยกันมาช่วยงานโดยแบ่ง form ให้ไปช่วยทำ   ทำไปได้ซักพักปรากฎว่าเริ่มมีฟังชั่นที่ใช้งานซ้ำ ๆ เกิดขึ้นจำนวนมากภายในฟอร์ม  นายเอิธจึงตกลงกับเพื่อนอีกคนในทีมว่า “เพื่อน เราจะแยกฟังชั่นที่ใช้ซ้ำ ๆ พวกนี้ไว้ใน utility class นะ  แล้วเพื่อนค่อยเอาไปใช้นะ”   หลังจากตกลงกันได้นายเอิธและเพื่อนก็เริ่ม refactoring code ในส่วนของฟังชั่นที่ได้ตกลงกันไว้  หลังจากทำงานไปได้ครึ่งทางปรากฎว่าเกิดมีการเปลี่ยน requirement โดยของแก้ business ส่วนกลางที่ใช้ในการคำนวนค่าทางบัญชี โดยการเปลี่ยนครั้งนี้กระทบกับ form ทั้งหมด 25 form 50 function เนื่องจากเป็นส่วนคำนวนที่ฝังโค้ดเอาไว้ในปุ่ม และยังมีงานเหลืออีก 15 Form ตั้งใจว่าจะ out source งานส่วนนี้ให้มือปืนรายอื่นเข้ามาช่วยงาน  แต่ต้องพบกับปัญหาที่ว่าไม่สามารถบอกโครงสร้างทางบิสซิเนสของลูกค้าให้บุคคลอื่นที่นอกเหนือจากสัญญาจ้างที่ได้เซ็นกันไว้ก่อนนี้  จนนายเอิธรู้สึกท้อใจกับการทำงานแนวทางนี้ จึงได้เปิดเว็บไปหากูเกิ้ล พบทางสว่างแห่งการลดปัญหาที่ว่า สามารถแบ่งงานกันทำได้ แก้ไขแล้วไม่กระทบระบบมากนัก ลดความซ้ำซ้อนและกระจายตัวของระบบงาน ก็คือการแบ่งโค้ดออกเป็น Layer โดยนายเอิธเห็นแนวทางว่าต้องแบ่งระบบออกเป็น 3 Layer (3 project) โดยมี</p>
<p>1. Presentation Layer (PL)  ส่วนที่ใช้แสดงผลได้แก่พวกกลุ่ม windows form, web form เป็นต้น</p>
<p>2. Business Logic Layer (BLL) แยกส่วนที่บรรจุลอจิกทาง business ออกมารวมกันไว้เป็นคลาส</p>
<p>3. Data Access Layer (DAL) เป็นส่วนที่ใช้ติดต่อกับดาต้าเบส</p></blockquote>
<p>โดยทั้ง 3 layer มีความสัมพันธ์กันดังนี้ PL –&gt; BLL –&gt; DAL โครงสร้างที่นายเอิธใช้ในรอบแรกมีลักษณะเป็นแบบนี้ครับ</p>
<p><strong>Sample01 Pattern : Basic structure </strong></p>
<p>เริ่มต้นเริ่มแรกใครได้ลองเขียนแยก layer ของโปรเจ็คออกเป็นชิ้นย่อย ๆ PL,BLL,DAL หากจุดไหนใครอยากเรียกใครก็แค่ add reference เข้ามาแล้วก็สร้างอินแสตนท์และเรียกใช้งานกันตรงนั้นดังตัวอย่างนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image4.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb4.png?w=167&#038;h=116" alt="image" width="167" height="116" border="0" /></a></p>
<p>กรณีใน Business Logic Layer (BLL) ที่จะเรียกใช้ Data Access Layer (DAL)<a href="http://nine69.files.wordpress.com/2011/02/image16.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb16.png?w=423&#038;h=129" alt="image" width="423" height="129" border="0" /></a></p>
<p>จาก class diagram จะพบว่า CustomerBLL มี association กับ CustomerDAL ตรง ๆ อีกนัยก็คือได้ add reference ของ project เข้ามาใช้งาน ลองดูโค้ดด้านล่างนี้ครับ</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image14.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb14.png?w=476&#038;h=266" alt="image" width="476" height="266" border="0" /></a></p>
<p>จากภาพจะพบได้ว่าใน line 3,7 มีการประกาศตัวแปรทีและสร้างอินสแตนท์ของ CustomerDAL ขึ้นใช้งาน ซึ่งเป็นการอ้างถึง DAL ตรง ๆ จะทำให้เราต้องมีการสร้าง DAL ขึ้นก่อน ถึงจะสามารถเขียน BLL ต่อไปได้ หรือแม้กระทั่งการทำเทสก็ยากต่อการทดสอบในกรณีที่ต้องแยกเทสแต่ละ Layer เพราะ BLL ไม่สามารถเทสโดยข้ามการสร้างอินแสตนท์ของ DAL ไปได้ และ DAL ยังถูกเรียกใช้ในทุกๆ จุดของเม็ธธอดของ BLL นั่นเอง</p>
<p>และในส่วนของ dependency diagram จะเห็นว่ามี 2 DLL ที่เรียกใช้งานกันตรง ๆ ซึ่งเป็นคำพูดที่ว่า Tight Coupling นั่นเอง</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image6.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb6.png?w=136&#038;h=166" alt="image" width="136" height="166" border="0" /></a></p>
<blockquote><p>ต่อมาแหม่ ทำงานพอได้ระบบใหญ่เข้าหน่อยชักฮึกเหิม ไม่นานนายเอิธก็บรรเจิดปิ๊งไอเดียที่ว่า อยากให้ EarthAccounting รองรับดาต้าเบสได้มากกว่า 1 ชนิด ต้องทำอย่างไร แน่นอนครับพึ่งพากูเกิ้ลอีก เสริชเข้าไปจนได้ความรุ้ที่ว่า “ก็ใช้ Class/Interface + Factory Method Pattern สิคร้าบบ” นายเอิธไม่รอนานรีบก่อนจะสายเวลาลงมือรื้อ BLL และ DAL ใหม่ทั้งยวง ตามตัวอย่างที่ 2 ข้างล่างนี้</p></blockquote>
<p><strong><strong>Sample02</strong> Pattern : Interface and Factory Class</strong></p>
<p><strong><a href="http://nine69.files.wordpress.com/2011/02/image7.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb7.png?w=172&#038;h=187" alt="image" width="172" height="187" border="0" /></a></strong></p>
<p>ตัวอย่างที่2 ในกรณีที่ว่า ระบบต้องการที่จะรองรับ DATABASE มากกว่า 1 ชนิด ในที่นี้ผมมี DAL ที่เอาไว้ใช้ทั้ง MySql และ MSSql ไว้ซัพพอร์ทลูกค้ากรณีเขาเลือกใช้อย่างใดอย่างหนึ่ง เราจึงแยกโครงสร้างโปรเจ็คไว้ประมาณหน้าตาดังรูปด้านบนภาพด้านล่างนี้เป็น DAL Class Structure ครับ<strong> </strong></p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image21.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image21_thumb.png?w=502&#038;h=347" alt="image" width="502" height="347" border="0" /></a></p>
<p>1. ผมกำหนดโครงสร้างของ DAL ไว้เป็น Interface ที่ชื่อว่า ICustomerServiceDAL ซึ่งมีเม็ธธอด GetCustomerName() ไว้ที่โปรเจ็ก Domain02</p>
<p>2. คลาสที่ใช้ติดต่อกับดาต้าเบสทั้ง MySqlDAL02.MySqlDAL และ MSSQLDAL02.MSSQLDAL จะ implement Domain02.ICustomerServiceDAL ทั้งคู่</p>
<p>3. โปรเจ็ก DALFactory Class จะมี GetActiveDAL method โดยมี return type เป็น ICustomerServiceDAL และภายในจะมีการสร้างอินแสตนท์ของคลาส MySqlDAL, MSSQLDAL โดยตามที่อ่านค่าได้จาก configuration file ตามโค้ดด้านล่างนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image121.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image12_thumb.png?w=466&#038;h=370" alt="image" width="466" height="370" border="0" /></a></p>
<p>4. ในโปรเจ็ค BLL02.CustomerBLL Class จะมีการเรียกใช้ Domain02.ICustomerServiceDAL และ DALFactory02.DALFactory ภายในดังนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image161.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image16_thumb.png?w=543&#038;h=253" alt="image" width="543" height="253" border="0" /></a></p>
<p>ต่อมาลองดู dependency diagram ของตัวอย่างที่ 2 กันครับ</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image10.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb10.png?w=594&#038;h=344" alt="image" width="594" height="344" border="0" /></a></p>
<p>จากรูปด้านบนจะเห็นได้ว่าคลาส BLL02.CustomerBLL นั้นไม่ได้เรียกใช้ MSSqlDALและ MySqlDAL ตรง ๆ แต่จะเรียกใช้ผ่านคลาส DALFactoty02.DALFactory โดยอิงตามเสปคของ Domain02.ICustomerServiceDAL interface ซึง DALFactory เป็นคลาสที่ช่วยแยก DAL ของ Database ชนิดต่าง ๆ ออกไปจัดการภายใน factory method  ตรงนี้จุดที่เกิด tight coupling คือ CustomerBLL และ DALFactory</p>
<p>และในส่วนของ  Factory Class ก็ต้องรู้จักกับคลาส SqlDAL, MySqlDAL และ OracleDAL ตรง ๆ ซึ่งจากดีไซน์นี้ความเป็นจริงคือไม่ได้ลดความ Tight Coupling ของโครงสร้างลงเลย  แต่ว่าดีไซน์นี้มีกลิ่นไอของ Dependency Injection อยู่ระดับนึง</p>
<blockquote><p>หลังจากที่นายเอิธพยายามกับโปรแกรมสุดเดิ้ล อย่าง EarthAccounting เพื่อเพิ่มความสามารถและสร้างความสามารถที่รองรับกับความต้องการของลูกค้าในเรื่องการเลือก database ได้ถึง 2 ชนิด  กลับมาเจอกับ challenge ใหม่ในหัวข้อที่ว่า ลูกค้าต้องการลอจิกในการคำนวณค่าบางตัวด้วยสูตรทางคณิตที่ซับซ้อน ซึ่งนายเอิธและเพื่อนไม่เก่งคณิตเอาซะเลย เลยตั้งใจจะ outsource งานส่วนนี้ไปให้คนอื่นทำ แต่มาติดปัญหาว่า คลาสใน BLL นั้นต้องมานั่งรอ คลาสอีกตัวของทาง outsource กว่าจะได้จัดส่ง มาให้ใช้งานใน BLL ถ้านั่งรอก็คงกินเวลาไปอีกเป็นอาทิตย์  ไหนกว่าจะได้งานมาก็มานั่งเขียนโปรแกรม นั่งเทส นั่ง build ทำ package งานเกินเวลาส่งแน่ ๆ จึงได้เปิดกูเกิ้ลและค้นหาจนได้พบกำคำว่า <strong>Dependency Injection</strong></p></blockquote>
<p>จากเรื่องราวด้านบน ทำให้เห็นได้ว่าสิ่งที่นายเอิธกำลังต้องการก็คือวิธีีการออกแบบและเฟรมเวิร์กที่จะช่วยแก้ปัญหา</p>
<p>1. ต้องการดีไซน์ที่ช่วยให้แยก Layer และ Dependency ให้เป็นอิสระจากกัน</p>
<p>2. ต้องการแยกเทสในแต่ละ Layer และ Dependency ที่เกี่ยวข้อง</p>
<p>3. ต้องการลดการ rebuild โปรแกรม กรณีที่มีการ update  DLL เพียงแค่บางตัว</p>
<p>4. สามารถกำหนดโครงสร้างของระบบ โดยใช้ Class, Interface เป็น contract ในการพัฒนาระหว่าง Layer และ Dependency ทั้งหมด</p>
<h4>Dependency Injection Pattern</h4>
<p>ถูกคิดค้นโดยนาย Martin Flower ในหัวข้อเรื่อง Inversion of control (IoC) มีวัตถุประสงค์เพื่อช่วยแก้ปัญหาการยึดเกาะระหว่างโมดูลของระบบให้แยกขาดออกจากกัน โดยกลับเส้นของ dependency จากผู้เรียกใช้กลายเป็นผู้ถูกเรียก (Hollywood Principal)   IoC เป็น 1 ในกลุ่มของ PoEAA โดยมีแนวทางการนำไปใช้งานได้ 2 แบบคือ Service Locator และ Dependency Injection   ซึ่งจะขอกล่าวถึงเพียง DI เท่านั้น  ดังนี้ผมขออธิบายแบบไม่อิงภาษา oo หรือแบบบ้าน ๆ ว่า DI นั้นคือการสร้างและยิง object ณ ตอน runtime เข้าไปยังกลุ่มคลาสที่ได้เรียกใช้ Interface ซึ่งเป็นข้อตกลงที่ object นั้นๆได้นำไป implement โดยการยิง object นั้นมีทั้งแบบ setter และ constructor</p>
<p>การนำ DI Pattern ไปใช้งานนั้นมีได้หลายวิธีครับ แบบ DIY (Do it your self) หรือใช้ Framework ซึ่งในปัจจุบันนั้นมีอยู่เยอะมากกกก ตามรายชื่อที่พอจะรวบรวมมาได้ด้านล่างนี้ (แต่ยังคงมีออีกเยอะ)</p>
<table width="571" border="2" cellspacing="1" cellpadding="2">
<tbody>
<tr>
<td valign="top" width="175"><strong></strong><strong>Name</strong></td>
<td align="center" width="238"><strong>Performance</strong><strong>(Transient : Singleton)*</strong></td>
<td valign="top" width="150"><strong>Current</strong> <strong>Version</strong></td>
</tr>
<tr>
<td valign="top" width="187">Spring.Net</td>
<td align="center" width="239">n/a:n/a</td>
<td valign="top" width="158">1.3.1</td>
</tr>
<tr>
<td valign="top" width="192">Castle Windsor</td>
<td align="center" width="234">2:4</td>
<td valign="top" width="161">2.5.1</td>
</tr>
<tr>
<td valign="top" width="194">Ninject</td>
<td align="center" width="233">2:2</td>
<td valign="top" width="162">2.1.0.76</td>
</tr>
<tr>
<td valign="top" width="195">StructureMap</td>
<td align="center" width="232">5:4</td>
<td valign="top" width="163">2.6.1.0</td>
</tr>
<tr>
<td valign="top" width="195">Unity (Microsoft)</td>
<td align="center" width="232">4:4</td>
<td valign="top" width="163">2.0</td>
</tr>
<tr>
<td valign="top" width="195">AutoFac</td>
<td align="center" width="232">3:4</td>
<td valign="top" width="163">2.2.4.9</td>
</tr>
<tr>
<td valign="top" width="195">MEF (Microsoft)</td>
<td align="center" width="232">N/A</td>
<td valign="top" width="163">1.0</td>
</tr>
<tr>
<td valign="top" width="195">Dynamo</td>
<td align="center" width="232">5:5</td>
<td valign="top" width="163">1.0(beta)</td>
</tr>
</tbody>
</table>
<p>* performance 1:bad,2:poor,3:normal,4:good,5:best</p>
<p>** มีหลายปัจจัยสำหรับการตัดสินใจเลือกใช้ framework เพราะแต่ละตัวนั้นมีความสามารถไม่เท่ากัน บางตัวสร้างมาเพื่อ DI โดยเฉพาะ บางตัวเป็น framework ที่มีการ integrate กับหลายส่วนงาน</p>
<h4>DI Start up : Demo ASP.NET 3 Layer with Dependency Injection (Unity 2.0)</h4>
<p>สำหรับเริ่มกับ DI ผมขอแนะนำการใช้งานเจ้า DI ตัวนึงก็คือ Unity ครับ เป็นของไมโครซอฟเองก่อนอื่นก็ไปดาวน์โหลดมาติดตั้งก่อนครับ ที่นี่ <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=2d24f179-e0a6-49d7-89c4-5b67d939f91b&amp;displaylang=en">Unity 2.0</a> ติดตั้งเสร็จแล้วก็เริ่มใช้งานกันเลย</p>
<p>ลองดูโครงสร้างโปรเจ็คทั้งหมดครับ</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image17.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb17.png?w=168&#038;h=194" alt="image" width="168" height="194" border="0" /></a></p>
<p>และให้ add reference ตาม dependency diagram ตามภาพด้านล่างนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image18.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb18.png?w=526&#038;h=219" alt="image" width="526" height="219" border="0" /></a></p>
<p>เราจะเห็นได้ว่า ไม่มีเส้น PL ไปเรียก BLL หรือ BLL ไปเรียก DAL ให้เห็นเลย ทุก Layer จะวิ่งไปมองที่ Domain ทั้งหมด</p>
<h5>1. Domains03 Project</h5>
<p><a href="http://nine69.files.wordpress.com/2011/02/image19.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb19.png?w=193&#038;h=102" alt="image" width="193" height="102" border="0" /></a></p>
<p>สำหรับโปรเจ็คนี้ ผมออกแบบไว้เพื่อกำหนดโครงสร้าง layer ทั้งหมดของ Application โดยภายในจะประกอบไปด้วย  Domain class เป็นกลุ่มคลาสที่เอาไว้ใช้งานข้ามระหว่าง layer , Service Interface เอาไว้กำหนดโครงสร้างให้ BLL , Repository Interface เอาไว้กำหนดโครงสร้างให้ DAL</p>
<ul>ตามรูปด้านล่างนี้</ul>
<p><a href="http://nine69.files.wordpress.com/2011/02/image20.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb20.png?w=307&#038;h=223" alt="image" width="307" height="223" border="0" /></a></p>
<ul>
<li>สำหรับ Domain03.Customer class เป็นโดเมนคลาส ที่จะใช้ในการทำงานกับทุก layer<br />
<blockquote><p><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">Customer</span><br />
{<br />
<span style="color:#0000ff;">   public</span> <span style="color:#0000ff;">string</span> CustId { <span style="color:#0000ff;">get</span>; <span style="color:#0000ff;">set</span>; }<br />
<span style="color:#0000ff;">   public</span> <span style="color:#0000ff;">string</span> FName { <span style="color:#0000ff;">get</span>; <span style="color:#0000ff;">set</span>; }<br />
<span style="color:#0000ff;">   public</span> <span style="color:#0000ff;">string</span> LName { <span style="color:#0000ff;">get</span>; <span style="color:#0000ff;">set</span>; }<br />
}</p></blockquote>
</li>
</ul>
<ul>
<li>ข้อกำหนดของ DAL ผมได้สร้าง Domain03.ICustomerRepository interface เอาไว้ใช้เป็นข้อกำหนด  โดยจะสร้างด้วยอะไรก็ได้ไม่ว่าจะเป็น Entity Framework, NHibernate หรือ Custom DAL with ADO.NET ก็ได้แล้วแต่ตามต้องการ  ซึ่งบังคับว่าคุณต้องใช้ interface ตัวนี้ในการทำงานเท่านั้น</li>
</ul>
<blockquote><p><span style="color:#0000ff;">public </span><span style="color:#0000ff;">interface </span><span style="color:#2b91af;">ICustomerRepository</span><br />
{<br />
<span style="color:#2b91af;">   Customer</span> GetCustomerById(<span style="color:#0000ff;">string</span> custId);<br />
}</p></blockquote>
<ul>
<li>ผมสร้างส่วนของ Domain03.CustomerService interface เป็นข้อกำหนดว่า Busines Logic Class ของ CustomerService ใดๆที่จะพัฒนาและนำเข้ามาใช้งานต้องนำ interface นี้ไปใช้เท่านั้น</li>
</ul>
<blockquote><p><span style="color:#0000ff;">public </span><span style="color:#0000ff;">interface </span><span style="color:#2b91af;">ICustomerService</span></p>
<p>{<br />
<span style="color:#2b91af;">   Customer</span> GetCustomer(<span style="color:#0000ff;">string</span> custId);<br />
}<span style="color:#0000ff;"><br />
</span></p></blockquote>
<p>&nbsp;</p>
<h5>2. L2SDAL03 Project (DAL –&gt; Domain)</h5>
<p><a href="http://nine69.files.wordpress.com/2011/02/image22.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb21.png?w=173&#038;h=72" alt="image" width="173" height="72" border="0" /></a></p>
<p>สำหรับโปรเจ็คนี้ ผมได้นำ interface ที่ชื่อ ICustomerRepository เข้ามาใช้งานใน CustomerLinq2Sql Class โดยตามภาพไดอะแกรมด้านล่างนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image23.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb22.png?w=168&#038;h=139" alt="image" width="168" height="139" border="0" /></a></p>
<p>ในส่วนของโค้ดผมได้สร้าง data สำหรับส่งค่ากลับไป ไม่ได้ติดต่อดาต้าเบสจริง ๆ ดังนี้</p>
<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:c8395f98-3144-4937-9ba7-8069ba566151" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background-color:#ffffff;overflow:auto;white-space:nowrap;padding:2px 5px;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">CustomerLinq2Sql</span> : <span style="color:#2b91af;">ICustomerRepository</span><br />
{<br />
<span style="color:#0000ff;">public</span> <span style="color:#2b91af;">Customer</span> GetCustomerById(<span style="color:#0000ff;">string</span> custId)<br />
{<br />
<span style="color:#0000ff;">if</span> (!<span style="color:#0000ff;">string</span>.IsNullOrEmpty(custId))<br />
{<br />
<span style="color:#0000ff;">var</span> cust = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Customer{</span>CustId = custId};                <span style="color:#0000ff;">if</span> (custId.ToLower().Contains(<span style="color:#a31515;">&#8217;1&#8242;</span>))<br />
{<br />
cust.FName = <span style="color:#a31515;">&#8220;Nine&#8221;</span>;<br />
cust.LName = <span style="color:#a31515;">&#8220;MVP&#8221;</span>;<br />
}<br />
<span style="color:#0000ff;">if</span> (custId.ToLower().Contains(<span style="color:#a31515;">&#8217;2&#8242;</span>))<br />
{<br />
cust.FName = <span style="color:#a31515;">&#8220;SHISUKA&#8221;</span>;<br />
cust.LName = <span style="color:#a31515;">&#8220;SHAREPOINT&#8221;</span>;<br />
}<br />
<span style="color:#0000ff;">if</span> (custId.ToLower().Contains(<span style="color:#a31515;">&#8217;3&#8242;</span>))<br />
{<br />
cust.FName = <span style="color:#a31515;">&#8220;JIENT&#8221;</span>;<br />
cust.LName = <span style="color:#a31515;">&#8220;BizTalk&#8221;</span>;<br />
}<br />
<span style="color:#0000ff;">return</span> cust;<br />
}<br />
<span style="color:#0000ff;">return</span> <span style="color:#0000ff;">null</span>;<br />
}<br />
}</p>
</div>
</div>
</div>
<h5>3. BLL03 Project  (BLL –&gt; Domain)</h5>
<p><a href="http://nine69.files.wordpress.com/2011/02/image24.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb23.png?w=178&#038;h=73" alt="image" width="178" height="73" border="0" /></a></p>
<p>ในส่วนของ BLL03 Project ก็คือ Business Logic Layer ของเรานั่นเอง ผมได้นำ ICustomerService interface เข้ามาอิมพลีเม้นให้กับคลาส CustomerService ตามไดอะแกรมด้านล่างนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image25.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb24.png?w=167&#038;h=190" alt="image" width="167" height="190" border="0" /></a></p>
<p>ลองมาดูส่วนของโค้ดในคลาส CustomerService กันครับ</p>
<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:4f13a722-312f-413e-95a4-61c39eccfcb5" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background-color:#ffffff;overflow:auto;white-space:nowrap;padding:2px 5px;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">CustomerService</span> : <span style="color:#2b91af;">ICustomerService</span><br />
{<br />
<span style="color:#0000ff;">private</span> <span style="color:#2b91af;">ICustomerRepository</span>dal;        <span style="color:#0000ff;">public</span> CustomerService(<span style="color:#2b91af;">ICustomerRepository</span> repository)<br />
{<br />
dal = repository;<br />
}</p>
<p><span style="color:#0000ff;">public</span> <span style="color:#2b91af;">Customer</span> GetCustomer(<span style="color:#0000ff;">string</span> custId)<br />
{<br />
<span style="color:#0000ff;">return</span> dal.GetCustomerById(custId);<br />
}</p>
<p>}</p>
</div>
</div>
</div>
<ul>
<li>จะเห็นได้ว่าในบรรทัดที่ 3 จะมีการประกาศตัวแปรของ ICustomerRepository ไว้ที่นี่เนื่องจากวน BLL นั้นจะเป็นผ้ที่เรียกใช้ DAL นั่นเอง</li>
<li>บรรทัดที่ 5 คือการเปิดให้ DI นั้นยิง object เข้ามาทาง Constructor นั่นเอง</li>
<li>บรรทัดที่ 12 เป็นการเรียกใช้ DAL ที่ถูกยิง object เข้ามาโดย DI โดยเรียกผ่านทาง polymorphism ของ interface</li>
</ul>
<h5>4. WebUI03 Project (PL –&gt; Domain)</h5>
<p>หลังจากที่เราได้วางโครงสร้างและทำการสร้างกลุ่ม BLL, DALเสร็จเรียบร้อยแล้ว  ขั้นตอนต่อไปคือการนำไปใช้งาน โดยก่อนนี้การแบ่งเลเยอร์แบบปกติ ลำดับของผู้ที่จะทำการเรียกใช้ ก็คือ PL –&gt; BLL –&gt; DAL แต่เราจะเปลี่ยนเส้นให้ชี้ไปที่ PL –&gt; Domain และสำหรับ PL นั่นจะมีส่วนที่พิเศษสำหรับการนำ DI เข้ามาใช้งาน เนื่องจากเป็นความแตกต่างของเทคโนโลยี ไม่ว่าจะเป็น ASP.NET, ASP.NET MVC, SilverLight, Windows App เป็นต้น</p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image26.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;margin:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb25.png?w=174&#038;h=216" alt="image" width="174" height="216" border="0" /></a></p>
<h6>ขั้นแรก  ตั้งค่าคอนฟิกของ Unity ใน web.config  ดังนี้</h6>
<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:2903e2ea-13d4-4216-a823-00e48a7f5d0c" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#ddd;overflow:auto;">
<ol style="background:#ffffff;margin:0 0 0 2em;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">configSections</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">section</span><span style="color:#ff0000;">name</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">unity</span>&#8220;<span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration</span>&#8220;<span style="color:#0000ff;"> /&gt;</span></li>
<li><span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">configSections</span><span style="color:#0000ff;">&gt;</span></li>
</ol>
</div>
</div>
</div>
<p>&nbsp;</p>
<p><span style="color:#0000ff;"><span style="color:#000000;">เป็นการเพิ่มโมเดลคอนฟิกของ Unity ภายใน web.config</span></span></p>
<p>&nbsp;</p>
<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:0fd7d19e-db34-4214-a32b-7ff2ea407bbe" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#ddd;overflow:auto;">
<ol style="background:#ffffff;margin:0 0 0 2.5em;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">unity</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">typeAliases</span><span style="color:#0000ff;">&gt;</span></li>
<li>    <span style="color:#0000ff;">&lt;!&#8211;</span><span style="color:#008000;"> Lifetime manager types </span><span style="color:#0000ff;">&#8211;&gt;</span></li>
<li style="background:#f3f3f3;">    <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">typeAlias</span><span style="color:#ff0000;">alias</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">singleton</span>&#8220;</li>
<li>         <span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">Microsoft.Practices.Unity.ContainerControlledLifetimeManager,</span></li>
<li style="background:#f3f3f3;">             <span style="color:#0000ff;">Microsoft.Practices.Unity</span>&#8220;<span style="color:#0000ff;"> /&gt;</span></li>
<li>    <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">typeAlias</span><span style="color:#ff0000;">alias</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">perThread</span>&#8220;</li>
<li style="background:#f3f3f3;">         <span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">Microsoft.Practices.Unity.PerThreadLifetimeManager,</span></li>
<li>             <span style="color:#0000ff;">Microsoft.Practices.Unity</span>&#8220;<span style="color:#0000ff;"> /&gt;</span></li>
<li style="background:#f3f3f3;">    <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">typeAlias</span><span style="color:#ff0000;">alias</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">external</span>&#8220;</li>
<li>         <span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">Microsoft.Practices.Unity.ExternallyControlledLifetimeManager,</span></li>
<li style="background:#f3f3f3;">             <span style="color:#0000ff;">Microsoft.Practices.Unity</span>&#8220;<span style="color:#0000ff;"> /&gt;</span></li>
<li>  <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">typeAliases</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">  <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">containers</span><span style="color:#0000ff;">&gt;</span></li>
<li>    <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">container</span><span style="color:#ff0000;">name</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">containerOne</span>&#8220;<span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">      <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">types</span><span style="color:#0000ff;">&gt;</span></li>
<li>        <span style="color:#0000ff;">&lt;!&#8211;</span><span style="color:#008000;"> map ICustomerService to CustomerService </span><span style="color:#0000ff;">&#8211;&gt;</span></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">type</span><span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">Domains03.ICustomerService, Domains03</span>&#8220;<span style="color:#ff0000;">mapTo</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">BLL03.CustomerService, BLL03</span>&#8220;<span style="color:#0000ff;">&gt;</span></li>
<li>          <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">lifetime</span><span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">singleton</span>&#8220;<span style="color:#0000ff;"> /&gt;</span></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">type</span><span style="color:#0000ff;">&gt;</span></li>
<li>        <span style="color:#0000ff;">&lt;!&#8211;</span><span style="color:#008000;"> map ICustomerRepository to CustomerLinq2Sql </span><span style="color:#0000ff;">&#8211;&gt;</span></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">type</span><span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">Domains03.ICustomerRepository, Domains03</span>&#8220;<span style="color:#ff0000;">mapTo</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">L2SDAL03.CustomerLinq2Sql, L2SDAL03</span>&#8220;<span style="color:#0000ff;">&gt;</span></li>
<li>          <span style="color:#0000ff;">&lt;</span><span style="color:#a31515;">lifetime</span><span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">singleton</span>&#8220;<span style="color:#0000ff;"> /&gt;</span></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">type</span><span style="color:#0000ff;">&gt;</span></li>
<li>      <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">types</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;">    <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">container</span><span style="color:#0000ff;">&gt;</span></li>
<li>  <span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">containers</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;"><span style="color:#0000ff;">&lt;/</span><span style="color:#a31515;">unity</span><span style="color:#0000ff;">&gt;</span></li>
</ol>
</div>
</div>
</div>
<p><span style="color:#0000ff;"><span style="color:#000000;">Line 2 – 13 คือการตั้งชื่อย่อให้ component กลุ่ม LifeTime </span></span></p>
<p><span style="color:#0000ff;"><span style="color:#000000;">Line 15 คือการกำหนด container name ที่จะบรรจุกุล่ม dependency เข้าไว้ในนี้</span></span></p>
<p><span style="color:#0000ff;"><span style="color:#000000;">Line 16 – 25 คือการแม๊พ Interface เข้ากับ Class ที่นำอินเทอเฟสไปใช้งาน โดยจะเป็น BLL และ DAL ของเรา</span></span></p>
<p>&nbsp;</p>
<h6><span style="color:#0000ff;"><span style="color:#000000;">ขั้นที่ 2 แก้ไขไฟล์ Global.asax </span></span></h6>
<p><span style="color:#0000ff;"><span style="color:#000000;">เพราะว่าเว็บเวลาจะ start up ขึ้นมาส่วนที่ทำหน้าที่ก่อนคือไฟล์นี้ครับ โดยแก้ไขตามนี้</span></span></p>
<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:e8803807-ca8a-46fc-9ba5-4c07f2296f7d" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">Code Snippet</div>
<div style="background:#ddd;overflow:auto;">
<ol style="background:#ffffff;margin:0 0 0 2.5em;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">interface</span> <span style="color:#2b91af;">IContainerAccessor</span></li>
<li style="background:#f3f3f3;">{</li>
<li>    <span style="color:#2b91af;">IUnityContainer</span> Container { <span style="color:#0000ff;">get</span>; <span style="color:#0000ff;">set</span>; }</li>
<li style="background:#f3f3f3;">}</li>
<li></li>
<li style="background:#f3f3f3;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">Global</span> : System.Web.<span style="color:#2b91af;">HttpApplication</span>, <span style="color:#2b91af;">IContainerAccessor</span></li>
<li>{</li>
<li style="background:#f3f3f3;"></li>
<li>    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> <span style="color:#2b91af;">IUnityContainer</span> _container;</li>
<li style="background:#f3f3f3;"></li>
<li>    <span style="color:#0000ff;">public</span> <span style="color:#2b91af;">IUnityContainer</span> Container</li>
<li style="background:#f3f3f3;">    {</li>
<li>        <span style="color:#0000ff;">get</span> { <span style="color:#0000ff;">return</span> _container; }</li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">set</span> { _container = <span style="color:#0000ff;">value</span>; }</li>
<li>    }</li>
<li style="background:#f3f3f3;"></li>
<li>    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> BuildContainer()</li>
<li style="background:#f3f3f3;">    {</li>
<li>        <span style="color:#2b91af;">IUnityContainer</span> container = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">UnityContainer</span>();</li>
<li style="background:#f3f3f3;">        <span style="color:#008000;">//unityContainer = new UnityContainer();</span></li>
<li>        <span style="color:#2b91af;">UnityConfigurationSection</span> section</li>
<li style="background:#f3f3f3;">            = (<span style="color:#2b91af;">UnityConfigurationSection</span>)<span style="color:#2b91af;">ConfigurationManager</span>.GetSection(<span style="color:#a31515;">&#8220;unity&#8221;</span>);</li>
<li>        section.Containers[<span style="color:#a31515;">"containerOne"</span>].Configure(container);</li>
<li style="background:#f3f3f3;">        _container = container;</li>
<li>    }</li>
<li style="background:#f3f3f3;"></li>
<li>    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> CleanUp()</li>
<li style="background:#f3f3f3;">    {</li>
<li>        <span style="color:#0000ff;">if</span> (_container != <span style="color:#0000ff;">null</span>)</li>
<li style="background:#f3f3f3;">        {</li>
<li>            _container.Dispose();</li>
<li style="background:#f3f3f3;">        }</li>
<li>    }</li>
<li style="background:#f3f3f3;"></li>
<li>    <span style="color:#0000ff;">void</span> Application_Start(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">    {</li>
<li>        <span style="color:#008000;">// Code that runs on application startup</span></li>
<li style="background:#f3f3f3;">        BuildContainer();</li>
<li>    }</li>
<li style="background:#f3f3f3;"></li>
<li>    <span style="color:#0000ff;">void</span> Application_End(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">    {</li>
<li>        <span style="color:#008000;">//  Code that runs on application shutdown</span></li>
<li style="background:#f3f3f3;">        CleanUp();</li>
<li>    }</li>
<li style="background:#f3f3f3;"></li>
<li>    <span style="color:#0000ff;">void</span> Application_Error(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">    {}</li>
<li>    <span style="color:#0000ff;">void</span> Session_Start(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">    {}</li>
<li>    <span style="color:#0000ff;">void</span> Session_End(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">    {}</li>
<li>}</li>
</ol>
</div>
</div>
</div>
<p><span style="color:#0000ff;"><span style="color:#000000;">line 1-4 เป็น interface ที่เอาไว้ให้ส่วนอื่นสามารถเรียกใช้ container ได้จาก Global </span></span></p>
<p><span style="color:#0000ff;"><span style="color:#000000;">line 6 อิมพลีเม้น IContainerAccessor ให้ Global</span></span></p>
<p><span style="color:#0000ff;"><span style="color:#000000;">line 9 เป็นการประกาศตัวแปรของ container </span></span></p>
<p><span style="color:#0000ff;"><span style="color:#000000;">line 11 เป็น Property จาก IContainerAccessor Interface </span></span></p>
<p><span style="color:#0000ff;"><span style="color:#000000;">line 17-25 เป็นการโหลด container จาก web.config ที่เราได้ตั้งค่าไว้เข้ามา</span></span></p>
<p>&nbsp;</p>
<h6><span style="color:#0000ff;"><span style="color:#000000;">ขั้นที่ 3 จัดการ set dependency ไปยังหน้า webpage (Setter Method)</span></span></h6>
<p><span style="color:#0000ff;"><span style="color:#000000;">ซึ่งเราจะสร้าง HttpModule เอาไว้สำหรับสั่งให้ DI เซ็ทค่าต่าง ๆ เข้าไปใน Web UI ณ จุด ที่มีการเรียกใช้กลุ่ม อินเทอเฟส ในทุกครั้งที่มีการเรียกถึง page นั้น ๆ ดังนี้</span></span></p>
<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:2de2225f-d765-42da-bfbb-9a72aeaef14b" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">DIHttpModule.cs</div>
<div style="background:#ddd;overflow:auto;">
<ol style="background:#ffffff;margin:0 0 0 2.5em;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">DIHttpModule</span> : <span style="color:#2b91af;">IHttpModule</span></li>
<li style="background:#f3f3f3;">    {</li>
<li>        <span style="color:#0000ff;">private</span> <span style="color:#2b91af;">IUnityContainer</span> container;</li>
<li style="background:#f3f3f3;"></li>
<li>        <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">void</span> ContextPreRequestHandlerExecute(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">        {</li>
<li>            <span style="color:#2b91af;">Page</span> page = <span style="color:#2b91af;">HttpContext</span>.Current.CurrentHandler <span style="color:#0000ff;">as</span> <span style="color:#2b91af;">Page</span>;</li>
<li style="background:#f3f3f3;">            <span style="color:#0000ff;">if</span> (page != <span style="color:#0000ff;">null</span>)</li>
<li>            {</li>
<li style="background:#f3f3f3;">                page.PreInit += Page_PreInit;</li>
<li>            }</li>
<li style="background:#f3f3f3;">        }</li>
<li></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">void</span> BuildUp(<span style="color:#0000ff;">object</span> o)</li>
<li>        {</li>
<li style="background:#f3f3f3;">            container.BuildUp(o.GetType(), o);</li>
<li>        }</li>
<li style="background:#f3f3f3;"></li>
<li>        <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">void</span> Page_PreInit(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li style="background:#f3f3f3;">        {</li>
<li>            <span style="color:#2b91af;">Page</span> page = sender <span style="color:#0000ff;">as</span> <span style="color:#2b91af;">Page</span>;</li>
<li style="background:#f3f3f3;"></li>
<li>            BuildUp(page);</li>
<li style="background:#f3f3f3;"></li>
<li>            BuildUpMaster(page.Master);</li>
<li style="background:#f3f3f3;"></li>
<li>            BuildUpControls(page.Controls);</li>
<li style="background:#f3f3f3;">        }</li>
<li></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">void</span> BuildUpControls(<span style="color:#2b91af;">ControlCollection</span> controls)</li>
<li>        {</li>
<li style="background:#f3f3f3;">            <span style="color:#0000ff;">foreach</span> (<span style="color:#2b91af;">Control</span> c <span style="color:#0000ff;">in</span> controls)</li>
<li>            {</li>
<li style="background:#f3f3f3;">                <span style="color:#0000ff;">if</span> (c <span style="color:#0000ff;">is</span> <span style="color:#2b91af;">UserControl</span>)</li>
<li>                    BuildUp(c);</li>
<li style="background:#f3f3f3;"></li>
<li>                BuildUpControls(c.Controls);</li>
<li style="background:#f3f3f3;">            }</li>
<li>        }</li>
<li style="background:#f3f3f3;"></li>
<li>        <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">void</span> BuildUpMaster(<span style="color:#2b91af;">MasterPage</span> page)</li>
<li style="background:#f3f3f3;">        {</li>
<li>            <span style="color:#0000ff;">if</span> (page != <span style="color:#0000ff;">null</span>)</li>
<li style="background:#f3f3f3;">            {</li>
<li>                BuildUp(page);</li>
<li style="background:#f3f3f3;">                BuildUpMaster(page.Master);</li>
<li>            }</li>
<li style="background:#f3f3f3;">        }</li>
<li></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">#region</span> IHttpModule Members</li>
<li></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span> Init(<span style="color:#2b91af;">HttpApplication</span> context)</li>
<li>        {</li>
<li style="background:#f3f3f3;">            container = ((<span style="color:#2b91af;">IContainerAccessor</span>)context).Container;</li>
<li>            context.PreRequestHandlerExecute += ContextPreRequestHandlerExecute;</li>
<li style="background:#f3f3f3;">        }</li>
<li></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span> Dispose()</li>
<li>        {</li>
<li style="background:#f3f3f3;">        }</li>
<li></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">#endregion</span></li>
<li>    }</li>
</ol>
</div>
</div>
</div>
<p><span style="color:#0000ff;"><span style="color:#000000;">เข้าไป register HttpModule ที่เราสร้างขึ้นใน web.config ภายในบริเวณ &lt;system.web&gt; ..  ดังนี้</span></span></p>
<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:f00ffd16-0862-464d-a8ca-e45a9f830a0e" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#fff;overflow:auto;">
<ol style="background:#ffffff;margin:0;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">    &lt;</span><span style="color:#a31515;">httpModules</span><span style="color:#0000ff;">&gt;</span></li>
<li style="background:#f3f3f3;"><span style="color:#0000ff;">      &lt;</span><span style="color:#a31515;">add</span><span style="color:#ff0000;">name</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">DIMod</span>&#8220;<span style="color:#ff0000;">type</span><span style="color:#0000ff;">=</span>&#8220;<span style="color:#0000ff;">WebUI03.IoC.DIHttpModule, WebUI03</span>&#8220;<span style="color:#0000ff;"> /&gt;</span></li>
<li><span style="color:#0000ff;">    &lt;/</span><span style="color:#a31515;">httpModules</span><span style="color:#0000ff;">&gt;</span></li>
</ol>
</div>
</div>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h6>ขั้นที่ 4  ทดสอบเรียกใช้งาน BLL ด้วย ICustomerService</h6>
<p><span style="color:#0000ff;"><span style="color:#000000;">หลังจากที่ได้ตั้งค่าและสร้าง Helper ในส่วนของ DI กันเสร็จแล้ว คราวนี้เราก็มาใช้งานกันได้แล้วครับ โดยแก้ไขหน้า default.aspx ออกมาประมาณนี้</span></span></p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image27.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb26.png?w=558&#038;h=302" alt="image" width="558" height="302" border="0" /></a></p>
<p><span style="color:#0000ff;"><span style="color:#000000;">และเขียนโค้ดไว้ด้านหลังแบบนี้</span></span></p>
<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:a7026781-17fa-440f-8058-3f3daf17ad24" class="wlWriterEditableSmartContent" style="display:inline;float:none;margin:0;padding:0;">
<div style="border:#000080 1px solid;color:#000;font-family:'Courier New', Courier, Monospace;font-size:10pt;">
<div style="background:#000080;color:#fff;font-family:Verdana, Tahoma, Arial, sans-serif;font-weight:bold;padding:2px 5px;">Code Snippet</div>
<div style="background:#ddd;overflow:auto;">
<ol style="background:#ffffff;margin:0 0 0 2.5em;padding:0 0 0 5px;">
<li><span style="color:#0000ff;">using</span> System;</li>
<li style="background:#f3f3f3;"><span style="color:#0000ff;">using</span> Domains03;</li>
<li><span style="color:#0000ff;">using</span> Microsoft.Practices.Unity;</li>
<li style="background:#f3f3f3;"></li>
<li><span style="color:#0000ff;">namespace</span> WebUI03</li>
<li style="background:#f3f3f3;">{</li>
<li>    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">partial</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">_Default</span> : System.Web.UI.<span style="color:#2b91af;">Page</span></li>
<li style="background:#f3f3f3;">    {</li>
<li>        [<span style="color:#2b91af;">Dependency</span>]</li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">public</span> <span style="color:#2b91af;">ICustomerService</span> custSvc { <span style="color:#0000ff;">get</span>; <span style="color:#0000ff;">set</span>; }</li>
<li></li>
<li style="background:#f3f3f3;">        <span style="color:#0000ff;">protected</span> <span style="color:#0000ff;">void</span> Button1_Click(<span style="color:#0000ff;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</li>
<li>        {</li>
<li style="background:#f3f3f3;">            <span style="color:#0000ff;">var</span> cust = custSvc.GetCustomer(txtCustId.Text);</li>
<li>            <span style="color:#0000ff;">if</span> (cust == <span style="color:#0000ff;">null</span>)</li>
<li style="background:#f3f3f3;">            {</li>
<li>                lbcustid.BackColor = System.Drawing.<span style="color:#2b91af;">Color</span>.Red;</li>
<li style="background:#f3f3f3;">                <span style="color:#0000ff;">return</span>;</li>
<li>            }</li>
<li style="background:#f3f3f3;">            lbcustid.Text = cust.CustId;</li>
<li>            lbfname.Text = cust.FName ?? <span style="color:#a31515;">&#8220;not found&#8221;</span>;</li>
<li style="background:#f3f3f3;">            lblname.Text = cust.LName ?? <span style="color:#a31515;">&#8220;not found&#8221;</span>;</li>
<li>        }</li>
<li style="background:#f3f3f3;">    }</li>
<li>}</li>
</ol>
</div>
</div>
</div>
<p>&nbsp;</p>
<p>Line 9-10  เป็นการประกาศตัวแปรสำหรับรับ object ของ BLL เข้ามาโดยกำหนด attribute [Dependency] ไว้บนหัว property ICustomerService custSvc   เมื่อมีการเรียก page นี้ให้ทำงาน  เจ้า DIHttpModule ที่เราเขียนไว้จะมาตรวจจับ Dependency attribute และ set BLL object (BLL03.CustomerBLL) เข้ามาที่ property นี้</p>
<p>Line 14  เป็นการเรียกใช้ CustomerService เพื่อดึงข้อมูลผ่าน DAL อีกทีนึง</p>
<p><strong>ผลลัพธ์ที่ได้</strong></p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image28.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb27.png?w=600&#038;h=324" alt="image" width="600" height="324" border="0" /></a></p>
<h4>Conclusion</h4>
<p>หลังจากที่ได้ทดลองทำลองอ่านตามที่ผมนำเสนอไป หวังทุกท่านคงพอมองเห็นลู่ทางในการนำไปใช้งานกันต่อ เนื่องจากเจ้า DI นี้ช่วยเพิ่มความยืดหยุ่นให้ระบบของเราได้มากจริง ๆ อาจจะมีข้อแลกเปลี่ยนบ้างเช่น ระบบในตอน startup จะช้ากว่าปกติบ้าง และอาจจะต้องระวังเรื่องหน่วยความจำด้วย</p>
<p>สำหรับตอนนี้ผมเขียนไปยาวมาก จริงแล้วยังไม่จบ ยังไม่ได้พูดถึงเรื่องการทำ Testing ในแต่ละ layer และการ integrate กับ ASP.NET MVC อีกทั้งยังมี DI Framework ที่น่าสนใจจะมาแนะนำอีกหลายยี่ห้อ  ค่อนข้างยาวครับ แต่ผมขอจบตอนไว้แค่นี้ก่อน ไว้จะมาเขียนต่อในเรื่องที่ได้บอกไปข้างต้น  สวัสดีครับ</p>
<hr />
<p>&nbsp;</p>
<p><strong><a href="http://cid-dadd0b92d4b7b2a3.office.live.com/self.aspx/%E0%B8%AA%E0%B8%B2%E0%B8%98%E0%B8%B2%E0%B8%A3%E0%B8%93%E0%B8%B0/DependencyInjection%5E_sample01.zip" target="_blank">สามารถ download source code ได้ที่นี่</a></strong></p>
<p><strong><a href="http://cid-dadd0b92d4b7b2a3.office.live.com/self.aspx/%E0%B8%AA%E0%B8%B2%E0%B8%98%E0%B8%B2%E0%B8%A3%E0%B8%93%E0%B8%B0/DependencyInjection%5E_sample01.zip" target="_blank">Download Source Code Here</a></strong></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png"><img src="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png?w=143" alt="" border="0" /></a></p></blockquote>
<blockquote><p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Chalermpon Areepong Nine (นาย)</a></p>
<p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Microsoft MVP Thailand ASP.NET</a></p>
<p>email : nine_biz-talk.net <strong>at</strong> hotmail <strong>dot</strong> com</p></blockquote>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nine69.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nine69.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nine69.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nine69.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nine69.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nine69.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nine69.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nine69.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nine69.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nine69.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nine69.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nine69.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nine69.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nine69.wordpress.com/142/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=142&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nine69.wordpress.com/2011/02/21/dependencyinjection01/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/8c2f25a91e95ddd2e418090794711d24?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">nine69</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb4.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb16.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb14.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb6.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb7.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image21_thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image12_thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image16_thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb10.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb17.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb18.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb19.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb20.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb21.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb22.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb23.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb24.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb25.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb26.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb27.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png?w=143" medium="image" />
	</item>
		<item>
		<title>AutoMapper: Mapping Objects Utility</title>
		<link>http://nine69.wordpress.com/2011/01/30/automapper-mapping-objects-utility/</link>
		<comments>http://nine69.wordpress.com/2011/01/30/automapper-mapping-objects-utility/#comments</comments>
		<pubDate>Sun, 30 Jan 2011 11:05:50 +0000</pubDate>
		<dc:creator>Nine MVP ASP.NET</dc:creator>
				<category><![CDATA[Design Pattern]]></category>
		<category><![CDATA[AutoMapper]]></category>
		<category><![CDATA[DTO]]></category>

		<guid isPermaLink="false">https://nine69.wordpress.com/?p=112</guid>
		<description><![CDATA[Programming Level: Intermediate – Advance Computer Skills: Object Oriented Programming, Design Pattern C# 3.0, LINQ Development Tool and Library Visual Studio 2010 SP1 or later AutoMapper 1.1 (download here) Introduce: ห่างหายไปนานกับการเขียนบทความออนไลน์&#160;&#160; วันนี้มีไลบราลี่ตัวนึงมาแนะนำซึ่งมีประโยชน์มากๆ สำหรับชาว OO Programming ที่นิยมใช้ DTO (data transfer object) ซึ่งปัญหาของการใช้ DTO นั้นคือต้องมานั่งเขียนโค้ดส่งค่าทีละ property ซึ่งค่อนข้างที่จะลำบากหากวันนึงมีการเปลี่ยนแปลงชื่อของ property เราก็ต้องมานั่งแก้โค้ดให้ตรงกันกับที่แก้ไขไป&#160; และไม่ค่อยจะยืดหยุ่นเนื่องจาก map ที่สร้างขึ้นไม่สามารถแก้ไขเปลี่ยนแปลงได้อิสระ&#160; สิ่งต่าง ๆ เหล่านี้ได้มีผู้ผลิตไลบราลี่ออกมาแจกจ่ายให้ใช้งานกัน แต่ก็ยังไม่ตรงกับที่ต้องการ&#160; จนกระทั่ง [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=112&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h4>Programming Level:</h4>
<ul>
<li>Intermediate – Advance </li>
</ul>
<h4>Computer Skills:</h4>
<ol>
<li>Object Oriented Programming, Design Pattern </li>
<li>C# 3.0, LINQ </li>
</ol>
<h4>Development Tool and Library</h4>
<ol>
<li>Visual Studio 2010 SP1 or later </li>
<li>AutoMapper 1.1 (<a href="http://automapper.codeplex.com/releases/view/44802#DownloadId=120555" target="_blank">download here</a>)</li>
</ol>
<h4>Introduce:</h4>
<p><font color="#000000">ห่างหายไปนานกับการเขียนบทความออนไลน์&#160;&#160; วันนี้มีไลบราลี่ตัวนึงมาแนะนำซึ่งมีประโยชน์มากๆ สำหรับชาว OO Programming ที่นิยมใช้ DTO (data transfer object) ซึ่งปัญหาของการใช้ DTO นั้นคือต้องมานั่งเขียนโค้ดส่งค่าทีละ property ซึ่งค่อนข้างที่จะลำบากหากวันนึงมีการเปลี่ยนแปลงชื่อของ property เราก็ต้องมานั่งแก้โค้ดให้ตรงกันกับที่แก้ไขไป&#160; และไม่ค่อยจะยืดหยุ่นเนื่องจาก map ที่สร้างขึ้นไม่สามารถแก้ไขเปลี่ยนแปลงได้อิสระ&#160; </font><font color="#000000">สิ่งต่าง ๆ เหล่านี้ได้มีผู้ผลิตไลบราลี่ออกมาแจกจ่ายให้ใช้งานกัน แต่ก็ยังไม่ตรงกับที่ต้องการ&#160; </font><font color="#000000">จนกระทั่ง </font><font color="#000000">jimmy bogard เป็นผู้ริเริ่มโปรเจ็ก Automapper ขึ้นใน CodePlex ผมได้ทดลองเล่นตอนที่ยังเป็น Beta version เห็นว่าน่าสนใจจึงเริ่มศึกษาเพื่อใช้งานอย่างจริงจัง&#160;&#160; หลังจากที่ได้ใช้งานในระบบงานจริง ๆ ปรากฎว่าใช้งานได้ดีและลดเวลาในการพัฒนางานไปได้ส่วนนึง จึงได้สรุปมาเป็นบทความตอนนี้</font></p>
<p>&#160;</p>
<h4>Basic AutoMapper &#8211; แนะนำเม็ธธอดที่ใช้บ่อยและสิ่งที่ควรรู้</h4>
<p>1. AutoMapper.Mapper.CreateMap() เป็นการสร้างแม๊พระหว่าง type ที่ต้องการจะทำการแม๊พค่ากัน โดยมี source type และ destination type โดยมีให้ใช้ทั้ง Generic Method และ Parameter Method มีให้ใช้หลายโอเวอร์โหลด</p>
<blockquote><p>Mapper.CreateMap&lt;class1, class2&gt;();</p>
<p>Mapper.CreateMap(typeof(class1), typeof(class2));</p>
</blockquote>
<p>&#160;</p>
<p>2. AutoMapper.Mapper.Reset() เป็นเม็ธธอดที่ใช้ในการล้างค่า config ที่เคยได้สร้างไว้ก่อนหน้านี้</p>
<p>3. AutoMapper.Mapper.Map() เป็นเม็ธธอดที่ใช้ในการรับ source object เข้าไปแม๊พและรีเทิร์น target object ที่ต้องการออกมา โดยมีให้ใช้ทั้ง Generic Method และ Parameter Method มีให้ใช้หลายโอเวอร์โหลดครับ</p>
<blockquote><p>var objClass2 = Mapper.Map&lt;class1, class2&gt;(srcClass1);</p>
<p>var objClass2 = Mapper.Map(srcClass1, typeof(class1), typeof(class2));</p>
</blockquote>
<p>&#160;</p>
<p>4. AutoMapper.Mapper.DynamicMap() คือเม็ธธอดที่รองรับการแม๊พค่ากับกลุ่ม anonymous object</p>
<p>5. ในด้าน Performance ของ AutoMapper นั้นเป็นข้อที่ต้องพิจารณาให้มาก เนื่องจาก AutoMapper ช้ากว่า Manual Map อยู่ประมาณ 7 เท่า เพราะหากมีจำนวน object collection จำนวนมาก ๆ จะทำให้ระบบทำงานช้าลง&#160; </p>
<p>ปล. ในรุ่นถัดไปทางทีมงานจะปรับปรุงประสิทธิภาพการทำงานไปใช้ Parallel Library ของ .NET ซึ่งจะทำให้ performance ดีขึ้น</p>
<p>&#160;</p>
<h4>6 Demo:</h4>
<p>มาดูวิธีการใช้งานกันครับ ว่าการใช้งาน AutoMapper ว่าลดเวลางานการพัฒนา และช่วยให้ระบบของเรายืดหยุ่นได้ยังไง&#160; โดยจะขออธิบายการทำงานที่เป็นพื้นฐานและใช้งานกันบ่อย ๆ </p>
<p>&#160;</p>
<p><strong>DEMO 1:&#160; Simple Type + Nested Type Mapping </strong></p>
<p><font><font color="#000000">ต้องการส่งค่าจาก Person (Domain) ไปยัง PersonDTO และมี Nested Type เป็น Address class โดยมีโครงสร้างและชื่อ property เหมือนกัน</font></font></p>
<blockquote><p><em><font color="#008000">//Domain Class</font>         <br />public class Person         <br />{         <br />&#160;&#160;&#160; public string Name { get; set; }         <br />&#160;&#160;&#160; public int Age { get; set; }         <br />&#160;&#160;&#160; public Address Address { get; set; }         <br />}         <br />public class Address         <br />{         <br />&#160;&#160;&#160; public string Road { get; set; }         <br />&#160;&#160;&#160; public string State { get; set; }         <br />&#160;&#160;&#160; public string Postcode { get; set; }         <br />&#160;&#160;&#160; public string Country { get; set; }         <br />}</em></p>
<p><em><font color="#008000">// DTO&#160; Class</font>         <br />public class PersonDTO         <br />{         <br />&#160;&#160;&#160; public string Name { get; set; }         <br />&#160;&#160;&#160; public int Age { get; set; }         <br />&#160;&#160;&#160; public AddressDTO Address { get; set; }         <br />}         <br />public class AddressDTO         <br />{         <br />&#160;&#160;&#160; public string Road { get; set; }         <br />&#160;&#160;&#160; public string State { get; set; }         <br />&#160;&#160;&#160; public string Postcode { get; set; }         <br />&#160;&#160;&#160; public string Country { get; set; }         <br />}         <br /></em></p>
</blockquote>
<p><strong>&#160;</strong>&#160; 1.1. กรณีเขียนโค้ดส่งค่าเอง (Manual Mapping) จะเห็นได้ว่าต้องกำหนดค่าเองทุก property</p>
<blockquote><p><em><font color="#008000">//สร้าง object person และกำหนดค่า</font>         <br />var objPerson = new Person         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Name = &quot;Calos Santana&quot;,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Age = 53,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Address = new Address         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Road = &quot;Platoo&quot;,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; State = &quot;CA&quot;,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Postcode = &quot;11000&quot;,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Country = &quot;USA&quot;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; };</em></p>
<p><em><font color="#008000">//ทำการ map ค่าจาก objPerson -&gt; dtoPerson ด้วย object initializer (c# 3.0 feature)</font>         <br />var personDto = new PersonDTO         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Name = objPerson.Name,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Age = objPerson.Age,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Address = new AddressDTO         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Road = objPerson.Address.Road,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; State = objPerson.Address.State,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Postcode = objPerson.Address.Postcode,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Country = objPerson.Address.Country         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; };</em></p>
</blockquote>
<p>&#160;&#160; 1.2. กรณีใช้งาน AutoMapper:</p>
<blockquote><p><em><font color="#008000">//config บอกว่า class Person จะ map ไปยัง PersonDTO</font>         <br />AutoMapper.Mapper.CreateMap&lt;Person, PersonDTO&gt;();         <br /><font color="#008000">//config Nested Type บอกว่า class Address จะ map ไปยัง AddressDTO</font>         <br />AutoMapper.Mapper.CreateMap&lt;Address, AddressDTO&gt;();         <br />&#160; <br /><font color="#008000">// Map value โดยใช้ AutoMapper</font>         <br />var dtoPerson =<font color="#000000"> <strong>AutoMapper.Mapper.Map&lt;Person, PersonDTO&gt;(objPerson);            <br /></strong></font></em></p>
</blockquote>
<p><strong></strong></p>
<p><strong>วิเคราะห์โค้ดจาก Demo 1 :</strong>&#160; </p>
<p>การ map ค่าจะสั่งให้ AutoMapper รู้ว่า Class ใด Map เข้ากับ Class ใดด้วยการใช้ CreateMap Method และการ map ค่านั้นสามารถสั่งได้ด้วย 3 บรรทัดดังที่เห็นในตัวอย่าง&#160; </p>
<p>&#160;</p>
<hr />
<p><strong>DEMO 2: Collection Mapping </strong></p>
<p>เป็นการแม๊พคลาสกลุ่มที่เป็น Array, List&lt;T&gt; ไปมาระหว่างกัน</p>
<p>มาดูโดเมนคลาสที่มีดังนี้ Person จะมี Address เป็น List&lt;T&gt; ซึ่งเป็น collection ประเภทหนึ่ง</p>
<blockquote><p><em><font color="#008000">//Domain Class</font>         <br />public class Person         <br />{         <br />&#160;&#160; public string Name { get; set; }         <br />&#160;&#160; public int Age { get; set; }         <br />&#160;&#160; public List&lt;Address&gt; Addresses { get; set; }         <br />}         <br />public class Address         <br />{         <br />&#160;&#160; public string Road { get; set; }         <br />&#160;&#160; public string State { get; set; }         <br />&#160;&#160; public string PostCode { get; set; }         <br />&#160;&#160; public string Country { get; set; }         <br />}         <br /></em></p>
</blockquote>
<p>และเราก็มี DTO Class ที่มีโครงสร้างเหมือนกันกับ Domain Class ดังนี้</p>
<blockquote><p><em><font color="#008000">// DTO&#160; Class</font>         <br />public class PersonDTO         <br />{         <br />&#160;&#160; public string Name { get; set; }         <br />&#160;&#160; public int Age { get; set; }         <br />&#160;&#160; public List&lt;AddressDTO&gt; Addresses { get; set; }         <br />}         <br />public class AddressDTO         <br />{         <br />&#160;&#160; public string Road { get; set; }         <br />&#160;&#160; public string State { get; set; }         <br />&#160;&#160; public string PostCode { get; set; }         <br />&#160;&#160; public string Country { get; set; }         <br />}</em></p>
</blockquote>
<p>ใช้ AutoMapper แม๊พค่า Collection</p>
<blockquote><p><em><font color="#008000">//ดึง persons list object collectionขึ้นมา</font>         <br />List&lt;Person&gt; lsPersons = GetPersons();         <br /><font color="#008000">//แปลง list ไปเป็น array object เพือใช้ทดสอบ</font>         <br />Person[] arPersons = lsPersons.ToArray();         </p>
<p><font color="#008000">//Config Mapper ให้รู้จัก Soruce Type และ Target Type</font>         <br />Mapper.CreateMap&lt;Person, PersonDTO&gt;();         <br />Mapper.CreateMap&lt;Address, AddressDTO&gt;();         </p>
<p><font color="#008000">//สั่งแม๊พค่า lsPersons List Object ไปเป็น lsPersonDto List Object</font>         <br />var lsPersonDto = Mapper.Map&lt;<strong><font color="#9b00d3">List&lt;Person&gt;, List&lt;PersonDTO&gt;</font></strong>&gt;(lsPersons);         <br /><font color="#008000">//สั่งแม๊พค่า arPersons array object ไปเป็น arPersonDto array Object</font>         <br />var arPersonDto = Mapper.Map&lt;<font color="#9b00d3"><strong>Person[], PersonDTO[]</strong></font>&gt;(arPersons);</em></p>
</blockquote>
<p><strong>วิเคราะห์โค้ดจาก Demo 2:</strong></p>
<p>จะเห็นได้ว่าโค้ดส่วนที่ได้ทำ Hilight ไว้นั้น จะเป็นส่วนที่บอกให้ AutoMapper รู้ว่า Source และ Target ที่ต้องการจะแม๊พค่า ณ ตอนนั้นเป็น Collection ประเภทใด และเรายังสามารถแม๊พค่าจาก List –&gt; Array ได้เนื่องจาก implement IEnumerable เหมือนกัน</p>
<p>&#160;</p>
<hr />
<p><font color="#000000"><strong>DEMO 3: Custom Mapping </strong></font></p>
<p><font color="#000000">คือการสร้างแม๊พขึ้นเองในกรณีที่ source class กับ target class นั้นมีความแตกต่างกันมาก ไม่ว่าจะเป็น Property Name/Type&#160; ที่ต่างกัน</font></p>
<blockquote><p><em><font color="#008000">//Domain Class</font>         <br />public class Person         <br />{         <br />&#160;&#160; public string Name { get; set; }         <br />&#160;&#160; public int Age { get; set; }</em></p>
<p><em>&#160;&#160; <font color="#9b00d3">public <strong>DateTime</strong> Birthdate { get ;set; }</font> <font color="#008000">// Birthdate แบบ DateTime</font>         <br /><font color="#9b00d3">&#160;&#160; public <strong>Address</strong> Address { get; set; } </font></em><em><font color="#008000">// Address แบบ class          <br /></font>}         <br />public class Address         <br />{         <br />&#160;&#160; public string Road { get; set; }         <br />&#160;&#160; public string State { get; set; }         <br />&#160;&#160; public string Postcode { get; set; }         <br />&#160;&#160; public string Country { get; set; }         <br />}         <br /></em></p>
</blockquote>
<p>ในส่วนของ dto class จะมีโครงสร้างแตกต่างกับ domain class คือมี property Birthdate และ Address เป็น Type แบบ string </p>
<blockquote><p><em><font color="#008000">// DTO&#160; Class</font>         <br />public class PersonDTO         <br />{         <br />&#160;&#160; public string Name { get; set; }         <br />&#160;&#160; public int Age { get; set; }</em></p>
<p><em><font color="#0000ff">&#160;&#160; public <strong>string</strong> Birthdate { </font><em></em><font color="#0000ff">get; set; } </font><font color="#008000">// Birthdate แบบ string</font>         <br /><font color="#0000ff">&#160;&#160; public <strong>string</strong> Address { get; set; } </font></em><em><font color="#008000">// Address แบบ string          <br /></font>}         <br /></em></p>
</blockquote>
<p><strong>วิธีแรกใช้ ForMember() Method :&#160; </strong></p>
<p>สำหรับ ForMember() method เป็น fluent syntax ที่ช่วยให้เรากำหนดค่าให้แก่ property ปลายทางที่ต้องการได้ และในตัวอย่างนี้ผมแสดงให้เห็นว่าเราต้องการแม๊พค่าจาก </p>
<p>Person.Birthdate (DateTime) –&gt; PersonDTO.Birthdate (string) โดยการใช้ DateTime.ToString() และ </p>
<p>Person.Address (class) –&gt; PersonDTO.Address (string) โดยการใช้ string.format(format string, object) ดังตัวอย่างด้านล่าง</p>
<blockquote><p><em><font color="#008000">//Config บอกว่า classs Person จะ map ไปยัง PersonDTO และกำหนด custom mapping          <br /></font>Mapper.CreateMap&lt;Person, PersonDTO&gt;()         <br />&#160; <font color="#c0504d">.ForMember(dest =&gt; dest.Birthdate, opt =&gt; opt.MapFrom(&#160; <br />&#160;&#160;&#160;&#160;&#160; src =&gt; src.Birthdate.ToShortDateString()))           <br /></font>&#160;&#160; <font color="#0000ff">.ForMember(dest =&gt; dest.Address, opt =&gt; opt.MapFrom(</font></em><em><font color="#0000ff"> src =&gt; string.Format(&quot;{0} {1} {2} {3}&quot;, src.Address.Road, src.Address.State,&#160;&#160;&#160;&#160;&#160;&#160; src.Address.Postcode, src.Address.Country)));</font></em></p>
<p><em><font color="#008000"></font></em></p>
<p><em><font color="#008000">// Map value โดยใช้ AutoMapper</font>         <br />var dtoPerson = AutoMapper.Mapper.Map&lt;Person, PersonDTO&gt;(objPerson);         <br /></em></p>
</blockquote>
<p><strong></strong></p>
<p><strong>วิธีที่สองคือใช้ TypeConverter&lt;TSource, TTarget&gt; abstract class</strong></p>
<p>สำหรับการใช้ TypeConverter นั้นเป็นการ override method ที่ชื่อ ConvertCore และ return Type เป็น TTarget ดังนี้</p>
<blockquote><p><em><font color="#008000">//Custom mapping Person -&gt; PersonDTO </font>        <br />public class PersonToDtoConverter : TypeConverter&lt;Person, PersonDTO&gt;         <br />{         <br />&#160;&#160; protected override PersonDTO ConvertCore(Person source)         <br />&#160;&#160; {         <br />&#160;&#160;&#160;&#160;&#160; return new PersonDTO         <br />&#160;&#160;&#160;&#160;&#160; {         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Name = source.Name,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Age = source.Age,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Birthdate = source.Birthdate.ToShortDateString(), <font color="#008000">// DateTime -&gt; String          <br /></font>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Address = string.Format(&quot;{0} {1} {2} {3}&quot;,&#160;&#160;&#160;&#160;&#160;&#160;&#160; <font color="#008000">// Class –&gt; String          <br /></font>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; source.Address.Road, source.Address.State,         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; source.Address.Postcode, source.Address.Country)         <br />&#160;&#160;&#160;&#160;&#160; };         <br />&#160;&#160;&#160; }         <br />}</em></p>
</blockquote>
<p>นำ PersonToDtoCoverter ไปใช้งานใน Map ดังนี้</p>
<blockquote><p><em><font color="#008000">//สร้าง object person และกำหนดค่า</font>         <br />var objPerson = new Person         <br />{         <br />&#160;&#160; Name = &quot;Calos Santana&quot;,         <br />&#160;&#160; Age = 53,&#160; Birthdate = DateTime.Now,         <br />&#160;&#160; Address = new Address         <br />&#160;&#160; {         <br />&#160;&#160;&#160;&#160;&#160; Road = &quot;Platoo&quot;, State = &quot;CA&quot;,         <br />&#160;&#160;&#160;&#160;&#160; Postcode = &quot;11000&quot;, Country = &quot;USA&quot;         <br />&#160;&#160;&#160; }         <br />};         <br />&#160; <br /><font color="#008000">//บอก mapping ชุดนี้ว่าให้ใช้ PersonToDtoConverter ที่เราสร้างขึ้น</font>         <br />Mapper.CreateMap&lt;Person, PersonDTO&gt;()<font color="#9b00d3"><strong>.ConvertUsing&lt;<font color="#0000ff">PersonToDtoConverter</font>&gt;();</strong>           <br /></font>var personDto = AutoMapper.Mapper.Map&lt;Person, PersonDTO&gt;(objPerson);</em></p>
</blockquote>
<p>&#160;</p>
<p><strong>ผลลัพธ์ของ custom mapping ทั้งสองวิธีของ personDto ตามภาพด้านล่างนี้</strong></p>
<p><a href="http://nine69.files.wordpress.com/2011/01/image.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/01/image_thumb.png?w=244&#038;h=87" width="244" height="87" /></a></p>
<p>&#160;</p>
<p>&#160;</p>
<hr />
<p><strong>DEMO 4: Flattening Mapping</strong> </p>
<p>คือการทำ value ของ nested class ให้ขึ้นมาอยู่ใน level เดียวกับ root class </p>
<p>จากโดเมนคลาสที่เห็นข้างล่างนี้จะมี nested class ที่ชื่อ Address</p>
<blockquote><p><em><font color="#008000">//Domail Class</font>         <br />public class Person         <br />{         <br />&#160;&#160; public string Name { get; set; }         <br />&#160;&#160; public Address Address { get; set; }         <br />}         <br />public class <font color="#9b00d3">Address</font>         <br />{         <br />&#160;&#160; public string <font color="#ff0000">Detail</font> { get; set; }         <br />&#160;&#160; public string <font color="#ff0000">Country</font> { get; set; }         <br />}</em></p>
</blockquote>
<p>มาดูการสร้าง DTO โดยใน PersonDetail Class ให้สร้าง property โดยใช้ชื่อ class name + property name ของ Domain Class มาสร้างดังนี้</p>
<blockquote><p><em><font color="#008000">//DTO Class          <br /></font>public class PersonDetail         <br />{         <br />&#160;&#160; public string Name { get; set; }         <br /></em><em><strong>&#160;&#160; public string <font color="#9b00d3">Address</font><font color="#ff0000">Detail</font> { get; set; } <font color="#008000">// flatten Address.Detail            <br /></font>&#160;&#160; public string <font color="#9b00d3">Address</font><font color="#ff0000">Country</font> { get; set; } <font color="#008000">// flatten Address.Country            <br /></font></strong>}</em></p>
</blockquote>
<p>จากนั้นทดลอง Map ค่าดูด้วยโค้ดด้านล่างนี้</p>
<blockquote><p><em>var person = new Person        <br />{         <br />&#160;&#160; Name = &quot;A la cart&quot;,         <br />Address = new Address         <br />&#160;&#160; {         <br />&#160;&#160;&#160;&#160;&#160; Detail = &quot;602 sukumwit road, bangkok 10110&quot;,         <br />&#160;&#160;&#160;&#160;&#160; Country = &quot;Thailand&quot;         <br />&#160;&#160; }         <br />};         </p>
<p>Mapper.CreateMap&lt;Person, PersonDetail&gt;();         <br />var dtoPersonDetail = Mapper.Map&lt;Person, PersonDetail&gt;(person);</em></p>
</blockquote>
<p>ผลลัพธ์ได้ค่าออกมาตามภาพด้านล่างนี้</p>
<p><a href="http://nine69.files.wordpress.com/2011/01/image1.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/01/image_thumb1.png?w=338&#038;h=72" width="338" height="72" /></a></p>
<p>&#160;</p>
<p>&#160;</p>
<hr />
<p><font color="#000000"><strong>DEMO 5: Interface Mapping</strong></font></p>
<p><font color="#000000">เป็นที่ทราบการว่าประโยชน์ของการใช้งาน Interface ช่วยลดการยึดเกาะของ implementation ในแต่ละส่วนออกจากกัน (loosely couple) ดังนั้นจึงมีความสามารถในการแม๊พ เช่นการแม๊พ object ไปเป็น Interface โดยที่ Class นั้นไม่ต้อง implement interface มาดูกันครับ</font></p>
<blockquote><p><em><font color="#008000">// domain class&#160; <br /></font>public class Customer         <br />{         <br />&#160;&#160; public string Code { get; set; }         <br />&#160;&#160; public string Name { get; set; }         <br />}         <br />&#160; <br /><font color="#008000">// interface&#160; <br /></font>public interface ICustomerService         <br />{         <br />&#160;&#160; string Code { get; set; }         <br />&#160;&#160; string Name { get; set; }         <br />}</em></p>
</blockquote>
<p>จากนั้นมาลองดูโค้ดกัน</p>
<blockquote><p><font color="#008000">//สร้าง cust object        <br /></font>var cust = new Customer() { Code = &quot;102&quot;, Name = &quot;John Mayer&quot;};       <br />&#160; <br /><font color="#008000">//กำหนด cust mapping ไปยัง interface        <br /></font>Mapper.CreateMap&lt;Customer, ICustomerService&gt;();       <br />&#160; <br /><font color="#008000">//สั่งให้ map ค่าไปยัง interface        <br /></font>var icustsvc = Mapper.Map&lt;Customer, ICustomerService&gt;(cust);       </p>
</blockquote>
<p>&#160;</p>
<p>ผลลัพธ์หลังการรันจะเห็นได้ตามภาพด้านล่างนี้ เห็นได้ว่า AutoMapper ได้สร้าง dynamic proxy ขึ้นมาสำหรับคืนค่ากลับไปให้ icussvc ที่เป็น interface </p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb.png?w=462&#038;h=71" width="462" height="71" /></a></p>
<p>&#160;</p>
<p>&#160;</p>
<hr />
<p><strong><font color="#000000">DEMO 6: Dynamic Mapping </font></strong></p>
<p><font color="#000000">เป็นการแม๊พค่าอ๊อบเจ็คที่เป็น anonymous type ไปยัง strong typed มีอยู่หลายวิธีและรูปแบบการทำงานด้งนี้</font></p>
<p><font color="#000000"><strong>Anonymous Type Mapping</strong></font></p>
<p><font color="#000000">มาดูโมเดลสำหรับเทสกันครับ ผมประกาศไว้ทั้ง class และ interface มีโครงสร้างเหมือนกันดังนี้</font></p>
<blockquote><p><em><font color="#008000">// domain class </font>        <br />public class Customer        <br />{        <br />&#160;&#160; public string Code { get; set; }        <br />&#160;&#160; public string Name { get; set; }        <br />}        </p>
<p><font color="#008000">// domain interface </font>        <br />public interface ICustomerService        <br />{        <br />&#160;&#160; string Code { get; set; }        <br />&#160;&#160; string Name { get; set; }        <br />}</em></p>
</blockquote>
<p><font color="#000000">จากนั้นผมได้สร้าง anonymous type ด้วย code line นี้ ให้มี property เหมือนกัน</font></p>
<blockquote><p><font color="#008000">// create anonymous type object       <br /></font>var cust = new {Code = &quot;C001&quot;, Name = &quot;Anderson&quot;};</p>
</blockquote>
<p><font color="#000000">จากนั้นก็สั่ง map ข้อมูล โดยใช้ class และ interface เข้าไปแม๊พค่าจาก cust anonymous object ดังนี้</font></p>
<blockquote><p><em><font color="#008000">// call dynamic map to Customer Class</font>        <br />var res1 = Mapper.DynamicMap&lt;Customer&gt;(cust);        <br /><font color="#008000">// call dynamic map tp ICustomerService interface</font>        <br />var res2 = Mapper.DynamicMap&lt;ICustomerService&gt;(cust);</em></p>
</blockquote>
<p><font color="#000000">มาดู output ของตัวแปร res1, res2 กันครับ</font></p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image1.png"><img style="background-image:none;border-bottom:0;border-left:0;padding-left:0;padding-right:0;display:inline;border-top:0;border-right:0;padding-top:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb1.png?w=189&#038;h=54" width="189" height="54" /></a>&#160; <a href="http://nine69.files.wordpress.com/2011/02/image2.png"><img style="background-image:none;border-bottom:0;border-left:0;padding-left:0;padding-right:0;display:inline;border-top:0;border-right:0;padding-top:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb2.png?w=244&#038;h=49" width="244" height="49" /></a></p>
<p>&#160;</p>
<p><font color="#000000"><strong>IQueryable Anonymous Type Mapping</strong></font></p>
<p><font color="#000000">หนีไม่พ้นกันกับ interface ตัวนี้ครับ เนื่องจากเราเขียนโปรแกรมกับ LINQ ดังนั้น มาดููวิธีการกันครับ</font></p>
<p><font color="#000000">ผมมี Domain Class ดังนี้ครับ</font></p>
<blockquote><p><em><font color="#008000">//Domain Class</font>         <br />public class Person         <br />{         <br />&#160;&#160;&#160; public string Name { get; set; }         <br />&#160;&#160;&#160; public int Age { get; set; } public DateTime Birthdate&#160; {get; set; }        <br />&#160;&#160;&#160; public Address Address { get; set; }         <br />}         <br />public class Address         <br />{         <br />&#160;&#160;&#160; public string Road { get; set; }         <br />&#160;&#160;&#160; public string State { get; set; }         <br />&#160;&#160;&#160; public string Postcode { get; set; }         <br />&#160;&#160;&#160; public string Country { get; set; }         <br />}</em></p>
</blockquote>
<p><font color="#000000">ผมสร้าง DTO class ไว้ตามนี้</font></p>
<blockquote><p><em><font color="#008000">//DTO class         <br /></font>public class CustomerInfo        <br />{        <br />&#160;&#160; public string Info1 { get; set; }        <br />&#160;&#160; public string Info2 { get; set; }        <br />&#160;&#160; public string Info3 { get; set; }        <br />}</em></p>
</blockquote>
<p>และผมมี Mapping Helper Method ไว้ช่วยทำการแม๊พค่าจาก IQueryable ดังนี้</p>
<blockquote><p><em>//       <br />public static List&lt;T&gt; MapDynamicType&lt;T&gt;(IQueryable query) where T : class        <br />{        <br />&#160;&#160; var output = new List&lt;T&gt;();        <br />&#160;&#160; var sourceType = query.GetType().GetGenericArguments()[0];        <br />&#160;&#160; var destType = output.GetType().GetGenericArguments()[0];        </p>
<p>&#160;&#160; foreach (var src in query)        <br />&#160;&#160; {        <br />&#160;&#160;&#160;&#160;&#160; var mySrc = Mapper.DynamicMap(src, src.GetType(), destType);        <br />&#160;&#160;&#160;&#160;&#160; output.Add(Mapper.DynamicMap&lt;T&gt;(mySrc));        <br />&#160;&#160; }        <br />&#160;&#160; return output;        <br />}</em></p>
</blockquote>
<p>จำลองสร้าง person เป็น list collection เอาไว้ ดสอบดังนี้</p>
<blockquote><p><font color="#008000">//สร้าง person list collection</font>      <br />var persons = new List&lt;Person&gt;();      </p>
<p><font color="#008000">//วนลูปสร้าง person object 10 ตัว</font>      <br />for (int i = 0; i &lt; 10; i++)      <br />{      <br />&#160;&#160; <font color="#008000">//สร้าง object person และกำหนดค่า</font>      <br />&#160;&#160; var objPerson = new Person      <br />&#160;&#160; {      <br />&#160;&#160;&#160;&#160;&#160; Name = &quot;Calos Santana&quot;+i,      <br />&#160;&#160;&#160;&#160;&#160; Age = 20+i,      <br />&#160;&#160;&#160;&#160;&#160; BirthDate = DateTime.Now.AddDays(i),      <br />&#160;&#160;&#160;&#160;&#160; Address = new Address      <br />&#160;&#160;&#160;&#160;&#160; {      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Road = &quot;Platoo&quot;+i,      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; State = &quot;CA&quot;+i,      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Postcode = &quot;1100&quot;+i,      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Country = &quot;USA&quot;+i      <br />&#160;&#160;&#160;&#160;&#160; }      <br />&#160;&#160; };      <br />&#160;&#160; persons.Add(objPerson);      <br />}      </p>
</blockquote>
<p>&#160;</p>
<p>จากนั้นทำการดึงข้อมูลให้ออกมาในรูป IQueryable Anonymous Type ดังนี้</p>
<blockquote><p><em><font color="#008000">//ใช้ LINQ ดึง person ออกมาในรูป anonymus type โดย return เป็น IQueryable</font>        <br />var query = from p in persons.AsQueryable()        <br />&#160;&#160; select new {        <br />&#160;&#160;&#160;&#160;&#160; Info1 = &quot;Name is &quot; + p.Name + &quot;, Age &quot; + p.Age,        <br />&#160;&#160;&#160;&#160;&#160; Info2 = &quot; Birthdate is &quot; + p.BirthDate.ToShortDateString(),        <br />&#160;&#160;&#160;&#160;&#160; Info3 = &quot; and Address &quot; + p.Address.Road + p.Address.State        <br />&#160;&#160;&#160;&#160; + p.Address.Postcode + p.Address.Country        <br />&#160;&#160;&#160; };</em></p>
</blockquote>
<p><font color="#000000">และสั่งให้แม๊พค่าดังนี้ โดยใช้ Helper medthod ที่สร้างไว้ดังนี้</font></p>
<blockquote><p><em>// ส่ง query ที่ได้เข้าไป map กับ CustomerInfo class       <br />var respx = MapDynamicType&lt;CustomerInfo&gt;(query);</em></p>
</blockquote>
<p><font color="#000000">ซึ่งจะได้ผลลัพธ์ดังนี้ครับ</font></p>
<p><a href="http://nine69.files.wordpress.com/2011/02/image3.png"><img style="background-image:none;border-bottom:0;border-left:0;padding-left:0;padding-right:0;display:inline;border-top:0;border-right:0;padding-top:0;" title="image" border="0" alt="image" src="http://nine69.files.wordpress.com/2011/02/image_thumb3.png?w=244&#038;h=190" width="244" height="190" /></a></p>
<p><font color="#000000"></font></p>
<p><font color="#000000"></font></p>
<h4>Conclusion</h4>
<p><font color="#000000">เราจะเห็นได้ว่าประโยชน์ของ AutoMapper นั้นมีค่อนข้างมากมาย เพียงแค่ให้รู้จักใช้และทดสอบดี ๆ เพื่อไม่ให้เกิด overhead ของการใช้งานมากเกินไป ไว้บทความหน้าผมจะนำ AutoMapper ไปใช้งานร่วมกับการทำ&#160; Application Architecture ครับ</font></p>
<p><font color="#000000"></font></p>
<p><font color="#000000"></font></p>
<p><font color="#000000"></font></p>
<p><font color="#000000"></font></p>
<p><font color="#000000"></font></p>
<p><font color="#000000"></font></p>
<p><font color="#000000"></font></p>
<p><font color="#000000"></font></p>
<p>&#160;</p>
<p>&#160;</p>
<p><strong></strong></p>
<hr />
<p><strong></strong></p>
<p><strong><a href="http://meohiq.blu.livefilestore.com/y1pKLP--67DDg3J4f8-py8vdDgcpd4q9nVeSdeYmyZsGTbGkEWatSq1zokIBiLxm0uZ3EXolPecO6enDBujCp78EnMWbUuNJoJs/AutoMapperDemo.zip?download&amp;psid=1" target="_blank">สามารถ download source code ได้ที่นี่</a></strong></p>
<p><strong><a href="http://meohiq.blu.livefilestore.com/y1pKLP--67DDg3J4f8-py8vdDgcpd4q9nVeSdeYmyZsGTbGkEWatSq1zokIBiLxm0uZ3EXolPecO6enDBujCp78EnMWbUuNJoJs/AutoMapperDemo.zip?download&amp;psid=1" target="_blank">Download Source Code Here</a></strong></p>
<p><strong></strong></p>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png"><img border="0" src="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png?w=143" /></a></p>
</blockquote>
<blockquote><p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Chalermpon Areepong Nine (นาย)</a></p>
<p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Microsoft MVP Thailand ASP.NET</a></p>
<p>email : nine_biz-talk.net <strong>at</strong> hotmail <strong>dot</strong> com</p>
</blockquote>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nine69.wordpress.com/112/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nine69.wordpress.com/112/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nine69.wordpress.com/112/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nine69.wordpress.com/112/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nine69.wordpress.com/112/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nine69.wordpress.com/112/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nine69.wordpress.com/112/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nine69.wordpress.com/112/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nine69.wordpress.com/112/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nine69.wordpress.com/112/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nine69.wordpress.com/112/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nine69.wordpress.com/112/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nine69.wordpress.com/112/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nine69.wordpress.com/112/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=112&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nine69.wordpress.com/2011/01/30/automapper-mapping-objects-utility/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/8c2f25a91e95ddd2e418090794711d24?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">nine69</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/01/image_thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/01/image_thumb1.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb1.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb2.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2011/02/image_thumb3.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2010/04/8dd414e86403ed9e654b180e0f6603951.png?w=143" medium="image" />
	</item>
		<item>
		<title>ASP.NET MVC Series I : Foundation of ASP.NET MVC</title>
		<link>http://nine69.wordpress.com/2010/06/04/asp-net-mvc-series-i-foundation-of-asp-net-mvc/</link>
		<comments>http://nine69.wordpress.com/2010/06/04/asp-net-mvc-series-i-foundation-of-asp-net-mvc/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 13:24:00 +0000</pubDate>
		<dc:creator>Nine MVP ASP.NET</dc:creator>
				<category><![CDATA[ASP.NET]]></category>

		<guid isPermaLink="false">http://nine69.wordpress.com/2010/06/04/asp-net-mvc-series-i-foundation-of-asp-net-mvc</guid>
		<description><![CDATA[ASP.NET MVC Series I : Foundation of ASP.NET MVC  ASP.NET MVC Series II : ASP.NET MVC Programming Next….. Developer Skills Intermediate Level Tools and Languages Visual Studio 2010 Ultimate RTM (MVC 2.0 RTM built-in)   or VS2008 SP1 with ASP.NET MVC 2.0 plug-in C#, OOP Articles Suggestion แนะนำบทความเรื่อง ASP.NET MVC ซึ่งผู้เขียนตั้งใจเขียนอ้างอิงกับ ASP.NET MVC v2.0 ตัวปัจจุบัน โดยเริ่มต้นกันแต่แรกไปจนจบเนื้อหาที่พอจะทยอยเขียนออกมาได้  [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=6&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div id="msgcns!DADD0B92D4B7B2A3!589" class="bvMsg">
<ul>
<li><strong>ASP.NET MVC Series I : Foundation of ASP.NET MVC</strong> 
<li>ASP.NET MVC Series II : ASP.NET MVC Programming Next…..</li>
</ul>
<h3><strong><font color="#0080ff">Developer Skills</font></strong></h3>
<ul>
<li>Intermediate Level</li>
</ul>
<h3><font color="#0080ff"><strong>Tools and Languages</strong></font></h3>
<ul>
<li>Visual Studio 2010 Ultimate RTM (MVC 2.0 RTM built-in)  
<li>or VS2008 SP1 with <a href="http://download.microsoft.com/download/7/B/1/7B11DE4E-0247-448E-8D39-7C9B12ABA1FF/AspNetMVC2_VS2008.exe" target="_blank">ASP.NET MVC 2.0 plug-in</a>
<li>C#, OOP </li>
</li>
</li>
</ul>
<h3><strong><font color="#0080ff">Articles Suggestion</font></strong></h3>
<p>แนะนำบทความเรื่อง ASP.NET MVC ซึ่งผู้เขียนตั้งใจเขียนอ้างอิงกับ ASP.NET MVC v2.0 ตัวปัจจุบัน โดยเริ่มต้นกันแต่แรกไปจนจบเนื้อหาที่พอจะทยอยเขียนออกมาได้  ในบทนี้จะแนะนำให้รู้จักกับ MVC Pattern และใช้งาน ASP.NET MVC 2.0 ในเบื้องต้น   และรวมไปถึงการเปรียบเทียบระหว่าง ASP.NET Web Form และ ASP.NET MVC เราควรจะเลือกใช้ตัวไหนในการพัฒนา</p>
<h3><strong><font color="#0080ff">Introduction</font></strong></h3>
<p>จะว่าไปแล้วเรากำลังศึกษาวิธีการเขียนโปรแกรมแบบโบราณอยู่ครับ    เพราะ MVC นั้นเป็นทั้ง Arichitectural Pattern และ Design Pattern ที่มีมานานมากสมัยปี คศ. 1979   โดยนาย Trygve Reenskaug พัฒนาตัวนี้ให้ smalltalks บน PARC   ซึ่งเท่าที่ผมศึกษาดูมาคร่าว ๆ ในแพลทฟอร์มอื่น  แทบทุกภาษาจะมี MVC Framework ไว้ให้ใช้    ฝั่ง Java คงไม่ต้องกล่าวถึงเพราะเป็นเจ้าแห่งการ implement pattern เกือบทั้งหมดที่มีอยู่ในโลกบวกกับที่คิดค้นใหม่และเติบโตขึ้น    ส่วนฝั่ง .NET เองก็พัฒนาต่อยอดมาเป็น MVP, MVVM, etc.  แม้กระทั้งภาษาอย่าง PHP ที่เป็น scriptlet ก็ยังมี MVC ให้ใช้กัน โอ้โฮ.. แบบนี้ MVC มันดียังไง แล้วทำไมทุก Platform ต้องมีเจ้านี่ไว้ในระบบ    ในบทความเรื่องนี้เราจะมาคุยกันครับ
<p>จากที่ผ่านมาหลาย ๆ ท่านคงคุ้นเคยกันดีใน Visual Studio  เมื่อกด double click ที่ control ต่าง ๆ แล้วจะสร้าง Event Click ให้ใน Code behind     สิ่งนี้นำพาโปรแกรมเมอร์ทั้งหลายไปทำงานภายใต้ Event ของคอนโทรล หลังจากได้ Click Event แล้ว  งานอะไรคิดอะไรได้ก็โค้ด ๆ เขียนใส่ลงไปทั้งหมด จะประกาศตัวแปร, จะติดต่อ Database, จะเรียก web service, จะวนลูปกี่ร้อยรอบ ทุกอย่างประดังลงไปใน Event Click   ดีหน่อยบางคนใส่ try catch ให้ด้วย    ซึ่งสิ่งที่ทำไปนี้โค้ดทั้งหมดจะไปฝังอยู่รวมกัน      ทำให้ชุดของโค้ดนั้นปนกันระหว่าง Presentation Logic,  Business Logic และ Data Access Logic     หากจะถามว่าผิดหรือไม่ก็คงตอบได้เต็มปากว่าไม่ผิดอะไรครับ เพราะตอบโจทย์ทางลูกค้าคือ งานสำเร็จและคุณรอดตัวได้งานในวันนี้    แต่ทั้งหมดนี้ไม่สามารถแยกแต่ละส่วนงานออกจากกันได้  แก้เพียงงานบางส่วน เช่น เปลี่ยนกฎการตรวจสอบ input data, แก้บิสเนสลอจิกให้ตรวจสอบเพิ่มเติม เป็นต้น ก็อาจจะกระทบทั้งโมดูล กลายเป็นต้อง retest ใหม่ทั้งหมด  และก็แปลได้ว่าทำงานได้คนเดียวและแบ่งงานกันยากลำบาก เพราะตัวระบบที่เขียนไว้นั้นผูกกันจนแน่นนั้นเอง<br />
<blockquote>
<p><a href="http://nine69.files.wordpress.com/2010/06/28a28075f007167d780df04c5e57d7cb.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/28a28075f007167d780df04c5e57d7cb.png?w=300" /></a>   รูปที่ 1.  3 Layered Architecture Diagram</p>
</blockquote>
<p>จากหลักการด้านบนหลายคนคงพูดว่า งั้นเราแบ่งชั้นของโค้ด (Layered Architecture) ก็ได้ ซึ่งการแบ่งโค้ดออกเป็นเลเยอร์นั้นเป็นการจำแนกโค้ดชุดที่มีความสัมพันธ์ทำหน้าที่เกี่ยวข้องกันไว้ในชั้นเดียวกัน  โดยแยกเป็น Presentation Layer –&gt; Business Logic Layer –&gt; Data Access Layer   ดังรูปที่ 1.  ด้านบน  วิธีนี้ก็ช่วยให้เราลดความสัมพันธ์ของโค้ดที่ยึดติดกันแน่นได้ในระดับนึง   แต่ก็ยังไม่มีเฟรมเวิร์กเข้ามาช่วยในการจัดการชั้น Presentation Layer แต่อย่างใด เนื่องจากการแบ่งกลุ่มโค้ดเป็นชั้น (Layer) นั้นเป็นการออกแบบโครงสร้างหลวม ๆ นั่นเอง   โดยทั้งนี้เราเองก็สามารถใช้ Web Form จัดการงานต่างๆ ใน Presentaion Layer ก็ได้   ซึ่งคล้ายกันสำหรับ MVC จะเป็นเฟรมเวิร์กเข้ามาจัดการในส่วนโครงสร้างของระบบให้เป็นระเบียบเช่นเดียวกับการทำเลเยอร์   และเราเองก็ยังสามารถใช้เลเยอร์เข้ามาผสมกับการใช้งาน MVC เพื่อสร้างความยืดหยุ่นได้อีกเช่นกัน ซึ่งจะอธิบายในบทความตอนต่อไป<br />
<h3><strong><font color="#0080ff">What’s The MVC Pattern</font></strong></h3>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/1245c6556fb057624bd4dada4601fcc0.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/1245c6556fb057624bd4dada4601fcc0.png?w=300" /></a>   รูปที่ 2.  Model View Control Diagram</p>
</blockquote>
<p><strong>MVC เป็นตัวย่อมาจาก Model / View / Control</strong>
<p><strong>Model</strong>  สำหรับโมเดลนั้นจะประกอบไปด้วยโครงสร้างคลาสข้อมูลของระบบธุรกิจ (Domain Business) เพื่อนำไปใช้งานใน View และ Controller  โดยความสัมพันธ์ระหว่าง View ก็คือการนำข้อมูลไปทำการ render หรือรับ input กลับเข้ามาในระบบ    และความสัมพันธ์ระหว่าง Controller คือเป็นโมเดลข้อมูล input/output สำหรับ Method ใน controller ไม่ว่าจะ Add/Edit/Delete/Detail  และส่งต่อให้ view เพื่อทำการ render อีกที (กรณีท่านที่ชอบ rich domain มักจะออกแบบ business logic และ Repository ไว้ทำงานที่โมเดล)     ในกรณีที่ระบบงานเล็กต้องการความเร็วในการพัฒนาก็ไม่จำเป็นต้องใช้ Model ก็ได้   อาจจะใช้ Controller ไปสั่งการเรียก Data Access Object  เพื่อส่งผลลัพธ์ที่อาจจะเป็น DataSet กลับไปยัง View ได้ตรง ๆ
<p><strong>View</strong> สำหรับวิวก็คือ User Interface ของระบบนั่นเอง ซึ่งการทำงานในส่วนของวิวนั้นจะอ้างถึงกล่องโมเดล โดยเพื่อทำการค้นหาและดึงข้อมูลขึ้นมาและแสดงข้อมูลออกมาในรูปแบบที่เราได้กำหนดไว้ในวิวนั้น ซึ่งวิวแต่ละวิวขึ้นอยู่กับ Controller จะเรียกใช้เพื่อ render การทำงาน ไม่ว่าจะเป็นวิวแบบ Add/Edit/Delete และ Detail  
<p><strong>Controller</strong> และสำหรับการทำงานของคอนโทรลเลอร์ เป็นเสมือนตัวกลางที่ทำงานระหว่างโมเดล (Model) และวิว (View)  ซึ่งเจ้าคอนโทรลเลอร์นี้เอง จะทำงานตามรีเควสจากผู้ใช้งาน ซึ่งจะรู้ว่าเมื่อมีการรีเควสโมเดลนี้ ต้องการคอนโทรลเลอร์ตัวไหน แอคชั่นอะไร ภายในแอคชั่นก็จะไปเรียก Model เพื่อทำงานตาม business อีกที จากนั้นเมื่อทำงานเสร็จเช่นการ Update หรือขอดู Detail ก็จะส่ง data ไปยัง view นั้น ๆ กลับไปแสดงผลพร้อมทั้งนำอ๊อปเจ็คที่สำเร็จไปแสดงผล (กรณีของ anemic model เรามักจะเขียน logic และติดต่อดาต้าเบสที่คอนโทรลเลอร์ซึ่งไม่ค่อยจะดีนัก จะแนะนำภายหลัง)</p>
<h3><strong><font color="#0080ff">Advantage of MVC Pattern</font></strong></h3>
<ul>
<li>SoC (Separate of Concern) ช่วยให้เราจัดการความยุ่งเหยิงในการพัฒนาออกเป็นสัดส่วนได้แก่ model, view และ controller
<li>รองรับการทำ test-driven development (TDD) 
<li>เหมาะสำหรับงาน web application ซึ่งรูปแบบการพัฒนานี้สามารถรองรับระบบงานใหญ่และการแบ่งงานกันทำงานภายในทีมพัฒนาทุกขนาด
<li>ระบบรองรับการขยับขยายเพิ่มเติมในอนาคต</li>
</li>
</li>
</li>
</ul>
<h3><strong><font color="#0080ff">Hello “ASP.NET MVC“ </font></strong></h3>
<p>มารู้จักกับ ASP.NET MVC ซึ่งเราเรียกว่าเฟรมเวิร์กก็ได้เนื่องจากไม่ได้เป็นเพียงแค่คอนเซ็ป แต่ทางไมโครซอฟต์มีไลบราลี่มาให้เราติดตั้งและใช้งาน นำไปพัฒนาต่อยอดระบบได้เลย  มาคุยกันอีกรอบถึงความสามารถของ ASP.NET MVC ซึ่งคงความสามารถเดิม ๆ ของ MVC Pattern ไว้ครบถ้วนทั้งเรื่อง </p>
<p>1. <strong>Separate of Concern (SoC)</strong> ที่ช่วยแยก logic ออกจากกันอย่างเป็นสัดส่วน ทั้ง User Interface, Business Logic, Data Access Logic  หากมือใหม่ ๆ ที่กำลังหัดเขียนโปรแกรม อาจจะเขียนแยก Function/Method ไว้กลับมาใช้งานอีกรอบ (Reuse) </p>
<p>2. <strong>Test-Driven Development (TDD)</strong> เนื่องจากโครงสร้างของ ASP.NET MVC นั้นได้ถูกออกแบบด้วย <strong>INTERFACE</strong>-<strong>BASED Programming</strong> ทำให้เราสามารถจำลองข้อมูล (mock object) เพื่อใช้ในการ input/output ใน method, class ที่เราต้องการทดสอบได้  จึงไม่จำเป็นต้องกด Run Debug (F5) เพื่อทำการทดสอบระบบเหมือนกับ ASP.NET Web Form ที่คอยต้อง input data เข้าไปเพื่อทำการทดสอบโค้ด  และข้อดีอีกคือสามารถเปลี่ยน unit-testing framework ที่พัฒนาบน .NET Frameowrk ได้ตามต้องการอีกด้วย</p>
<p>3. <strong>Extensible/Plugable Abilities</strong> ความสามารถในการต่อเติมขยับขยายระบบ  เนื่องจากคอมโพเน้นท์ของ ASP.NET MVC นั้นได้ถูกพัฒนามาให้เราสามาถแก้ไขเพิ่มเติม หรือหาอะไรมาทดแทนการทำงานก็ได้ เช่นคุณสามารถนำ View Engine มาใช้งานเอง หรือจะกำหนดการทำงานของ URL Routing เอง และอีกมากมาย  ซึ่งเจ้า ASP.NET MVC นั้นรองรับการใช้งานในลักษณะ Dependency Injection (DI) คือการยิงอ๊อปเจคเข้าไปยังคลาสแทนการเรียกใช้ตรง ๆ โดยอ้างอิงจาก Interface Contract   และยังรองรับการทำงานแบบ Inversion of Control (IoC) ซึ่งเป็นการ reverse ของการเรียกใช้อ๊อปเจคนั้นเอง โดยไปอ่านจาก config ที่กำหนดไว้  โดยทั้ง DI/LoC สามารถนำมาใช้งานเข้ากับ ASP.NET MVC ได้ทุกส่วน ซึ่งการใช้งานวิธีการเหล่านี้จะช่วยให้เราแยกเทสระบบได้อย่างอิสระมากขึ้น</p>
<p>4. <strong>Modern Web Programming Support</strong> เนื่องจากความสามารถของ Routing ใน ASP.NET MVC มาใช้ในการทำ URL Mapping ทำให้ URL ของเรานั้นดูง่ายและไม่ซับซ้อน ตลอดจนยังสามารถซ่อน extension ของไฟล์ (.aspx ) และพวก Query String ทำให้ URL ดูง่ายจดจำง่ายสะอาดตา ซึ่งความสามารถนี้ยังช่วยในการทำ Search Engine Optimize (SEO) และ REpresentational State Transfer (REST) อีกด้วย</p>
<h5>5. <strong>ASP.NET Programming Model Support</strong> อะไร ๆ ที่เคยโค้ดใน ASP.NET Web Form เราก็ยังนำมาใช้งานได้ด้วยเช่นกัน ไม่ว่าจะเป็น asp.net page (.aspx), user control (.ascx) และ master page (.master) nested master page ซึ่งไฟล์เหล่านี้นำมาใช้เป็น View Template นั้นเอง  อีกทั้งการโค้ดที่ใช้ใน View เราจะใช้ in-line expression (&lt;%= %&gt;) ในการควบคุม logic ของ view นั้น ๆ  นอกจากนั้นก็ยังมีการใช้ Server control + template, การทำ data binding, localization และอีกมากมาย  นอกเหนือที่กล่าวมาด้านบนเจ้า ASP.NET MVC ก็ยังใช้ความสามารถอื่น ๆ ของ ASP.NET ได้อย่างครบถ้วนไม่ว่าจะเป็นการทำ </h5>
<ul>
<li>
<h5>forms authentication / windows authentication</h5>
<li>
<h5>URL Authorization</h5>
<li>
<h5>Membership and Roles</h5>
<li>
<h5>output and data caching</h5>
<li>
<h5>session and profile state management</h5>
<li>
<h5>health monitoring</h5>
<li>
<h5>configuration system</h5>
<li>
<h5>provider architecture</h5>
</li>
</li>
</li>
</li>
</li>
</li>
</ul>
<h5><strong>ลองสรุปฟีเจอร์ ในแต่ละ version กันดูครับ</strong></h5>
<h5><strong>ASP.NET MVC v1.0</strong> นั้นทางไมโครซอฟต์ได้ออกเวอร์ชั่นเต็มเมื่อ  09/04/2009 โดยมีฟีเจอร์เด่น ๆ ของการทำงานดังนี้</h5>
<ul>
<li>ควบคุม HTML ได้ตามที่ต้องการ (หมายถึงเขียนสคริปเองอย่างเยอะ)
<li>สามารถนำ AJAX และ jQuery มาใช้งานร่วมกันได้
<li>อนุญาติให้เราสร้าง SEO-friendly URLs สำหรับเว็บไซต์ของเรา ช่วยค้นหาจาก search engine 
<li>ช่วยทำ Test Driven Development (TDD) เป็นไปโดยง่าย
<li>มีโปรเจ็คเท็มเพลทสำหรับ ASP.NET MVC</li>
</li>
</li>
</li>
</li>
</ul>
<p><strong>ASP.NET MVC 2.0 </strong>เป็นเวอร์ชั่นล่าสุดที่เพิ่งออกมาเมื่อ 12/03/2010  ซึ่งสามารถทำงานได้เหมือน v1.0 และมีความสามารถเพิ่มเติมตลอดจนปรับเปลี่ยนการทำงาน ซึ่งสามารถใช้วิซาร์ดในการอัพเกรดไปเป็น v2.0 ได้เลย</p>
<ul>
<li>Areas: เป็นการอนุญาติให้เราสามารถทำการแบ่งโมดูลงานของระบบออกเป็นส่วน ๆ  ช่วยให้เราสามารถแยกกันทำงานเป็นทีมได้
<li>UI Helpers: เมื่อคุณเลือกสร้างวิวแบบ strong typed ตัว helper จะทำการเลือก control สำหรับแสดงผลของโมเดลที่เหมาะสมให้เองตามลักษณะของข้อมูล ช่วยเพิ่มความรวดเร็วในการพัฒนาระบบงาน ตลอดจนเรายังสามารถ customize template เหล่านี้ตามที่ต้องการได้ และนำกลับไปใช้งานได้
<li>Asynchronous controllers: สำหรับ ASP.NET MVC v1.0 ยังเป็นปัญหากับการใช้งาน เพราะถ้ามีรีเควสใดทำงานนานมาก ๆ จะต้องรอจนตัวคอนโทรลเลอร์ทำงานเสร็จ จึงจะรับรีเควสใหม่ได้ (แต่สามารถเขียนเพิ่มเติมได้เองในภายหลัง)  สำหรับ v2.0 ทำมาให้แล้ว โดยให้คอนโทรลเลอร์รองรับการทำงานแบบ async ด้วย 
<li>Server-side validation: เป็นการอนุญาตให้เราสามารถกำหนดกฎในการตรวจสอบข้อมูลของโมเดลได้ ด้วยการกำหนด attribute หรือเขียนเพิ่มเองก็ได้
<li>Client-side validation: เมื่อกำหนดให้โค้ดอนุญาติให้ตรวจสอบโมเดลที่ไคลเอนท์ สคริปต่างๆ จะทำ dynamic validation ให้อัตโนมัติ จากแอททริบิ้วต์ที่กำหนดไว้ในโมเดล</li>
</li>
</li>
</li>
</ul>
<h3><strong><font color="#0080ff">Install ASP.NET MVC 2.0 for VS 2008 SP1</font></strong></h3>
<ul>
<li>ถอนการติดตั้ง ASP.NET MVC 2.0 Preview, RC  เอาออกให้หมด 
<li>จากนั้นทำการดาวน์โหลด <a href="http://download.microsoft.com/download/7/B/1/7B11DE4E-0247-448E-8D39-7C9B12ABA1FF/AspNetMVC2_VS2008.exe" target="_blank">ASP.NET MVC 2.0</a> 
<li>เมื่อได้มาแล้วก็ทำการติดตั้ง แล้วเสร็จจะได้ project template ของ asp.net mvc มาใช้งานใน vs2008 ของเรา</li>
</li>
</li>
</ul>
<p></p>
<h3><font color="#0080ff"><strong>First Look for ASP.NET MVC 2.0</strong></font></h3>
<p>ต่อไปเราจะมาทดลองเขียนใช้งาน ASP.NET MVC กันเบื้องต้นโดยให้เห็นการทำงานอย่างคร่าว ๆ  เปิด VS 2010 หรือ VS 2008 ของคุณขึ้นมาและลุยกันต่อ </p>
<p>1. ไปที่เมนู File –&gt; New –&gt; Project… </p>
<p>2. เลือกตามรูปที่ 3  Visual C# –&gt; Web –&gt; .Net Framework 4 (choose 3.5 for VS2008)–&gt; เลือก ASP.NET MVC 2 Empty Web Application (จะเป็นโปรเจ็คเทมเพลทที่มีโครงสร้างต่าง ๆ มาให้ค่อนข้างครบ) จากนั้นใส่รายละเอียดดังนี้:</p>
<ul>
<li>Name: ASPNETMVC01,
<li>Location:[อะไรก็ได้] ,
<li>Solution name: ASPNETMVC </li>
</ul>
<blockquote><p> <a href="http://nine69.files.wordpress.com/2010/06/4f23efa9933768240b4fde4f56a26b0b.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/4f23efa9933768240b4fde4f56a26b0b.png?w=300" /></a>    รูปที่ 3. สร้างโปรเจ็ก ASP.NET MVC 2 Web Application</p>
</blockquote>
<blockquote><p> <a href="http://nine69.files.wordpress.com/2010/06/62f117df302329d9bd54d6a951f8de68.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/62f117df302329d9bd54d6a951f8de68.png?w=300" /></a> รูปที่ 4. สร้าง Unit Test Project</p>
</blockquote>
<p> </p>
<p>3. จากนั้นจะได้โครงสร้างภายในโปรเจ็คดังภาพที่ 4 ด้านล่าง</p>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/e8f6be51eff2ceffa29401c956344f55.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/e8f6be51eff2ceffa29401c956344f55.png?w=154" /></a>   รูปที่  5. ผลลัพธ์</p>
</blockquote>
<p>    ซึ่งจะขออธิบายดังต่อไปนี้</p>
<p>    3.1 ASPNETMVC01 Project </p>
<ul>
<ul>
<li>Content folder คือโฟล์เดอร์ที่เอาไว้เก็บพวก style sheet, image, icon ประมาณนั้น
<li>Controllers folder คือโฟล์เดอร์ที่เอาไว้เก็บโดยแยกเก็บเป็น Controller class ที่ใช้ในการสร้าง method ในการควบคุมสั่งงานต่าง ๆ
<li>Models folder คือโฟล์เดอร์ที่เอาไว้เก็บพวกกลุ่ม Domain class ต่าง ๆ ที่จะใช้ในการทำงานกับ Controller และ View
<li>Scripts folder คือเอาไว้เก็บ javascript, jquery, microsoft script ต่าง ๆ เป็นต้น
<li>Views folder คือโฟลเดอร์สำหรับเก็บ View ที่เราจะสร้างขึ้นเพื่อแสดงผล รับค่าต่าง ๆ
<ul>
<li>Account คือ view ที่สร้างอัตโนมัติโดยโปรเจ็คเทมเพลทนี้เท่านั้น ใช้สำหรับ user account เข้าใช้งานระบบ
<li>Home คือ default view ตั้งต้น ส่วนมากจะสามารถเข้าสู่ view นี้เป็นหน้าแรก
<li>Shared คือ view ที่จะมองเห็นเรียกใช้ได้จาก view อื่น ๆ ครับ เช่น master page เป็นต้น</li>
</li>
</ul>
</li>
</li>
</li>
</ul>
</ul>
</p>
</p>
<p>     3.2 ASPNETMVC01.Tests Project  ตัวนี้จะเป็นเทสโปรเจ็คที่เราสร้างไว้ในตอนสร้างโปรเจ็คก่อนหน้านี้ ซึ่งเอาไว้เทส Controller</p>
<p>4. ทดสอบ Run (F5) ดูครับ จะได้ผลลัพธ์ดังนี้</p>
<blockquote><p>   <a href="http://nine69.files.wordpress.com/2010/06/0e1edb0de7f8b42011195c59ba61dc0e.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/0e1edb0de7f8b42011195c59ba61dc0e.png?w=295" /></a> <a href="http://nine69.files.wordpress.com/2010/06/cd248434394e700a119a3a0ed14f5cdb.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/cd248434394e700a119a3a0ed14f5cdb.png?w=295" /></a> <a href="http://nine69.files.wordpress.com/2010/06/2f9afbf9c2c1fdd3b11da1a6639aeac9.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/2f9afbf9c2c1fdd3b11da1a6639aeac9.png?w=295" /></a> รูปที่ 6</p>
<p>ข้อแรก ผู้อ่านจะเห็นว่ามีการใช้งาน Master Page ในโปรเจ็คนี้ด้วย</p>
</blockquote>
<blockquote><p>ข้อสอง ผู้อ่านจะเห็นได้ว่า URL ใน Address Bar ของ Browser จะดูเรียบง่าย</p>
</blockquote>
<ol>
<ol>
<li><a href="http://localhost:63282/">http://localhost:63282/</a> 
<li><a href="http://localhost:63282/Home/About">http://localhost:63282/Home/About</a> 
<li><a href="http://localhost:63282/Account/LogOn">http://localhost:63282/Account/LogOn</a></li>
</li>
</ol>
</ol>
<p>5. สำหรับ Unit Test Project ที่เราได้สร้างขึ้นมานั้น Visual Studio จะสร้าง Unit-test Method มาให้เป็นตัวอย่างไว้ศึกษา (ไว้ลงรายละเอียดกันในตอนหลัง)  เราสามารถทดสอบรัน Unit Test Projects ด้วยการกด Crlt+R หรือ Crlt+T  หรือไปที่ Menu –&gt; Test –&gt; Run –&gt; Test in current context  จะได้ผลลัพธ์ดังนี้</p>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/b345346b8f12b045095fe7f7e8f1ef30.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/b345346b8f12b045095fe7f7e8f1ef30.png?w=300" /></a> รูปที่ 7</p>
</blockquote>
<p> </p>
<h3><font color="#0080ff"><strong>How ASP.NET MVC work?</strong></font></h3>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/db5f05e4f4ec19c854db139e69f218ad.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/db5f05e4f4ec19c854db139e69f218ad.png?w=300" /></a> รูปที่ 8 โปรเซสการทำงานระหว่าง ASP.NET Web Form กับ ASP.NET MVC</p>
<p>จากรูปคอลัมภ์ด้านซ้ายจะเป็นโปรเซสการทำงานของ ASP.NET Web Form จะพบว่ามีการใช้งาน Page Class และอาศัยการทำงานของ Postback event ซึ่งทำให้การทำงานนั้นมีความซับซ้อน ส่วนคอลัมภ์ด้านขวาจะเป็นโปรเซสการทำงานของ ASP.NET MVC จะเห็นได้ว่าไม่มีการ Postback event ทำให้ดูเรียบง่ายและเมนเทนได้ง่ายกว่า</p>
</blockquote>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/8ec00388e2330214562b2adde81bd716.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/8ec00388e2330214562b2adde81bd716.png?w=300" /></a> รูปที่ 9 Sequence Diagram การทำงานของ ASP.NET MVC Request</p>
<p> 1. Browser เมื่อผู้ใช้ได้ส่งคำสั่ง request คำสั่งใด ๆ จาก Browser เข้ามา  เช่นขอหยิบยกตัวอย่างด้านบน <a href="http://localhost:63282/Home/About">http://localhost:63282/Home/About</a>  </p>
<p>2. URL Routing  จะนำ URL Request ที่ได้ไปแม๊พเข้ากับ pattern ที่ได้กำหนดไว้ใน Global.asax.cs ตั้งแต่ตอนที่ Application_Start() เรียกเมดธอดที่ชื่อว่า RegisterRoutes()  ซึ่งกำหนดค่าเริ่มต้นไว้ดังนี้ <strong>&#123;controller&#125;/&#123;action&#125;/&#123;id&#125;</strong>  เมื่อเทียบกับรีเควส  Home/About  ก็จะได้ค่า controller = Home, action = About  ดังนั้น RouteHandler จะไปขอ HomeController จาก ControllerFactory และทำการเรียก About Method ใน HomeController ตาม action ที่ร้องขอมา</p>
<p>3. Controller ในเคสนี้ About Action นั้น เป็นแค่การกำหนดค่า ViewData และสั่ง render Views/Home/About.aspx แค่นั้น    แต่ในการทำงานส่วนใหญ่มักจะมีการเรียกใช้ Model เข้ามาทำงานตามไดอะแกรมด้านบน    ซึ่งใน controller จะทำการเรียก Model เพื่อรัน business method ให้ได้ผลลัพธ์กลับออกมา จากนั้นก็ส่ง Data ที่ได้เข้าไป Render เพื่อให้ได้ ViewResult และหา ViewEngine ได้ที่ตั้งค่าเลือกใช้ไว้ ซึ่ง WebFormViewEngine เป็นของที่มีมาให้ใช้งาน</p>
<p>4. View เมื่อเลือก ViewEngine ได้ก็ทำการ Render HTML กลับไปยัง Browser</p>
</blockquote>
</p>
<h3><font color="#0080ff"><strong></strong></font> </h3>
<h3><font color="#0080ff"><strong>Conclusion</strong></font></h3>
<p>หวังว่าบทความตอนนี้คงพอช่วยให้เข้าใจถึงคำว่า MVC และ ASP.NET MVC เทคโนโลยีกันบ้างนะครับ ในตอนหน้าเราจะมาลองโค้ดกัน ด้วยการสร้าง ASP.NET MVC แบบง่าย ๆ เพื่อเอาไว้ทำความเข้าใจทั้งเรื่อง Controller, Routing และ View ในขั้นต้นกัน <img src="http://www.zu14.cn/coolemotion/emotions/zz_6.gif" />  </p>
<p> </p>
<p>Reference <a href="http://msdn.microsoft.com">http://msdn.microsoft.com</a></p>
<hr />
<p><strong></strong>
<p><strong><a href="http://meohiq.blu.livefilestore.com/y1pNPlTkKFs38u46gymP_U7c1D4kGGNorltLtXISm0d-nzRPJdcCLuXJyWrLiPIn_lbWPXmk73oonU672DV65OCJgdpqxvRrPaq/SQLiteTester.zip?download"></a></strong>
<p><strong></strong><br />
<blockquote>
<p><a href="http://nine69.files.wordpress.com/2010/06/53caf716f73bab5d4db70b9023f36a1e1.png"><img border="0" src="http://nine69.files.wordpress.com/2010/06/53caf716f73bab5d4db70b9023f36a1e1.png?w=300" /></a></p>
</blockquote>
<blockquote><p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Chalermpon Areepong Nine (นาย)</a>
<p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Microsoft MVP Thailand ASP.NET</a>
<p> 
<p>Greatfriends.biz Community Leader
<p>Email : nine_biz-talk.net <strong>at</strong> hotmail <strong>dot</strong> com
<p>Blog : http://nine-biztalk-net.spaces.live.com/blog</p>
</p>
</p>
</p>
</blockquote>
</p>
</p>
</p>
</p>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nine69.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nine69.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nine69.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nine69.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nine69.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nine69.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nine69.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nine69.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nine69.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nine69.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nine69.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nine69.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nine69.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nine69.wordpress.com/6/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=6&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nine69.wordpress.com/2010/06/04/asp-net-mvc-series-i-foundation-of-asp-net-mvc/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/8c2f25a91e95ddd2e418090794711d24?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">nine69</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2010/06/28a28075f007167d780df04c5e57d7cb.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/1245c6556fb057624bd4dada4601fcc0.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/4f23efa9933768240b4fde4f56a26b0b.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/62f117df302329d9bd54d6a951f8de68.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/e8f6be51eff2ceffa29401c956344f55.png?w=154" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/0e1edb0de7f8b42011195c59ba61dc0e.png?w=295" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/cd248434394e700a119a3a0ed14f5cdb.png?w=295" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/2f9afbf9c2c1fdd3b11da1a6639aeac9.png?w=295" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/b345346b8f12b045095fe7f7e8f1ef30.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/db5f05e4f4ec19c854db139e69f218ad.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/8ec00388e2330214562b2adde81bd716.png?w=300" medium="image" />

		<media:content url="http://www.zu14.cn/coolemotion/emotions/zz_6.gif" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/53caf716f73bab5d4db70b9023f36a1e1.png?w=300" medium="image" />
	</item>
		<item>
		<title>[Article] Database Series : ทดสอบใช้ SQLite 3 กับ .NET Application (Using Sqlite 3 with .NET Application)</title>
		<link>http://nine69.wordpress.com/2010/06/03/article-database-series-%e0%b8%97%e0%b8%94%e0%b8%aa%e0%b8%ad%e0%b8%9a%e0%b9%83%e0%b8%8a%e0%b9%89-sqlite-3-%e0%b8%81%e0%b8%b1%e0%b8%9a-net-application-using-sqlite-3-with-net-application/</link>
		<comments>http://nine69.wordpress.com/2010/06/03/article-database-series-%e0%b8%97%e0%b8%94%e0%b8%aa%e0%b8%ad%e0%b8%9a%e0%b9%83%e0%b8%8a%e0%b9%89-sqlite-3-%e0%b8%81%e0%b8%b1%e0%b8%9a-net-application-using-sqlite-3-with-net-application/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 05:19:00 +0000</pubDate>
		<dc:creator>Nine MVP ASP.NET</dc:creator>
				<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://nine69.wordpress.com/2010/06/03/article-database-series-%e0%b8%97%e0%b8%94%e0%b8%aa%e0%b8%ad%e0%b8%9a%e0%b9%83%e0%b8%8a%e0%b9%89-sqlite-3-%e0%b8%81%e0%b8%b1%e0%b8%9a-net-application-using-sqlite-3-with-net-application</guid>
		<description><![CDATA[Agenda : Database Series : ทดสอบใช้ SQLite 3 กับ .NET Application (Using SQLite 3 with .NET Application) Database Series : มารู้จักกับ OODB กันเถอะ next… Tools Visual Studio 2010/2008 ตัวใดก็ได้ใช้ได้เหมือนกัน SQLite3 Precompiled Library &#8211; Database Command-Line เลือกเอา for windows http://www.sqlite.org/sqlite-3_6_23_1.zip System.Data.SQLite .NET Data Provider (Support VS2008/VS2010) กดเพื่อ download ที่นี่ SQLite Expert Personal Edition (Free) เอาไว้จัดการดาต้าเบสแบบ GUI [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=7&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div id="msgcns!DADD0B92D4B7B2A3!643" class="bvMsg">
<h3><font color="#0080ff"><strong>Agenda :</strong></font></h3>
<ul>
<li><strong><font color="#0000ff">Database Series : ทดสอบใช้ SQLite 3 กับ .NET Application (Using SQLite 3 with .NET Application)</font></strong></li>
<li>Database Series : มารู้จักกับ OODB กันเถอะ next…</li>
</ul>
<h3><font color="#0080ff"><strong>Tools</strong></font></h3>
<ol>
<li>Visual Studio 2010/2008 ตัวใดก็ได้ใช้ได้เหมือนกัน</li>
<li>SQLite3 Precompiled Library &#8211; Database Command-Line เลือกเอา for windows <a title="http://www.sqlite.org/sqlite-3_6_23_1.zip" href="http://www.sqlite.org/sqlite-3_6_23_1.zip">http://www.sqlite.org/sqlite-3_6_23_1.zip</a></li>
<li><a href="http://downloads.sourceforge.net/project/sqlite-dotnet2/SQLite for ADO.NET 2.0/1.0.66.0/SQLite-1.0.66.0-setup.exe?use_mirror=nchc" target="_blank">System.Data.SQLite .NET Data Provider (Support VS2008/VS2010) กดเพื่อ download ที่นี่</a></li>
<li><a href="http://www.sqliteexpert.com/SQLiteExpertPersSetup.exe" target="_blank">SQLite Expert Personal Edition (Free) เอาไว้จัดการดาต้าเบสแบบ GUI กดเพื่อ download ที่นี่</a></li>
</ol>
<h3><font color="#0080ff"><strong>Introduce</strong></font></h3>
<p>พอดีมีถามตอบประเด็นในกระทู้ ก็เลยเอ๊ะ!! เจ้า SQLite หากจะใช้งาน Embedded DB ตัวนี้ ต้องทำอย่างไรบ้างน๊ออ เนื่องจากความสามารถของเจ้า SQLite นี้มีชื่อเสียงระบือไกลไม่ต่างกับเจ้า MySql (เป็นที่กล่าวขานกันได้ด้านดี) บทความนี้เป็นเพียงพื้นฐานแนะนำการใช้งานเท่านั้น เพราะผู้เขียนก็ขอทดสอบเพียงแค่นี้</p>
<h3><font color="#0080ff"><strong>SQLite Embedded Database</strong></font></h3>
<p>ต้องขอบอกว่า SQLite เหมาะกับงานเล็ก ส่วนมากเหมาะจะเอาไปฝังไว้กับพวกอุปกรณ์ hand held ต่าง ๆ   หรือจะทำเป็นดาต้าเบสขนาดย่อม ๆ สำหรับเก็บข้อมูลที่ฝั่ง client ก็ดี ซึ่ง SQLite คือEmbedded Database เป็นระบบ File System ไม่ต้องติดตั้ง ไม่ต้องสตาร์ทเซอร์วิสใดๆ ขึ้นมาทำงาน  รองรับมาตรฐาน SQL-92   มีความรวดเร็วในการทำงานสูง กินเมมโมรี่ต่ำ สามารถทำงานได้หลายแพลทฟอร์ม รองรับการทำ Transaction ไม่ต้องตั้งค่ากำหนดค่าการทำงานอะไร เริ่มต้นก็สร้าง Database/ Table ใช้งานได้เลย</p>
<h3><font color="#0080ff"><strong>Basic SQLite</strong></font></h3>
<p>1. หลังจากได้ดาวน์โหลดเจ้า Command-Line ในหัวข้อ <strong>Tools –&gt; 2. </strong> สำหรับสร้าง Database สร้าง Table มาแล้วให้ทำการแตก zip ออกมาจะได้ sqlite3.exe</p>
<p>2. วิธีการใช้งาน ก็ให้เปิด command ขึ้นมาใช้งานโดยไปที่ Start –&gt; Run –&gt; พิมพ์ Cmd กด Enter จากนั้นก็ Dir ไปยัง folder ที่แตกไฟล์ในข้อ 1 ไว้</p>
<blockquote><p>ดังภาพของผู้เขียนแตก sqlite3.exe ไว้ใน folder SQLiteTest ก็จะใช้คำสั่ง  <strong>&gt;Dir SQLiteTest</strong>  เข้าไปยังโฟลเดอร์ดังภาพ</p>
</blockquote>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/22003ab1773c8d41c1d815fe6ffe1954.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/22003ab1773c8d41c1d815fe6ffe1954.png?w=300" /></a> </p>
</blockquote>
<p>3. สร้าง Database แสนง่ายด้วยคำสั่ง C:\SQLiteTest&gt;<strong>SQLite3  Customer.db </strong></p>
<blockquote><p>จะได้คำสั่งรอเตรียมพร้อมสำหรับการสร้าง Table ดังภาพ</p>
</blockquote>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/76c19da35e39170e38d3d2b673357123.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/76c19da35e39170e38d3d2b673357123.png?w=300" /></a> </p>
</blockquote>
<p>4. มาทดลองสร้างเทเบิ้ล และคำสั่ง CRUD พื้นฐานกันดูครับ พิมพ์สคริปเข้าไปตรง ๆ จบสคริปด้วย “;” </p>
<p>    4.1  เปิดการใช้งาน Foreign key ด้วยคำสั่ง </p>
<blockquote><p>&gt;PRAGMA FOREIGN_KEYS = ON;</p>
<p>จากนั้นพิมพ์ script ตามนี้เพื่อสร้างเทเบิ้ลสำหรับ Customer table และ Address table ซึ่งมี Foreign Key ผูกกันไว้</p>
</blockquote>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/71ae01a0aa0b2500191af6653bcd4703.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/71ae01a0aa0b2500191af6653bcd4703.png?w=300" /></a> </p>
</blockquote>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/f7b601635530cd7b601e796c6a4f32ce.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/f7b601635530cd7b601e796c6a4f32ce.png?w=300" /></a> </p>
</blockquote>
<p>    4.2 ทดสอบคำสั่ง INSERT</p>
<blockquote><p>ทำการ insert data ลง customer table</p>
</blockquote>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/0513d749aa054057dee1f01b4b5ab89c.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/0513d749aa054057dee1f01b4b5ab89c.png?w=300" /></a> </p>
<p>ทำการ insert data ลง address table</p>
<p><a href="http://nine69.files.wordpress.com/2010/06/0137c99a1c9eee582958610527456b57.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/0137c99a1c9eee582958610527456b57.png?w=300" /></a> </p>
</blockquote>
<p>    4.3 ทดสอบคำสั่ง Select ในแบบต่าง ๆ</p>
<blockquote><p>Select * from table</p>
</blockquote>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/9c7399472a9b76782079f158a040e364.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/9c7399472a9b76782079f158a040e364.png?w=300" /></a> </p>
<p>Select with Inner Join</p>
<p><a href="http://nine69.files.wordpress.com/2010/06/4191f16b7a58246a5cf671ed5149868c.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/4191f16b7a58246a5cf671ed5149868c.png?w=300" /></a> </p>
</blockquote>
<p>    4.4 ทดสอบคำสั่ง Update </p>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/fb692283ea2a9533dc47284da549ac52.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/fb692283ea2a9533dc47284da549ac52.png?w=300" /></a> </p>
</blockquote>
<p>    4.5 ทดสอบคำสั่ง Delete</p>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/6390088647f47c252740c7a7115d46d6.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/6390088647f47c252740c7a7115d46d6.png?w=300" /></a> </p>
<p>เมื่อเสร็จสิ้นการใช้งาน ก็พิมพ์คำสั่ง  &gt;<strong>.quit</strong> เพื่อออกจากการใช้งาน  และเมื่อลองกลับไปดูในโฟลเดอร์ SQLiteTest จะพบไฟล์ customer.db ปรากฎอยู่ดังภาพ</p>
<p><a href="http://nine69.files.wordpress.com/2010/06/02c583ae8d15b6b1b945c6f50bb7fa0c.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/02c583ae8d15b6b1b945c6f50bb7fa0c.png?w=300" /></a> </p>
</blockquote>
<h3><font color="#0080ff"><strong>SQLite Database Management Tools</strong></font></h3>
<p>เพื่อความง่ายในการจัดการโครงสร้างและแก้ไขข้อมูลต่าง หลาย ๆ ท่านนิยมที่จะใช้ GUI tool ตามแต่ถนัดของแต่ละท่าน ซึ่งของฟรีมีให้ใช้เยอะมากครับ ไม่ว่าจะเป็นWeb Tool, Application Tool, command-line tool ในหัวข้อนี้ขอแนะนำตัวนี้ครับ <strong>SQLite Expert Personal Edition</strong> เพียงพอสำหรับใช้พัฒนาและทดสอบครับ ใช้งานง่ายด้วยสิ</p>
<blockquote><p><a href="http://nine69.files.wordpress.com/2010/06/38680239ed51d4df6fd2c1619e0ad942.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/38680239ed51d4df6fd2c1619e0ad942.png?w=300" /></a> <a href="http://nine69.files.wordpress.com/2010/06/e025e035fe47b13e756829d09d12d661.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/e025e035fe47b13e756829d09d12d661.png?w=300" /></a> <a href="http://nine69.files.wordpress.com/2010/06/7831e214a09996f967b8d9206647ee46.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/7831e214a09996f967b8d9206647ee46.png?w=300" /></a> <a href="http://nine69.files.wordpress.com/2010/06/44449cd983316a99bd4017942879c902.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/44449cd983316a99bd4017942879c902.png?w=300" /></a>   </p>
</blockquote>
<p> </p>
<h3><font color="#0080ff"><strong>SQLite Database Driver And Test Drive</strong></font></h3>
<p>สำหรับวิธีการเขียนโปรแกรมติดต่อกับ SQLite นั้น มีหลายวิธีเช่นกันทั้ง C/C++, TCL , ODBC, JDBC, ADO.NET ครบทุกค่าย แต่ผู้เขียนได้ลองค้นหา ADO.NET Data Provider สำหรับใช้งานเจ้า SQLite ปรากฎว่าพบกับ <strong>SQLite.NET ADO.NET Provider</strong> ใน version 1.0.66.0 นี้จะทำงานกับ VS2008/VS2010 ได้ โดย support ทั้ง Typed DataSet Designer, Entity Framework (ยังทำงานไม่ดีนัก)  จึงได้นำมาทดลองใช้งานในบทความนี้</p>
<p>ให้ดาวน์โหลดและทำการติดตั้งได้เลยครับ จากนั้นเปิด Visual Studio ขึ้นมาเพื่อทดสอบเขียนโค้ดเพื่อทำงานกับ Customer.db ที่เราสร้างไว้ในขั้นตอนก่อนหน้านี้</p>
</p>
</p>
</p>
</p>
</p>
</p>
</p>
</p>
<p>ซึ่งเข้าไปเอา Driver ได้ที่นี่ C:\Program Files (x86)\SQLite.NET\bin\<strong>System.Data.SQLite.dll  </strong></p>
<p>ดูรูปแบบของ connection string ได้ที่นี่ <a href="http://www.connectionstrings.com/sqlite">http://www.connectionstrings.com/sqlite</a>  ในส่วน sqlite.net</p>
<p>จากนั้นก็เขียน Code ติดต่อ Database ตามปกติ</p>
<table border="2" cellspacing="1" cellpadding="2" width="702">
<tbody>
<tr>
<td valign="top" width="696">
<p>using System;<br />using System.Data;<br />using System.Windows.Forms;<br />using System.Data.SQLite;
<p>namespace SQLiteTester<br />&#123;<br />    public partial class Form1 : Form<br />    &#123;<br />        public Form1()<br />        &#123;<br />            InitializeComponent();<br />        &#125;
<p>        private string constr = @&quot;data source=Customer.db&quot;;  //กรณีโปรแกรม exe อยู่ folder เดียวกับ customer.db
<p>        private void Form1_Load(object sender, EventArgs e)<br />        &#123;<br />            dataGridView1.DataSource = GetCustomerData().Tables[0];<br />        &#125;
<p>        public DataSet GetCustomerData()<br />        &#123;<br />            using (var conn = new SQLiteConnection(constr))<br />            &#123;<br />                var ds = new DataSet();<br />                using (var da = new SQLiteDataAdapter(<br />                    &quot;select * from customer c inner join address a on c.id = a.customer_id&quot;, conn))<br />                &#123;<br />                    da.Fill(ds, &quot;CustomerData&quot;);<br />                    return ds;<br />                &#125;<br />            &#125;<br />        &#125;<br />    &#125;<br />&#125;</p>
</p>
</td>
</tr>
</tbody>
</table>
<p> </p>
<p>ผลลัพธ์เมื่อกด RUN (F5)</p>
<p><a href="http://nine69.files.wordpress.com/2010/06/b2d8eceb0daa06df3a6779271f9f9e02.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/b2d8eceb0daa06df3a6779271f9f9e02.png?w=300" /></a> </p>
<p> </p>
<p>ปล. สำหรับภาษาไทยให้ใช้พวก NVARCHAR, NCHAR จะรองรับ unicode language ได้</p>
<p> </p>
<hr />
<p><strong></strong>
<p><strong>สามารถ download source code ได้ที่นี่</strong>
<p><strong><a href="http://meohiq.blu.livefilestore.com/y1pNPlTkKFs38u46gymP_U7c1D4kGGNorltLtXISm0d-nzRPJdcCLuXJyWrLiPIn_lbWPXmk73oonU672DV65OCJgdpqxvRrPaq/SQLiteTester.zip?download" target="_blank">Code Example Download Here!!</a></strong>
<p><strong></strong> <br />
<blockquote>
<p><a href="http://nine69.files.wordpress.com/2010/06/53caf716f73bab5d4db70b9023f36a1e.png" rel="WLPP"><img border="0" src="http://nine69.files.wordpress.com/2010/06/53caf716f73bab5d4db70b9023f36a1e.png?w=300" /></a> </p>
</blockquote>
<blockquote><p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Chalermpon Areepong Nine (นาย)</a>
<p><a href="https://mvp.support.microsoft.com/profile/Chalermpon.Areepong">Microsoft MVP Thailand ASP.NET</a>
<p>Greatfriends.biz Community Leader
<p> 
<p>Email : nine_biz-talk.net <strong>at</strong> hotmail <strong>dot</strong> com
<p>Blog : http://nine-biztalk-net.spaces.live.com/blog </p>
</p>
</p>
</blockquote>
</p>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nine69.wordpress.com/7/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nine69.wordpress.com/7/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nine69.wordpress.com/7/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nine69.wordpress.com/7/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nine69.wordpress.com/7/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nine69.wordpress.com/7/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nine69.wordpress.com/7/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nine69.wordpress.com/7/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nine69.wordpress.com/7/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nine69.wordpress.com/7/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nine69.wordpress.com/7/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nine69.wordpress.com/7/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nine69.wordpress.com/7/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nine69.wordpress.com/7/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=7&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nine69.wordpress.com/2010/06/03/article-database-series-%e0%b8%97%e0%b8%94%e0%b8%aa%e0%b8%ad%e0%b8%9a%e0%b9%83%e0%b8%8a%e0%b9%89-sqlite-3-%e0%b8%81%e0%b8%b1%e0%b8%9a-net-application-using-sqlite-3-with-net-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/8c2f25a91e95ddd2e418090794711d24?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">nine69</media:title>
		</media:content>

		<media:content url="http://nine69.files.wordpress.com/2010/06/22003ab1773c8d41c1d815fe6ffe1954.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/76c19da35e39170e38d3d2b673357123.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/71ae01a0aa0b2500191af6653bcd4703.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/f7b601635530cd7b601e796c6a4f32ce.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/0513d749aa054057dee1f01b4b5ab89c.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/0137c99a1c9eee582958610527456b57.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/9c7399472a9b76782079f158a040e364.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/4191f16b7a58246a5cf671ed5149868c.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/fb692283ea2a9533dc47284da549ac52.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/6390088647f47c252740c7a7115d46d6.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/02c583ae8d15b6b1b945c6f50bb7fa0c.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/38680239ed51d4df6fd2c1619e0ad942.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/e025e035fe47b13e756829d09d12d661.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/7831e214a09996f967b8d9206647ee46.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/44449cd983316a99bd4017942879c902.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/b2d8eceb0daa06df3a6779271f9f9e02.png?w=300" medium="image" />

		<media:content url="http://nine69.files.wordpress.com/2010/06/53caf716f73bab5d4db70b9023f36a1e.png?w=300" medium="image" />
	</item>
		<item>
		<title>ASP.NET เมื่อใช้ Response.BinaryWrite() แล้วชื่อภาษาไทยกลายเป็นยึกยือ ปัญหาของIE</title>
		<link>http://nine69.wordpress.com/2010/05/11/asp-net-%e0%b9%80%e0%b8%a1%e0%b8%b7%e0%b9%88%e0%b8%ad%e0%b9%83%e0%b8%8a%e0%b9%89-response-binarywrite-%e0%b9%81%e0%b8%a5%e0%b9%89%e0%b8%a7%e0%b8%8a%e0%b8%b7%e0%b9%88%e0%b8%ad%e0%b8%a0%e0%b8%b2/</link>
		<comments>http://nine69.wordpress.com/2010/05/11/asp-net-%e0%b9%80%e0%b8%a1%e0%b8%b7%e0%b9%88%e0%b8%ad%e0%b9%83%e0%b8%8a%e0%b9%89-response-binarywrite-%e0%b9%81%e0%b8%a5%e0%b9%89%e0%b8%a7%e0%b8%8a%e0%b8%b7%e0%b9%88%e0%b8%ad%e0%b8%a0%e0%b8%b2/#comments</comments>
		<pubDate>Tue, 11 May 2010 00:49:00 +0000</pubDate>
		<dc:creator>Nine MVP ASP.NET</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://nine69.wordpress.com/2010/05/11/asp-net-%e0%b9%80%e0%b8%a1%e0%b8%b7%e0%b9%88%e0%b8%ad%e0%b9%83%e0%b8%8a%e0%b9%89-response-binarywrite-%e0%b9%81%e0%b8%a5%e0%b9%89%e0%b8%a7%e0%b8%8a%e0%b8%b7%e0%b9%88%e0%b8%ad%e0%b8%a0%e0%b8%b2</guid>
		<description><![CDATA[เป็นเรื่องของการเขียน asp.net ให้ download file โดยการอ่าน File เข้ามาเป็น byte[]  แล้วค่อยใช้ Response.BinaryWrite(byte[])  ออกไป มันเป็นปัญหาเฉพาะ IE เท่านั้น   หากเจอ อักขระ ที่ต้องห้าม  file name ภาษาไทยจะเอ๋อกินทันที  ซึ่งนั่งปวดหมองอยู่วันนึงแล้วก็พบทางสว่าง   เลยต้องแก้ไขตามนี้         public string FileNameEncoder(string filename)         &#123;             if (Request.Browser.Browser.Contains(&#34;IE&#34;))             &#123;                 filename = Uri.EscapeDataString(Path.GetFileNameWithoutExtension(filename)).Replace(&#34;%20&#34;, &#34; &#34;) + Path.GetExtension(filename);             &#125;             return filename;         &#125; ในตอนเรียกใช้ก็เขียนประมาณนี้         private void WriteFile(string [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=8&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div id="msgcns!DADD0B92D4B7B2A3!599" class="bvMsg">
<p>เป็นเรื่องของการเขียน asp.net ให้ download file โดยการอ่าน File เข้ามาเป็น byte[]  </p>
<p>แล้วค่อยใช้ Response.BinaryWrite(byte[])  ออกไป </p>
<p>มันเป็นปัญหาเฉพาะ IE เท่านั้น   </p>
<p>หากเจอ อักขระ ที่ต้องห้าม  file name ภาษาไทยจะเอ๋อกินทันที  </p>
<p>ซึ่งนั่งปวดหมองอยู่วันนึงแล้วก็พบทางสว่าง   </p>
<p>เลยต้องแก้ไขตามนี้ </p>
<p>        public string FileNameEncoder(string filename) </p>
<p>        &#123; </p>
<p>            if (Request.Browser.Browser.Contains(&quot;IE&quot;)) </p>
<p>            &#123; </p>
<p>                filename = <strong>Uri.EscapeDataString</strong>(Path.GetFileNameWithoutExtension(filename)).<strong>Replace(&quot;%20&quot;, &quot; &quot;) + Path.GetExtension(filename);</strong> </p>
<p>            &#125; </p>
<p>            return filename; </p>
<p>        &#125; </p>
<p>ในตอนเรียกใช้ก็เขียนประมาณนี้ </p>
<p>        private void WriteFile(string pdfFileName,string type) </p>
<p>        &#123; </p>
<p>            try </p>
<p>            &#123; </p>
<p>                var bytefile = File.ReadAllBytes(pdfFileName); </p>
<p><strong>                pdfFileName = FileNameEncoder(pdfFileName);  </strong> </p>
<p>                Response.Clear(); </p>
<p>                Response.ClearContent(); </p>
<p>                Response.ClearHeaders(); </p>
<p>                Response.Charset = System.Text.Encoding.UTF8.WebName; </p>
<p>                Response.HeaderEncoding = System.Text.Encoding.UTF8; </p>
<p>                Response.ContentEncoding = System.Text.Encoding.UTF8; </p>
<p>                Response.ContentType = &quot;Application/&quot; + type; </p>
<p>                Response.AppendHeader(&quot;content-disposition&quot;, &quot;attachment; filename=&quot; + Path.GetFileName(<strong> pdfFileName));</strong> </p>
<p>                Response.BinaryWrite(bytefile); </p>
<p>                Response.End(); </p>
<p>            &#125; </p>
<p>            catch (Exception ex) </p>
<p>            &#123; </p>
<p>                Response.Write(ex); </p>
<p>            &#125; </p>
<p>        &#125;  </p>
<p>Happy ครับ</p>
<p></p>
<p></p>
<p><b><font color="#FF0000">ปล.  แต่ปัญหาจะไม่เกิด ถ้าใช้ Chrome, Firefox, IE9</font></b></p>
<p></p>
<p></p>
</p></div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/nine69.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/nine69.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/nine69.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/nine69.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/nine69.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/nine69.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/nine69.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/nine69.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/nine69.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/nine69.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/nine69.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/nine69.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/nine69.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/nine69.wordpress.com/8/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=nine69.wordpress.com&amp;blog=8253225&amp;post=8&amp;subd=nine69&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://nine69.wordpress.com/2010/05/11/asp-net-%e0%b9%80%e0%b8%a1%e0%b8%b7%e0%b9%88%e0%b8%ad%e0%b9%83%e0%b8%8a%e0%b9%89-response-binarywrite-%e0%b9%81%e0%b8%a5%e0%b9%89%e0%b8%a7%e0%b8%8a%e0%b8%b7%e0%b9%88%e0%b8%ad%e0%b8%a0%e0%b8%b2/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/8c2f25a91e95ddd2e418090794711d24?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">nine69</media:title>
		</media:content>
	</item>
	</channel>
</rss>
