Nine MVP's Blog

22/04/2010

ORM Series : Introduce NHibernate

Filed under: ORM — Nine MVP @ 2:27 am

 

  1. ORM Series : Start to ORM World
  2. ORM Series : Introduce to NHibernate
  3. ORM Series : Introduce Entity Framework   next…

Programming Level

  •     Intermediate (ควรมีประสบการณ์เขียนโปรแกรมด้าน OOP, ADO.NET และ SQL )

Required Development Tools and Libraries

  1. Visual Studio 2010 all edition or later
  2. C# 3.0 feature
  3. SQL Server 2005 or later
  4. NHibernate 2.1.2 GA  <- click download

 

Introduce NHibernate

ORM ตัวนี้ผมได้ศึกษามาระยะนึงตั้งแต่ v1.0 จนปัจจุบันมาถึง v2.1.2 กันแล้ว ซึ่ง version นี่เองที่เราจะมาพูดกัน บทความตอนนี้จะเป็นการแนะนำเจ้า NHibernate ว่าคืออะไร มีกลไกการทำงานอย่างไร และวิธีการใช้งานในเบื้องต้น หากใครอยากอ่านประวัติความเป็นมาก็เข้าไปดูได้ที่นี่ครับ  nhibernate history

Figure 1.  Application 3 Layers with NHibernate

จากรูปด้านบนนั่นคือการทำ Architectural Layering ของ Software จะเห็นได้ว่ามีสัดส่วนพื้นฐานง่าย ๆ เป็น 3 ส่วนคือ

  1. Presentation Layer  โค้ดส่วนที่เกี่ยวข้องกับ User Interface ไม่ว่าจะตรวจสอบค่า จัดรูปแบบ ต่าง ๆ จะอยู่ที่ชั้นนี้ทั้งหมด
  2. Business Logic Layer  โค้ดส่วนที่เกี่ยวข้องกับ Business ต่าง ๆ ของระบบเช่น คำนวนค่าต่าง ๆ  การหายอด การขอดูรายการในระบบ และเป็นชั้นที่จัดเก็บ Business Objects ต่าง ๆ ด้วย 
  3. Data Access Layer  โค้ดส่วนที่ใช้จัดการ object ทั้ง Insert/ Delete/Update/Select ลง Database

และ กล่องแดง ๆ นั่นคือ Object Relational Mapping Framework ที่ชื่อ NHibernate ที่เราจะมาทำความรู้จักกันแบบเจาะโครงสร้าง ลงรายละเอียดการทำงานแต่ละส่วนกันให้เข้าใจ ตัวของ NHibernate เองก็จะเกี่ยวข้องอยู่กับ Data Access Layer โดยเราจะเรียกใช้ NHibernate จากใน DAL     ซึ่ง DAL อาจจะ implement interface เอาไว้ ให้ business เรียกใช้ก็ได้ช่วยได้การ decouple layer ได้สมบูรณ์ขึ้น

NHibernate Concept and Architecture

Figure 3. NHibernate Concept Overview

NHibernate จะทำหน้าที่เพียงเปลี่ยนลักษณะของ Objects <-ไปกลับ-> Database Recode ให้เรานั้นเอง       แนวคิดและวิธีการของ NHibernate ในการทำ mapping object เข้ากับ table ใน database จะใช้ XML Mapping, Attribute หรือ utility อย่าง Fluent NHibernate ก็ได้ (บทความนี้สอน XML Mapping)       โดยเราจะต้องตั้งค่าระบุว่า Class ใน Domain Object นี้จะไป Map เข้ากับ Table ไหน และ Property นี้จะไป map เข้ากับ Column ไหนใน Table รวมไปถึงการกำหนด property เพิ่มเติมได้ค่อนข้างยืดหยุ่นทีเดียว แต่ปัจจุบันยังไม่มี GUI Tool ให้เราใช้ จึงค่อนข้างจะต้องใช้ความรู้ในการสร้าง Mapping เช่นกัน

ต่อมาคือ Detail Architecture ของ NHibernate ดังรูปข้างล่างนี้

Figure 4. NHibernate Architecture

จากรูปด้านบนผมจะแนะนำ NHibernate Components ที่เราต้องรู้จักกันก่อนครับ (reference nhibernate document 2.0) โดยขอแนะนำที่จำเป็นสำหรับเริ่มต้นเรียนู้ไว้เพียงแค่นี้ก่อนครับ

  1. SessionFactory (NHibernate.ISessionFactory) เป็นอ็อปเจ็กที่ใช้เริ่มต้นการทำงานของ NHibernate โดยจะ load mapping file และ config ต่าง ๆ เข้ามาตั้งต้นใช้งาน อีกทั้งยังเป็น factory สำหรับสร้าง ISession ซึ่งอาจจะมีแคชของข้อมูล ในกรณีที่มีนำข้อมูลกลับมาใช้งานในระดับของ transactions, process หรือ cluster-level.

  2. Session (NHibernate.ISession) เป็นอ๊อปเจ็กที่ทำงานแบบเธรดเดี่ยว(Single Thread) มีช่วงการทำงานที่สั้น ซึ่งจะเป็นตัวที่ใช้ติดต่อระหว่าง application กับส่วนเก็บข้อมูลของระบบเช่น database เป็นต้น  โดยการทำงานนั้นจะเป็นการใช้งาน ADO.NET ในการติดต่อนั้นเอง ตลอดจนยังเป็น Factory ไว้สร้าง ITransaction เมื่อต้องการใช้งาน transaction  ที่สำคัญยังมีการใช้ Cache กับ Persistant Object ด้วย ช่วยให้เราสามารถทำงานกับ object graph และกรณีค้นหา object จาก ID เป็นต้น

  3. Persistent Objects and Collections : เป็นอ๊อปเจ็กที่มีช่วงชีวิตสั้น ๆ โดยเป็นการทำงานของเธรดเดี่ยว(Single Thread) โดยจะเก็บค่า persistent state เอาไว้ด้วย และอาจจะรวมไปถึง business method บางตัวไว้ด้วย ซึ่งก็แล้วแต่ Design ของแต่ละคน    ซึ่งอ๊อปเจ็กตัวนี้จะเป็นพิมพ์เดียวกับ Domain Model ที่ออกแบบไว้ โดยจะคงคุณสมบัติของ POCO ไว้ได้  และที่สำคัญอ๊อปเจ็กตัวนี้จะอยู่ใน Session ของ ISession  และหาก Session ดังกล่าวปิดลง อ๊อปเจ็กเหล่านี้จะลอยตัวจาก nhibernate และส่งต่อไปยัง layer อื่น ๆ ได้ (โดยอาจจะ map object ไปเป็น dto เพื่อส่งต่อไป presentation layer ก็ได้)

  4. Transient Objects and Collections : คือ อ๊อปเจ็กที่อยู่ใน system memory โดยเป็นอ๊อปเจ็กที่ถูกสร้างขึ้นใหม่ หรือเป็นอ๊อปเจ็กที่ไม่ได้อยู่ในการดูแลของ ISession  

 

ดาวน์โหลดและติดตั้ง NHibernate และ Fluent NHibernate

  1. ทำการดาวน์โหลด NHibernate 2.1.2 GA (<— กดเลย)
  2. แตกzip ไว้ใน C:\NHibernate\NHibernate-2.1.2.GA-bin 

 

ตั้งค่าให้ Visual Studio ใช้งาน NHibernate XML Intellisense

เนื่องจากการพิมพ์ xml configuration ของ nhibernate เองใน visual studio เองนั้น มีโอกาสผิดพลาดสูงมาก intellisense นี้จะช่วยลดความผิดพลาดในการทำงานครับ มี step ดังนี้

  1. หลังจากที่ download NHibernate มาแล้วให้ unzip และเข้าไปใน folder NHibernate-2.1.2.GA-bin\Required_Bins เลือก copy file nhibernate-configuration.xsd และ nhibernate-mapping.xsd
  2. จากนั้นนำไปวางใน visual studio ตาม path ดังนี้ “C:\Program Files\Microsoft Visual Studio X.0\xml\Schemas”
  3. จบขั้นตอน

 

มาสร้างโปรเจ็คแรกกัน First Application with NHibernate

เราจะใช้งานเจ้า NHibernate กับตัวอย่าง Application ง่าย ๆ กันครับ โดยเราจะสร้าง Data Access Layer สำหรับ Customer Profile ซึ่งจะมีไดอะแกรมต่าง ๆ เป็นโมเดลดังนี้

1. Business Domain Class Diagram

Figure 5. Customer Profile Class Diagram

2. Database: Tables Structure

Figure 6. Customer Profile Database Model

หลังจากที่ได้ดู Class Diagram และ Database Diagram ทั้ง 2 ไดอะแกรมไปแล้วเราก็จะมาทำการสร้างงานโดยใช้ Visual Studio กัน

สร้าง Database

1. สร้าง database ชื่อ CustomerDB

2. ทำการสร้างเทเบิ้ลด้วย script ล่างนี้

USE [CustomerDB]
GO

CREATE TABLE [dbo].[Customer](
    [Id] [uniqueidentifier] NOT NULL,
    [FirstName] [nvarchar](50) NULL,
    [LastName] [nvarchar](50) NULL,
    [Age] [int] NULL,
    [Sex] [char](5) NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Address](
    [Id] [uniqueidentifier] NOT NULL,
    [Road] [nvarchar](255) NOT NULL,
    [City] [nvarchar](255) NOT NULL,
    [Country] [nvarchar](100) NOT NULL,
    [PostCode] [char](5) NOT NULL,
    [Owner_Id] [uniqueidentifier] NULL,
CONSTRAINT [PK_Address] PRIMARY KEY CLUSTERED
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Address]  WITH CHECK ADD  CONSTRAINT [FK_Address_Customer] FOREIGN KEY([Owner_Id])
REFERENCES [dbo].[Customer] ([Id])
GO
ALTER TABLE [dbo].[Address] CHECK CONSTRAINT [FK_Address_Customer]
GO

 

 

เริ่มสร้างโปรแกรม

มีขั้นตอนดังนี้

1. สร้างโปรเจ็คไฟล์

1.1  ไปที่ Menu –> File –> New –> Project… –> จากนั้นเลือก Visual C# –> .NET Framework 3.5 –> Class Library –> ใส่ค่า Name:= Vol1.Sample01.MyDAL, Location:= c:\ORMSeries, Solution name:= ORMSeries –>  กด OK

1.2 จะได้โปรเจ็คที่มีโครงสร้างดังภาพด้านล่างนี้

และให้ลบ Class1.cs ทิ้ง

 

2. เรียกใช้ NHibernate library

2.1 เรียกใช้ NHibernate คลิ๊กขวาที่ Vol1.Sample01.MyDal Project –> เลือก add reference… –> browse ไปที่ “C:\NHibernate\NHibernate-2.1.2.GA-bin\Required_Bins” –> เลือก NHibernate.dll กด OK

       

2.2 เรียกใช้ Dynamic Proxy Library คลิ๊กขวาที่ Vol1.Sample01.MyDal Project –> เลือก add reference… –> browse ไปที่ “C:\NHibernate\NHibernate-2.1.2.GA-bin\Required_For_LazyLoading\Spring” –> เลือก NHibernate.ByteCode.Spring.dll กด OK

2.3 มาตรวจสอบ Library ใน Reference กันครับ

 

3. สร้าง Entity Class

3.1 สร้างโฟลเดอร์ โดยคลิ๊กขวาที่โปรเจ็ค –> Add –> New Folder ตั้งชื่อว่า “DomainEntities”

3.1 สร้าง Customer Class –> คลิ๊กขวาที่โฟลเดอร์ “DomainEntities” –> Add –> Class… –> ตั้งชื่อว่า  “Customer.cs”  และ copy code ด้านล่างไปแปะ

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Vol1.Sample01.MyDAL.DomainEntities
{
    public class Customer
    {
        public virtual Guid Id { get; private set; }
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
        public virtual int Age { get; set; }
        public virtual Sex Sex { get; set; }
        public virtual IList<Address> Addresses { get; set; }

        public Customer()
        {
            Addresses = new List<Address>();
        }
    }

    public enum Sex
    {
        Male, Female
    }
}

 

3.2 สร้าง Address Class –> คลิ๊กขวาที่โฟลเดอร์ “DomainEntities” –> Add –> Class… –> ตั้งชื่อว่า  “Address.cs”  และ copy code ในตารางด้านล่างไปแปะ

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Vol1.Sample01.MyDAL.DomainEntities
{
    public class Address
    {
        public virtual Guid Id { get; private set; }
        public virtual string Road { get; set; }
        public virtual string City { get; set; }
        public virtual string Country { get; set; }
        public virtual string PostCode { get; set; }

        public Address()
        {
        }

    }
}

 

4. สร้าง Mapping File ใช้สำหรับบอก NHibernate ว่า assembly file –>Class–>Property ใด map เข้ากับ Database –>Table –> Colume ใดบ้าง

     4.1  สร้าง mapping สำหรับ Customer Class: คลิ๊กขวาที่โฟลเดอร์ “DomainEntities” –> Add –> New Item… –> Xml File  –> ตั้งชื่อว่า  “Customer.hbm.xml” –> คลิ๊ก Add

       

     จากนั้นและ copy xml code ในตารางด้านล่างไปแปะ และทำการ Save

 

<?xml version="1.0" encoding="utf-8" ?>
<!–  เริ่มต้นสร้าง mapping  พร้อมระบุ assembly name ของ class ที่บรรจุอยู่ภายใน   และระบุความลึกของ namespace ไปถึงตำแหน่งที่ class อยู่  –>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Vol1.Sample01.MyDAL"
                   namespace="Vol1.Sample01.MyDAL.DomainEntities" >

  <!–  เริ่ม map class พร้อมระบุ table ที่จะ map เข้าด้วยกัน  –>
  <class name="Customer" table="Customer">

    <!– กำหนด id ของ class map เข้ากับ Pk ของ column –>
    <id name="Id" column="Id">
      <!– ระบุให้ NHibernate ทำการ auto assign Guid ให้กับ Property นี้ –>
      <generator class="guid"/>     
    </id>
    <!– เนื่องจากชื่อ property เหมือนกับ column ใน DB จึงไม่ต้องระบุ column name –>
    <property name="FirstName" column="FirstName"/>  
    <property name="LastName" />
    <property name="Age" />
    <property name="Sex"  />
     <!–bag คือ collection object มีมากกว่า 1 ซึ่งเป็นลักษณะ 1:M ซึ่ง customer สามารถมี address
    ได้มากกว่า 1 และกำหนดให้ collection type เป็น generic–>
    <bag name="Addresses"  generic="true" cascade="all" >
       <!–ระบุ colume FK name ของ table address–>
      <key column="Owner_Id" not-null="true" foreign-key="Id"/>
       <!–ระบุ class name ที่จะดึงข้อมูลมาใส่ collection–>
      <one-to-many class="Address"/>
    </bag>
  </class>
</hibernate-mapping>

 

4.2  สร้าง mapping สำหรับ Address Class: คลิ๊กขวาที่โฟลเดอร์ “DomainEntities” –> Add –> New Item… –> Xml File  –> ตั้งชื่อว่า  “Address.hbm.xml” –> คลิ๊ก Add

 

   

และ copy xml code ด้านล่างไปแปะ

<?xml version="1.0" encoding="utf-8" ?>
<!–  เริ่มต้นสร้าง mapping  พร้อมระบุ assembly name ของ class ที่บรรจุอยู่ภายใน   และระบุความลึกของ namespace ไปถึงตำแหน่งที่ class อยู่  –>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Vol1.Sample01.MyDAL"
                   namespace="Vol1.Sample01.MyDAL.DomainEntities" >
  <!–  เริ่ม map class พร้อมระบุ table ที่จะ map เข้าด้วยกัน  –>
  <class name="Address" table="Address">

    <!– กำหนด id ของ class map เข้ากับ Pk ของ column –>
    <id name="Id" column="Id">
      <!– ระบุให้ NHibernate ทำการ auto assign Guid ให้กับ Property นี้ –>
      <generator class="guid"/>
    </id>

    <!– เนื่องจากชื่อ property เหมือนกับ column ใน DB จึงไม่ต้องระบุ column name ก็ได้ –>
    <property name="Road" column="Road"/>
    <property name="City" />
    <property name="Country" />
    <property name="PostCode" />
  </class>
</hibernate-mapping>

 

 

4.3  จะได้ output file ตามรูปด้านล่างนี้

 

และใน Solution Explorer ให้ทำการคลิ๊กเลือก Customer.hbm.xml และไปปรับค่าที่ Property windows แก้ไขค่า Build Action = Embeded Resource ตามรูปด้านล่าง

ทำซ้ำกับ file Address.hbm.xml เช่นเดียวกัน

 

 

 

5. สร้าง Config file สำหรับการตั้งค่าการทำงานของ NHibernate ทั้งหมด

5.1  Solution Explorer คลิ๊กขวาที่ Vol1.Sample01.MyDAL –> เลือก Add –> New Item… –> XML File –> ตั้งชื่อว่า “hibernate.cfg.xml” –> คลิ๊ก Add  จากนั้น copy code ในตารางด้านล่างไปแปะ และทำการบันทุึก

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <!– สร้าง session factory –>
  <session-factory name="Vol1.Sample01.MyDAL">
    <!– cache provider เป็นการระบุให้ nh ใช้ cache –>
    <property name="cache.provider_class">NHibernate.Cache.HashtableCacheProvider, NHibernate</property>
    <!– กำหนดให้ใช้ cache ของ query  –>
    <property name="cache.use_query_cache">true</property>
    <!– ไม่ใช้การตรวจสอบในตอนสร้าง session –>
    <property name="query.startup_check">false</property>

    <!– จำนวน batch ในการทำงาน –>
    <property name="adonet.batch_size">10</property>
    <!– กำหนด transaction level –>
    <property name="connection.isolation">ReadCommitted</property>

    <!– กำหนดให้ gen "" ครอบ sql ที่เป็น keyword ป้องกัน error –>
    <property name="hbm2ddl.keywords">auto-quote</property>
    <!– กำหนดให้ show sql ที่ gen ได้ ที่ console log –>
    <property name="show_sql">false</property>
    <!– กำหนดให้ format sql ให้อ่านง่าย เว้นบรรทัด ที่ console log–>
    <property name="format_sql">true</property>

    <!– กำหนด driver สำหรับติดต่อ dabase  –>
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <!– กำหนดตัวแปลง sql สำหรับ database  –>
    <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name="connection.connection_string">Server=.;initial catalog=CustomerDB;Integrated Security=SSPI</property>

    <property name="use_outer_join">true</property>
    <property name="command_timeout">444</property>
    <property name="query.substitutions">true 1, false 0, yes ‘Y’, no ‘N'</property>
    <property name="adonet.wrap_result_sets">false</property>
    <!– กำหนด DI สำหรับสร้าง proxy class ปกติเดิม NH จะใช้ castle แต่สำหรับ v2.1.x นั้น มีให้เลือกใช้ Spring.Net, Castle, Linfu –>
    <property name="proxyfactory.factory_class">NHibernate.ByteCode.Spring.ProxyFactoryFactory, NHibernate.ByteCode.Spring</property>

    <!– !!!!!!!!!  กำหนด assembly name ที่ต้องการจะใช้ NH ทำการ load เข้ามาทำงาน    !!!!!!!!!! –>
    <mapping assembly="Vol1.Sample01.MyDAL"/>
  </session-factory>
</hibernate-configuration>

 

 

5.2 บังคับ Client Project ให้เอา config file ของ NH ไปใช้งานด้วย  โดยไปที่ Solution Explorer เลือก hibernate.cfg.xml –> เลื่อนไปดูที่ Properties window ปรับค่า Build Action = Content และ Copy to Output Deirectory = Copy always

 

 

6. สร้าง Helper เพื่อไว้เรียกใช้ Session ของ NH ได้สะดวกขึ้น (ตัวอย่างแบบง่าย สำหรับ Client App)

6.1  ไปที่ Solution Explorer เลือก Vol1.Sample01.MyDAL คลิ๊กขวาเลือก –> Add –> Class..  ตั้งชื่อว่า “NHibernateHelper.cs” ให้ Copy code จากด้านล่างนี้แปะ และทำการ save

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using NHibernate;
using NHibernate.Cfg;

namespace Vol1.Sample01.MyDAL
{
    /// <summary>
    /// Helper นี้เหมาะสำหรับ basic client application (ไม่เหมาะกับ web app)
    /// </summary>

    public static class NHibernateHelper
    {
        // กำหนดตัวแปร factory ไว้เป็น static เมื่อสร้างขึ้นใช้งานใน App ไม่ต้องสร้างใหม่ทุกครั้งเนื่องจาก จะใช้เวลาในการสร้างนานมาก
        private static readonly ISessionFactory sessionFactory;
        // สร้าง Session
        private static ISession currentSession;

        static NHibernateHelper()
        {
            // ทำการสร้าง factory
            sessionFactory = new Configuration().Configure().BuildSessionFactory();
        }

        // เปิด session เพื่อทำงานกับ DB
        public static ISession GetCurrentSession()
        {
            if (currentSession == null)
            {
                // เปิด session ใหม่
                currentSession = sessionFactory.OpenSession();
            }
            return currentSession;
        }

        // ทำการปิด session คล้ายการปิด db connection
        public static void CloseSession()
        {
            if (sessionFactory == null)
            {
                return;
            }
            currentSession.Close();
        }

        // ปิด factory ยกเลิกการใช้งาน
        public static void CloseSessionFactory()
        {
            if (sessionFactory != null)
            {
                sessionFactory.Close();
            }
        }
    }

}

 

7. สั่ง Build ด้วยการกด Ctrl + Shift + B  หรือไปที่ Menu –> Build –> Build Solution  เมื่อสำเร็จ จะได้ DAL โปรเจ็คที่มีรูปร่างหน้าต่างประมาณนี้

 

 

8.  นำ MyDAL ของเราไปใช้งาน

8.1 ทำการสร้าง Client Project  เริ่มต้นไปที่ Menu –> File –> Add –> New Project..   ตั้งชื่อว่า ClientTest  และกด Add

    

8.2 ทำการ Add Reference ของ NHibernate  ย้อนไปทำตามข้อ 2.1 และ 2.2

8.3 ทำการ Add Reference ของ Vol1.Sample01.MyDAL  โดยไปที่ Solution Explorer –> เลือก TestClient Project และทำตามรูปด้างล่าง

    

    

     จะได้ output ตามรูปนี้

      

 

8.4  เปิด Program.cs ขึ้นมาทำการเขียนโค้ดด้านล่างนี้

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClientTest
{
    class Program
    {
        static void Main(string[] args)
        {
           //// เปิด session เพื่อเตรียมทำงานกับ Database
            NHibernate.ISession session = Vol1.Sample01.MyDAL.NHibernateHelper.GetCurrentSession();
            // ใช้งาน transaction
            NHibernate.ITransaction tx = session.BeginTransaction();

           #region Save
            // ทำการสร้าง customer instance
            Vol1.Sample01.MyDAL.DomainEntities.Customer cust1 = new Vol1.Sample01.MyDAL.DomainEntities.Customer();
            cust1.FirstName = "Somchai";
            cust1.LastName = "Sakleoi";
            cust1.Sex = Vol1.Sample01.MyDAL.DomainEntities.Sex.Male;
            cust1.Age = 25;

            // ทำการสร้าง address ของ customer
            Vol1.Sample01.MyDAL.DomainEntities.Address addr = new Vol1.Sample01.MyDAL.DomainEntities.Address();
            addr.Road = "Ratchada";
            addr.City = "Huaykwang";
            addr.Country = "Thailand";
            addr.PostCode = "10310";

           // เพิ่ม address ให้ customer
            cust1.Addresses.Add(addr);

           // สั่ง Save ลง Database
            session.Save(cust1);
            #endregion

            #region Search
            // ทำการค้นหา customer object ใน table ด้วยเงื่อนไข firstname like ‘Som%’
            var res = session.CreateCriteria(typeof(Vol1.Sample01.MyDAL.DomainEntities.Customer))
                .Add(NHibernate.Criterion.Restrictions.Like("FirstName", "Som%")).List<Vol1.Sample01.MyDAL.DomainEntities.Customer>() ;

            Console.WriteLine(" Search customer by FirstName ‘Som%’ found {0} object ", res.Count);
            foreach (var customer in res)
            {
                Console.WriteLine("customer firstname={0} lastname={1}  have address {2} ", customer.FirstName,
                                  customer.LastName, customer.Addresses.Count);
            }
           #endregion

            #region Update
            var custx = res[0];
           // แก้ไขค่า firstname ของ custx
            custx.FirstName = "XXX";
            // สั่ง update custx ใน table
            session.Update(custx);
            Console.WriteLine("Update customer name from ‘{0}’ to ‘{1}’",res[0].FirstName, custx.FirstName);
           #endregion

            #region Delete
            //ลบ object custx ออกจาก table
            session.Delete(custx);
            Console.WriteLine("Delete customer name ‘{0}’ ", custx.FirstName);
            #endregion

            // สั่งให้ commit transaction
            tx.Commit();
            // สั่งปิด Session
            Vol1.Sample01.MyDAL.NHibernateHelper.CloseSession();

            Console.ReadKey();
        }
    }
}

 

8.5  เมื่อทำการกด Run โปรแกรมด้วยการกด F5 จะได้ output ตามรูปด้านล่าง

 

อธิบายการทำงานของ Code ด้านบน

จะเห็นได้ว่ามีการสร้าง customer และ address  และได้มีการสั่งให้ Save ซึ่ง NHibernate จะบันทึกทั้ง Customer , Address ลงเทเบิ้ล

           // สั่ง Save ลง Database
            session.Save(cust1);

จากนั้นก็ได้มีการ Search customer object ด้วยการกำหนดเงื่อนไข FirstName Like ‘Som%’  ซึ่งส่งค่ากลับมาเป็น List<Customer>

          // ทำการค้นหา customer object ใน table ด้วยเงื่อนไข firstname like ‘Som%’
           var res = session.CreateCriteria(typeof(Vol1.Sample01.MyDAL.DomainEntities.Customer))
                .Add(NHibernate.Criterion.Restrictions.Like("FirstName", "Som%")).List<Vol1.Sample01.MyDAL.DomainEntities.Customer>() ;

ต่อมาจะสั่งให้ update customer ที่ search มาได้

           // แก้ไขค่า firstname ของ custx
            custx.FirstName = "XXX";
            // สั่ง update custx ใน table
            session.Update(custx);

 

และสุดท้าย คำสั่ง Delete 

            //ลบ object custx ออกจาก table
            session.Delete(custx);

 

สรุปตอนท้าย

จะเห็นว่าการใช้งาน NHibernate ค่อนข้างจะมีขั้นตอนซับซ้อน ซึ่งนี่เป็นสิ่งที่ทาง Hibernate (java) เขาใช้งานกันมายาวนาน และขึ้นชื่อว่า Hibernate นั้นสร้างชื่อเสียงเป็นอย่างมาก   เพราะความยืดหยุ่นในการทำงานและประสิทธิภาพการทำงานนั้นจัดได้ว่าในระดับที่ดีและไว้ใจได้เนื่องจากใช้งานกันมายาวนาน  ยังรวมไปถึงเหล่า contributor ต่าง ๆ ที่คอยพัฒนาไลบราลี่ไว้เสริมการทำงานอื่นๆ ให้ NHibernate อีกมากมาย      ซึ่ง NHibernate ได้พัฒนาโดยอิงตาม Hibernate ทุกประการ     จากบทความนี้เป็นเพียงพื้นฐานเริ่มต้นเล็กน้อย  ก่อนจะต่อยอดไปศึกษาในเรื่องที่ซับซ้อนกว่านี้เช่น Mapping Pattern, Performance Tuning, Caching, Transaction และ การใช้งานร่วมกับ framework อื่น ๆ เช่น Spring.Net, AOP เป็นต้น 

ซึ่งในตอนต่อไปจะมาสอนการสร้าง Mapping ในรูปแบบต่างๆ ที่ซับซ้อนกว่านี้ด้วย Real World Business Domain

 


 

สามารถ download source code ได้ที่นี่

ORMSeries Code Sample Download Here!!

 

Chalermpon Areepong Nine (นาย)

Microsoft MVP Thailand ASP.NET

email : nine_biz-talk.net at hotmail dot com

10/04/2010

WCF Series : เริ่มต้น (Begin) I

Filed under: Uncategorized — Nine MVP @ 6:51 am

WCF Series : เริ่มต้น (Begin) I

WCF Series : xxx II

Tools and Language

  1. Visual Studio 2010 RC or later 
  2. C#

แนะนำบทความ

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

ซึ่งในตอนแรกจะเป็นการกล่าวถึง WCF แบบกว้าง ๆ ทำความเข้าใจโครงสร้างและการทำงานเบื้องต้น รวมไปถึงวิธีการสร้างเพื่อนำไปใช้งานเบื้องต้นครับ

ยุคเริ่มต้น ASP.NET Web Services 

คงไม่ย้อนยุคกลับไปสมัยโบราณมากมาย เริ่มต้นกันที่ Web Services ใน .NET นั้นมีมาตั้งแต่รุ่น .NET 1.0 จนมาถึงปัจจุบัน .NET 3.5 SP1 ซึ่งได้หยุดพัฒนาแล้ว ASP.NET Web Service เป็นอะไรที่เรียบง่ายมาก ๆ สามารถเขียน WebMethod ได้เหมือนการเขียนฟังชั่นปกติธรรมดา แม้กระทั่งการคืนค่ากลับจากก็เหมือนการเขียนฟังชั่นเช่นกัน แต่มาถึงยุคการสื่อสารไร้พรหมแดนอย่าง SOA สำหรับ ASP.NET Web Services นั้น ไม่พอเพียง ทั้งเรื่อง interoperaion, performance, security, extensibility  ที่ต้องเพิ่มแติมและเปลี่ยนแปลงอยู่เรื่อย ๆ จึงจะทำให้สิ้นยุคของ ASP.NET Web Service ในไม่นานนี้

WCF นั้นคืออะไร? (What’s WCF)

WCF (Windows Communication Foundation) มีมาตั้งแต่ .NET 3.0 แล้วครับ วัตถุประสงค์ก็เพื่อช่วยขยับขยายขีดความสามารถของ ASP.NET Web Service ที่เราใช้กันอยู่ในอดีตมาจนถึงปัจจุบันนี้ก็คิดว่ายังมีหลายท่านเลือกใช้กันเป็นระบบหลัก    ซึ่งทางไมโครซอฟต์ตั้งใจพัฒนา WCF ขึ้นเพื่อรองรับลักษณะงานประเภท SOA ในกรณีที่มีระบบ(System) หรือผู้ใช้(User) ที่มีความหลากหลายในด้านมาตรฐานการสื่อสาร(Protocol) มีประสทธิภาพการทำงานที่รวดเร็วขึ้นกว่าเดิม      สามารถนำ Service ที่พัฒนาไว้นั้นไปรันบนโฮสต์ชนิดต่าง ๆ ได้ และยังรวมไปถึงระบบรักษาความปลอดภัยที่พัฒนาให้รองรับกับมาตรฐานที่มีและรองรับอนาคตอีกด้วย     ซึ่ง ASP.NET Web Service ไม่สามารถตอบโจทย์ที่ว่านี่ได้ จึงเป็น New Generation Web Service ของทางไมโครซอฟต์ที่มีมาให้เลือกใช้ครับ

รายละเอียดเพิ่มเติมอ่านต่อได้ที่นี่ วิวัฒนาการก่อนจะมาเป็น WCF คุณนเรศเขียนไว้ได้ละเอียดดีครับ

วิวัฒนาการของ WCF (WCF Evolution)

เริ่มต้นก้าวแรกสำหรับ WCF ได้ออกตามหลัง Visual Studio 2005 เป็นปลั๊กอินชื่อว่า Visual Studio 2005 extensions for.NET Framework 3.0    เป็นก้าวแรกที่ microsoft ตั้งใจที่จะพัฒนาให้ .NET ได้มีที่ยืนในกลุ่มโปรดักของ SOA   ซึ่งถือว่าได้เปิดตัว WCF เป็นครั้งแรกโดยมีความสามารถตามที่ได้กล่าวไปข้างต้น    ต่อมาสำหรับ WCF 3.5 นั้นได้ออกมาพร้อมกับ Visual Studio 2008 โดยเพิ่มเติมการทำงานในส่วนของ SOA เข้าไปอีกก็คือ Workflow Services และเมื่อ Visual Studion 2008 ได้ปล่อย Service Pack 1 ก็ได้มีการอัพเกรดเวอชั่น WCF เป็น SP1 ไปด้วยในตัวโดยเพิ่มเติมด้าน Web Programming เข้ามา     ซึ่ง WCF 3.5 SP1 เป็นตัวที่ใช้กันเป็น production อยู่ในปัจจุบัน    จนกระทั่งที่เขียนบทความนี้อยู่ WCF 4.0 Release Candidate version ก็มีให้เราได้ทดสอบใช้งานกัน และบทความนี้จะใช้ WCF 4.0 เป็นหลัก ตั้งแต่พื้นฐานเป็นต้นไปครับ

WCF FEATURE TABLE: (แต่ละฟีเจอร์จะอธิบายแนะนำการใช้งานรอบหลังอีกครั้ง)

WCF 3.0

  • One-way and duplex messaging 
  • Synchronous and asynchronous remote procedure calls 
  • Callbacks  
  • Sessions   
  • Multi-contract services 
  • Transport- and message-based security, reliability, and ordered delivery  
  • Queued messaging   
  • Transaction support  

WCF 3.5 and SP1

  • WCF and WF Integration—Workflow Services 
  • Durable Services
  • WCF Web Programming Model
  • WCF Syndication
  • WCF and Partial Trust
  • WCF and ASP.NET AJAX Integration
  • Web Services Interoperability
  • Expanded UriTemplate syntax
  • Syndication OM for the Atom Publishing Protocol.
  • Attribute-free Data Contract serialization.
  • Interoperable Object References.
  • Improved logging/tracing in Partial Trust.
  • Scalability Improvements on IIS7

WCF 4.0

  • Configuration Based Activation.
  • System.Web.Routing Integration
  • Multiple IIS Site Bindings Support
  • Routing Service
  • Support for WS-Discovery
  • Standard Endpoints
  • Workflow Services
  • Target Framework Attribute
  • WCF REST
    1. Caching
    2. Formats Support
    3. HTTP REST Error Handling
    4. Deployment Features
    5. Cross Domain JavaScript

 

โครงสร้างสถาปัตยกรรมของ WCF (WCF Architecture)

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

 

ไดอะแกรมด้านบนนี้เป็นโครงสร้างพื้นฐานของ WCF โดยได้แบ่งเอาไว้เป็นชั้น ๆ (Layer) ดังที่เห็น ซึ่งจำเป็นที่เราจะต้องเข้าใจครับว่าแต่ละส่วนคืออะไร ผมขออธิบายสั้น ๆ ได้ดังนี้

Application

คือส่วนที่เราได้ทำการ implement code ตัวเซอร์วิสไว้เช่น method, code logic, entity ต่างๆ ที่ใช้ในการทำงานของตัวเซอร์วิส

Contracts

Contract Layer เป็นชั้นที่เชื่อมต่อกับ Application Layer ซึ่งนักพัฒนาจะทำงานโดยตรงกับส่วนนี้เพื่อใช้ในการสร้างตัวเซอร์วิสต่าง ๆ     

  • Service contracts

– เป็นส่วนที่บ่งบอกว่าเซอร์วิสที่เราสร้างขึ้นนั้นมี operation (Method) อะไรไว้ให้บริการบ้าง ตัวอย่างเช่น บริการคำนวนภาษี, ให้ข้อมูลอัตราแลกเปลี่ยนค่าเงิน เป็นต้น

[ServiceContract]
public interface IMoneyServices
{
  [OperationContract]
   string CalculateTAX(decimal money, float vatRate);
}

จากตัวอย่างโค้ดด้านบน จะมีการใช้งานอินเตอร์เฟสในการกำหนดโครงสร้างของตัวเซอร์วิสของเรา โดยอาศัยแอททริบิ้วที่ชื่อ [ServiceContract] เป็นตัวบอก WCF ให้ทราบว่านี่คือเซอร์วิสที่ให้บริการ  และใช้แอททริบิ้ว [OperationContract] กำหนดบนเม็ดธอดของอินเตอร์เฟสเพื่อบอก WCF ว่าเม็ดธอดนี้จะเปิดเผยแก่ผู้ขอใช้บริการเซอร์วิสนี้    ส่วนนี้ยังไม่สิ้นสุดการสร้างเซอร์วิสเป็นเพียงการกำหนดโครงสร้างเท่านั้น ต้องนำอินเตอร์เฟสที่ได้ไปทำการ implement บนคลาสใด ๆ อีกครั้งหนึ่ง

สงสัย Interface นั้นคืออะไร? กดที่นี่

  • Data contract

– เป็นส่วนที่กำหนดโครงสร้างข้อมูลต่าง ๆ ที่มีรับส่งข้อมูลทั้งอินพุทและเอ้าท์พุทโดย Operation Contract ของ Service Contracts ซึ่งอาจจะประกอบไปด้วย ชนิดข้อมูลพื้นฐาน (Primitive Data Type) เช่น string, int, decimal, float, double, bool  และกลุ่มข้อมูลโครงสร้างที่ซับซ้อน (Complex Data Type) อย่างเช่น Class, Enumeration Data ต่าง ๆ ดังตัวอย่าง

[DataContract]
public class PurchaseOrder
{
   private int poId_value;

   [DataMember]
   public int PurchaseOrderId
   {
      get { return poId_value; }
      set { poId_value = value; }
   }
}

จากตัวอย่างโค้ดด้านบนจะเห็นว่าแอททริบิ้ว [DataContract] จะถูกกำหนดไว้บนคลาส เพื่อบอก WCF ว่าให้ทำการเปิดเผยคลาสนี้ลงใน WSDL ด้วย  และแอททริบิ้ว [DataMember] นั้นจะเป็นตัวบอก WCF ให้ทำการเปิดเผย data property นี้ลงไปใน WSDL ด้วย   ตัวอย่างต่อไปคือความสัมพันธ์ระหว่าง ServiceContract และ DataContract

[ServiceContract]
public interface ISampleInterface
{
    [OperationContract]
    double SquareRoot(int root);

    [OperationContract]
    bool ApprovePurchaseOrder(PurchaseOrder po);
}

จากโค้ดด้านบนนี้จะเห็นว่า OperationContract ทั้งสองตัวมีการใช้งาน Primitive Data Type และ Complex Data Type

  1. SqaureRoot มีพารามิเตอร์เข้าชื่อ root มีชนิดเป็น int  และส่งค่ากลับเป็น double
  2. ApprovePurchaseOrder มีพารามิเตอร์เข้าชื่อ po มีชนิดเป็น PurchaseOrder Class และส่งค่ากลับเป็น bool     ซึ่ง PurchaseOrder Class เราได้ประกาศเป็น DataContract ไว้ก่อนนี้ เนื่องจากเป็น Complex Data Type จึงต้องระบุให้ WCF ทำการนำโครงสร้างของคลาสไปบรรยายไว้ใน WSDL ด้วย
  • Message Contract

– โดยปกติข้อมูลที่ส่งข้ามกันระหว่าง Service และ Client นั้น ถูกกำหนดรูปแบบอยู่ใน SOAP Message อยู่แล้ว แต่บางครั้งเนื่องจากความต้องการในการรองรับการทำงานต่าง ๆ เช่น ต้องการจัดรูปแบบโครงสร้างเมสเสจใหม่, อยากใช้ Header, การเพิ่มเติม Status เหล่านี้  เราจะต้องอาศัย Message Contract เป็นตัวช่วยครับ

  • Policies and Binding

– ส่วนของ Policies และ Binding นั้นเป็นตัวกำหนดตั้งค่าเงื่อนไขและวิธีการให้เซอร์วิสของเรามีการติดต่อสื่อสารในรูปแบบใด (Protocol) ใช้ระบบการรักษาปลอดภัย (Security) แบบไหน และอื่น ๆ อีกมากมาย

Service Runtime

– เป็นส่วนที่กำหนดพฤติกรรม (Behavior) การทำงานของเซอร์วิส ขณะที่เซอร์วิสทำงานอยู่ มีดังนี้

  • Throttling Behavior- ใช้กำหนดจำนวนของเมสเสจที่จะเข้ามาทำงานในเซอร์วิส
  • Error Behavior – หากมีปัญหาเกิดขึ้นภายในเซอร์วิส ใช้มาช่วยทำการจัดการปัญหาดังกล่าว
  • Metadata Behavior – ใช้กำหนดการเปิดเผยข้อมูลโครงสร้าง (MetaData) ของเซอร์วิส แก่ผู้ใช้งาน
  • Instance Behavior – ใช้กำหนดจำนวนของผู้ใช้ที่จะเข้ามาใช้งานในเซอร์วิสโดยพร้อม ๆ กันขณะที่เซอร์วิสทำงานอยู่ 
  • Transaction Behavior – ช่วยในการย้อนกลับ (Rollback) การทำงานหากโอเปอเรชั่นเกิดการทำงานที่ผิดพลาดขึ้น 
  • Dispatch Behavior – เป็นตัวควบคุมว่าเมสเสจต่าง ๆ นั้นจะเข้าการโปรเซสด้วยสถาปัตยกรรมใดของ WCF

Messaging

– ใน Messaging Layer นี้เป็นการจัดการเมสเสจที่ส่งเข้าออกภายในเซอร์วิส ทั้งการกำหนดรูปแบบของเมสเสจโด การวิธีการแลกเปลี่ยนเมสเสจซึ่งพอจะแบ่งได้เป็นสองกลุ่มดังนี้

  • Transport channels :  จะทำการอ่านและเขียนเมสเสจจากเน็ตเวิร์กภายในหรือภายนอกองค์กร มีบาง transports จำเป็นต้องมีการแปลง (encoder) เมสเสจจากหน่วยสตรีมไบท์ที่ใช้รับส่งกันในเน็ตเวิร์กมาเป็น XML เช่น HTTP, named pipes, TCP, และ MSMQ
  • Protocol channels :  เป็นการทำงานโปรโตคอลระดับเมสเสจ โดยส่วนใหญ่เป็นการเขียนอ่านในส่วนของหัวเมสเสจเช่น WS-Security Protocol เป็นการกำหนดใช้ความปลอดภัยในระดับชั้นเมสเสจ และ WS-Reliability Protocol เป็นการการันตีการส่งเมสเสจระหว่างกัน

Activation and Hosting

– เซอร์วิสที่ได้สร้างไว้เป็นเพียงไลบราลี่เท่านั้น เราต้องการนำไปรันบนโฮสครับ เพื่อให้เซอร์วิสสามารถซึ่งมีให้เลือกใช้อยู่หลายวิธีดังนี้

  • Internet information Service (IIS)

    ก็คือเว็บเซอร์นั้นเอง เป็นโฮสที่ดีมีข้อดีหลายข้อในการเลือกใช้งานเป็นโฮสให้แก่ WCF Service ของเรา เน้นไปในเรื่องของการทำ Load Balance  การขยับขยายความสามารถในการรองรับผู้ใช้ในอนาคต  ข้อเสือคือทำงานบน HTTP ได้เพียงโปรโตคอล และเซอร์วิสจะไม่ทำงานจนกว่าจะมีการร้องขอการทำงานมาจากผู้ใช้หรือระบบอื่น ๆ

  • Windows Activation Service (WAS)

    เป็นของใหม่ที่ส่งมาพร้อมกับ IIS 7.0 จะทำงานเมื่อมีการร้องขอบริการเข้ามา รองรับเกือบทุกโปรโตคอล HTTP, TCP, Named Pipes, MSMQ

  • Self-Hosting

    เป็น executeable ได้เช่น console app, win app, WPF app เป็นต้น ไม่สามารถทำงานอัตโนมัติได้ ต้องรันโปรแกรมทุกครั้งเพื่อให้โฮสทำงาน

  • Windows Service

    คล้ายกับ Executable โฮส แต่จะทำงานอัตโนมัติทุกครั้งที่ Windows Start

  • COM+ 

    โฮสตัวนี้ส่วนใหญ่ไม่มีคนได้ใช้งาน เพราะค่อนข้างจะลึกลึกเรื่อง Windows Component Programming คงไม่ขอพูดถึงตลอดบทความนี้

 

 

ลงมือสร้าง (My First WCF)

อ่านหลักการทฤษฎีกันมายาว เรามาเริ่มสร้าง WCF ในเบื้องต้นกันต่อครับ

ตัวอย่าง Requierment คร่าว ๆ :  ทางบริษัทต้องการให้พัฒนาส่วนให้บริการข้อมูลสินค้าแก่ผ้ใช้งานทั่วไปผ่านทาง Web Service

1. เปิด Visual Studio

2. เลือก Menu File –> New –> Project..

3. เลือก Visual C# –> WCF –> .NET Framework 4.0 –> WCF Service Application –> Name : Vol1.Sample01.ProductSvc, Location: C:\WCFSeries, Solution Name: WCFSeries –> OK

4.  สังเกตูดูโครงสร้างโปรเจ็คที่ Visual Studio สร้างออกมาให้ดังนี้ครับ  

    • IService1.cs – คือ Service Contract
    • Service1.svc – คือ Host file ใช้สำหรับ Host ที่เป็น Web Site (IIS)
    • Web.config – คือ configuration file ของ wcf ที่จะใช้ตั้งค่าต่าง ๆ

5. แก้ไขไฟล์ IService1.cs เพื่อระบุข้อกำหนด (Contract) ของเซอร์วิสเราดังนี้    <———-  (Design Concept)

  • เปลี่ยนชื่อเป็น IProductService.cs
  • แก้ไข code ดังนี้

        using System.Collections.Generic;
        using System.Linq;
        using System.Runtime.Serialization;
        using System.ServiceModel;
        using System.ServiceModel.Web;
        using System.Text;

        namespace Vol1.Sample01.ProductSvc
        {
            // 1. สร้าง Interface สำหรับเป็น Contract ของระบบ
            [ServiceContract]
            public interface IProductService
            {
               // 2. กำหนด operation สำหรับ contract ที่จะใช้เป็น web method ให้ user ใช้งาน
                //    2.1 สร้าง interface method ชื่อ GetCurrentVatRate มีการรีเทิร์นค่ากลับเป็น float type
                [OperationContract]
                float GetCurrentVatRate();

                //    2.2 สร้าง interface method ชื่อ GetAllProduct มีการรีเทิร์นค่ากลับเป็น Product Class
                //    แต่เนื่องจาก Product Class นั้นยังไม่ได้สร้าง จึงต้องไปสร้าง class ที่ข้อ 2.3

                [OperationContract]
                List<Product> GetAllProduct();
            }

           // 2.3  สร้าง Product Class เพื่อใช้เป็น DataContract สำหรับ IProductService.GetAllProduct() method ในข้อ 2.2
             [DataContract] // DataContract เป็นตัวระบุว่าให้เปิดเผย Type นี้ผ่านทาง web service
            public class Product
            {
                [DataMember] // DataMember เป็นตัวระบุว่าให้เปิดเผย member ตัวนี้ผ่านทาง web service
                public string ProductID { get; set; }
                [DataMember]
                public string ProductName { get; set; }
                [DataMember]
                public decimal Price { get; set; }
                [DataMember]
                public float Weight { get; set; }
                [DataMember]
                public string Model { get; set;}
            }

        }

    6. แก้ไขไฟล์ Service1.svc ซึ่งเป็น host file จะผูกกับ Service1.svc.cs ซึ่งเป็น Service File  ให้เราทำการแก้ไขดังนี้  <———-  (Implement Concept)

    • 6.1 เปลี่ยนชื่อเป็น ProductService.svc ให้ถูกต้อง
    • 6.2 ดับเบิ้ลคลิ๊กที่ไฟล์ ProductService.svc.cs แล้วแก้ไข Code ดังนี้

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.Text;

    namespace Vol1.Sample01.ProductSvc
    {
       // ProductService คือ Service Class ที่เราจะเขียนโค้ดควบคุมการทำงานของเซอร์วิส
        public class ProductService : IProductService // นำ contract ที่ประกาศไว้มาใช้งานกับ service class
        {
            // operation จาก contract ถูกบังคับให้ประกาศใช้งานใน Service Class
            public float GetCurrentVatRate()
            {
                return 0.7f;
            }
           // operation จาก contract ถูกบังคับให้ประกาศใช้งานใน Service Class
            public List<Product> GetAllProduct()
            {
                return new List<Product>
                {
                    new Product{ProductID = "01", ProductName = "VIAO", Model = "VGN-FE44S/W", Price = 70000, Weight = 2.8f},
                    new Product{ProductID = "02", ProductName = "VIAO", Model = "VGN-FE45S/W", Price = 80000, Weight = 2.5f},
                    new Product{ProductID = "03", ProductName = "VIAO", Model = "VGN-FE46S/W", Price = 90000, Weight = 2.5f},
                    new Product{ProductID = "04", ProductName = "VIAO", Model = "VGN-FE47S/W", Price = 100000, Weight = 2.2f},
                    new Product{ProductID = "05", ProductName = "VIAO", Model = "VGN-FE48S/W", Price = 120000, Weight = 1.9f}
                };
            }
        }
    }

        • 6.3  แก้ไข Class Name ใน host file ใหม่ให้ถูกต้องเนื่องจากมีการแก้ไขจากด้านบน  คลิ๊กขวาที่ไฟล์ ProductService.svc.cs –> เลือก Open with –> เลือก Web Service Editor –> OK และแก้ไขตามตารางด้านล่างนี้
            <%@ ServiceHost Language="C#" Debug="true" Service="Vol1.Sample01.ProductSvc.ProductService" CodeBehind="ProductService.svc.cs" %>
      • 7.  ทำการทดสอบ WCF Service เบื้องต้น
        • 7.1  Build ด้วยการกด Ctrl+Shft+B หรือ menu –> Build –> Build Solution
        • 7.2  คลิ๊กขวาที่ไฟล์ ProductService.svc –> View in Browser เพื่อตรวจการทำงานเบื้องต้น

             

      • 8. ทดสอบสร้าง Client เพื่อเรียกใช้ WCF Service
        • 8.1 ไปที่ Menu –> File –> Add –> เลือก New Project..
        • 8.2  เลือก Visual C# –> Windows –> .NET Framework 4.0 –> Console Application –> Name: Vo1.Sample01.ConsoleTest –> กด OK

     

        • 8.3  จากนั้น คลิ๊กขวาที่ Project Vo1.Sample01.ConsoleTest  เลือก Add Service Reference…
        • 8.4 จะได้ output ตามรูปด้านล่างนี้ จะเห็นได้ว่ามี Service References (ProductService) คือ WCF Proxy Class  และ app.config ถูกสร้างขึ้น
        • 8.5 ทำการเรียกใช้ WCF ภายใน code ที่เราสร้างไว้ โดยดับเลิ้บคลิ๊กเปิด Program.cs มาทำการแก้ไข ตามตารางด้านล่างนี้

          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Text;

          namespace Vol1.Sample01.ConsoleTest
          {
              class Program
              {
                  static void Main(string[] args)
                  {

                     // ประกาศเรียกใช้ Service Client
                      var wsClient = new ProductService.ProductServiceClient();

                      // ทดสอบเรียก GetCurrentVatRate()
                      Console.WriteLine("GetCurrentVatRate() result = {0} \n", wsClient.GetCurrentVatRate());

                      // ทดสอบเรียก GetAllProduct()
                      var productResult = wsClient.GetAllProduct();
                      Console.WriteLine("———- GetAllProduct() —————–");
                      Console.WriteLine("———- List All Product —————–");

                      Console.WriteLine("\tProductID\tBrandName\tModel\tPrice\tWeight");
                      foreach (var product in productResult)
                      {
                          Console.WriteLine("\t{0}\t{1}\t{2}\t{3}\t{4}", product.ProductID, product.BrandName, product.Model,
                                            product.Price, product.Weight);
                      }

                      Console.ReadKey();
                  }
              }
          }

     

        • 8.6  ทำการทดสอบ Client ด้วยการกด F5 จะได้ผลดังภาพด้านล่างนี้

     

    สรุปจากที่ได้เห็น โดยการเลือก WCF Service Application Project ในตอนแรกทำให้เราเลือกสร้าง WCF พร้อมเลือกโฮสประเภท Web host ไปด้วยในตัว  ซึ่งเหมือนกับการสร้าง ASP.NET Web Service แต่ขั้นตอนการสร้างอาจจะมากกว่า ASP.NET Web Service      เพราะ wcf มีโฮสใช้งานมากกว่า 1 ชนิดนั่นเองจึงต้องแยกพัฒนา service contract ออกมาอย่างชัดเจน      ซึ่งจะอธิบายการสร้าง Service และการเลือกใช้ Host ประเภทต่าง ๆ ในตอนหน้า

     


    สามารถ download source code ได้ที่นี่ 

       WCFSeries Code Sample Download Here!!

     

    Chalermpon Areepong Nine (นาย)

    Microsoft MVP Thailand ASP.NET

    email : nine_biz-talk.net at hotmail dot com

    Blog at WordPress.com.