NET Application Framework Magic
NET Application Framework Magic
7 September 2009
Ariyanto
Page |2
Kata Pengantar
Dari pengalaman penulis, mengembangkan sebuah software yang baik ternyata tidak semudah
membalikan telapak tangan. Apalagi jika software yang kita kembangkan termasuk katagori
Enterprise Application. Sebetulnya sulit memberikan defenisi aplikasi Enterprise itu apa, bahkan Martin
Fowler tidak berani untuk membuat defenisi tentang ini. Beliau hanya memberi contoh apa itu
aplikasi enterprise dalam bukunya “Pattern of Enterprise Application Architecture”. Menurut beliau
aplikasi skala enterprise itu harus memiliki ciri-ciri sebagai berikut : berhubungan dengan database,
banyak data yang diolah, banyak pengakses data secara kongkuren, banyak user interface yang terlibat,
dan terintegrasi dengan aplikasi lain.
Martin Fowler, Chief Scientist Thought Works begitu mempesona saya. Bukunya, Pattern of Enterprise
Application Architecture merubah cara pandang saya tentang bagaimana mendesain software yang baik.
Berdasarkan buku tersebut saya membuat Origami, sebuah lightweight enterprise application
framework yang menerapkan repository pattern, data mapper pattern, fluent interface, virtual proxy,
dan beberapa pattern lainnya. Dengan menggunakan application framework tersebut- yang terdiri dari
empat application block : Container, data, Logging, dan Security - diharapkan produktivitas developer
dapat meningkat tanpa harus mengorbankan desain arsitektur yang baik dan elegan. Origami dapat
secara bebas didiwnload di http://origami.codeplex.com.
Tidak ada karya manusia yang sempurna, hanya kreasi-Nya lah yang tak bercela. Segala kritik, dan saran
bisa dialamatkan ke e-mail [email protected].
Ariyanto
Page |4
Daftar Isi
BAB 1
Application Framework
Framework adalah design reusable dari sebuah sistem atau sub sistem. Framework dapat terdiri dari
kode program, library, atau bagian lainnya dari sebuah komponen software yang terpisah dari aplikasi
itu sendiri. Bagian dari framework dapat di expose keluar melaui API (Application Programming
Interface). Menurut Booch, framework adalah pola arsitektur yang menyediakan suatu template yang
dapat diperluas untuk aplikasi di dalam suatu domain. Framework dapat digambarkan sebagai
mikro arsitektur yang meliputi sekumpulan mekanisme yang bekerjasama untuk memecahkan
suatu masalah yang umum pada suatu domain.
Modularity
Developer dapat menggunakan salah satu component/modul/block dari application framework sesuai
dengan kebutuhan .
Reusability
Penggunaan ulang kembali adalah salah satu tujuan application framework yang paling penting. Sebuah
aplikasi umumnya memiliki beberapa bagian code yang sama dan berulang-ulang, misal untuk
pengaksesan basis data banyak code untuk membuka koneksi yang di ulang-ulang. Framework
memastikan reusability melalui sebuah API yang seragam.
Simplicity
Maintainability
Application framework dirancang dengan memperhatikan best practice dan pattern populer yang sudah
terbukti, sehingga aplikasi yang dikembangkan memiliki struktur code yang lebih efesien dan mudah di
maintenance jika terjadi perubahan requirement
Page |6
Walaupun konsep framework telah lama diadopsi untuk pengembangan user interface, masih ada
beberapa jenis framework lain yang digunakan untuk pengembangan aplikasi secara generik. Taligent,
sebuah perusahaan yang mengembangkan object oriented operating system termasuk salah satu
perusahaan pelopor penggunaan konsep framework. Taligent dibentuk tahun 1992 sebagai kolaborasi
antara IBM dan Apple untuk membuat sistem operasi yang dapat berjalan diberbagai platform
hardware. Karena kegagalannya dalam membangun sistem operasi baru ini, ahirnya Taligent menggeser
fokusnya pada pengembangan application framework yang berjalan diatas existing operating system.
CommonPoint, framework yang dibangun oleh Taligent, bertujuan untuk mengurangi kerumitan
pengembangan aplikasi dengan menyediakan developer sebuah API (Application Programming
Interface) dan environment yang comprehensive, seperti yang pernah Sun Microsystem ciptakan untuk
bahasa pemrograman Java dan Java Virtual Machine.
IBM (yang kemudian membeli Taligent) membuat sendiri business domain oriented framework yang
disebut San Fransisco Project. San Fransisco Project dibangun menggunakan Java dan mengandung
application framework untuk berbagai tipe business domain, seperti order management, warehouse
management, dan general ledger management. Tidak seperti general purpose framework seperti Java
dan .NET, San Fransisco Project didesain untuk spesifik business domain.
1. Application Framework
Bertujuan menyediakan suatu cakupan kemampuan yang secara khas diperlukan oleh suatu
aplikasi. Contoh dari application framework adalah MFC.
2. Domain Framework
Framework untuk membantu mengembangkan aplikasi pada domain tertentu. Istilah domain
framework menandakan bahwa framework tersebut digunakan untuk domain yang spesifik.
Contoh domain framework adalah domain perbankan atau asuransi.
3. Support Framework
Support framework secara khas dialamatkan pada suaut domain yang sangat spesifik yang
berkaitan dengan komputer, seperti management memory. Support framework digunakan
secara bersama-sama dengan application framework atau domain framework.
Page |7
Origami dikembangkan oleh Ariyanto untuk menyediakan solusi sebuah Enterprise Application
Framework yang ringan (lightweight) di platform .NET. Framework lain yang populer di .NET, yaitu
Microsoft EnterpriseLib dan Spring.NET. Origami dapat didownload di http://origami.codeplex.com/
Logging Security
Data
Container
Page |8
Container (Origami.Container)
Menyediakan fungsi untuk mengatur konfigurasi, konstruksi , dan pengaturan object depedency baik
secara programatic maupun declarative. Container menjadi perekat application block lainnya dimana
semua objek dalam aplikasi dirangkai dalam sebuah file konfigurasi berformat XML. Origami Container
merupakan implementasi dari konsep Depedency Injection yang memastikan desain class lebih loosely
coupled sehingga code lebih mudah di baca (readable) dan mudah di guna ulang (reusable).
Data (Origami.Data)
Menyediakan fungsi untuk melakukan operasi-operasi database secara umum dengan kode yang jauh
lebih sedikit dan efesien. Application block ini menyediakan class-class yang mengenkapsulasi fitur-fitur
ADO.NET sehingga dapat lebih mudah digunakan. Dengan menggunakan Origami Data, developer
dengan mudah menrapkan pattern dan practice yang berhubungan dengan desain data access layer.
Pattern yang digunakan dalam application block ini diantaranya : repository, data mapper, fluent
interface, dan virtual proxy.
Logging (Origami.Logging)
Menyediakan fungsi untuk melakukan logging (pencatatan) atas berbagai event yang timbul.Block ini
dapat melakukan pencatatan secara konsisten baik pada level aplikasi ataupun level infrastructure
layer. Application block ini meneyediakan berbagai jenis tipe logger yang dapat disesuaikan dengan
kebutuhan aplikasi. Logger yang didukung adalah Console, Database, File, Event Log, SMTP, Trace, dan
Messaging (MS MQ). Dengan memanfaatkan Origami Container, implementasi logging dapat diganti
secara runtime lewat konfigurasi tanpa harus meng-compile ulang source code.
Security (Origami.Security)
BAB 2
Depedency Injection Container
Pada pengembangan aplikasi berorientasi objek, umumnya kita tidak hanya berhubungan dengan satu
objek, melainkan banyak objek yang saling berelasi dan memiliki depedency satu sama lain. Pattern &
Practice menyarankan bagaimana cara mendesain sebuah class yang memiliki ketergantungan yang
rendah satu sama lainnya (loosely coupled). Makin loosely sebuah class, maka makin flexible aplikasi
yang dikembangkan sehingga akan memudahkan maintenece dan testing. Ada beberapa cara untuk
menghasilkan code yang lousley diantaranya adalah : programming to interface instead implementation,
factory pattern, dan depedency Injection.
Container di Origami bertugas untuk melakukan konfigurasi dan instantiasi objek berikut depedency
(ketergantungan) antar objek yang telah diregistrasikan baik secara programatic atau declarative
(melalui file XML). Container merupakan penerapan dari Depedency Injection sebagai bentuk dari
Inversion of Control (IoC) design yang diterapkan dibanyak framework. Depedency Injection memberikan
fleksibilitas dalam menerapkan custom implementation seperti “plugin” tanpa harus memodifikasi
exisiting code. Depedency injection dapat diterapkan pada constructor dan property.
Sebenarnya untuk kasus yang sederhana, depedency injection dapat dilakukan tanpa menggunakan
framework tertentu. Berikut contohnya :
ObjectContainer.RegisterObject("greeting", typeof(Greeting),depedency);
Pada contoh diatas Injection dilakukan secara programatic menggunakan Origami Container. Origami
mendukung dua cara dalam menangani depedency, yaitu programatic dan declarative. Pada
programatic injection registrasi objek berikut depedency nya dilakukan di code, sedangkan pada
declarative injection semuanya cukup diletakkan di XML. Karena menggunakan XML, objek-objek
tersebut dengan mudah diganti implementasinya tanpa harus mengubah code.
Semua objek yang digunakan di aplikasi harus di registrasikan terlebih dahulu di Container dengan
menggunakan method RegisterObject() dari static class ObjectContainer. Setiap objek diregistrasikan
dengan menggunakan sebuah id unik bertipe string. Bukan hanya objek-objek yang di registrasikan,
P a g e | 11
depedency dari objek-objek tersebut juga perlu di registrasi. Bayangkan Container adalah sebuah kotak
tempat menyimpan objek. Letakkan objek-objek di kotak (register object), dan jika membutuhkannya,
ambil objek tersebut dari kotak (get object).
Untuk contoh class Greeting diatas jika menggunakan declarative depedency injection, terlebih dahulu
buatkan sebuah file XML bernama Configuration.xml berikut :
ObjectContainer.SetApplicationConfig("Configuration.xml");
Greeting greeting=ObjectContainer.GetObject<Greeting>("greeting");
Console.WriteLine(greeting.ShowMessage);
File confuguration bisa jadi lebih dari satu dan diletakkan didirektori yang berbeda dengan aplikasi
Contoh :
ObjectContainer.SetApplicationConfig(@"d:\conf\Configuration.xml");
P a g e | 12
</object>
<objects>
</container>
Object id berisi Id dari objek, bisa type berisi fully qualified assembly name, yaitu
berisi string apa saja yang penting nama class beserta namespace secara lengkap
unik
isi dari variabel yang menjadi
type berisi tipe dari variabel yang
depedency constructor
menjadi depedency constructor
return result;
}
}
P a g e | 13
Class Calculator memiliki depedency di Property Logger. Property Logger sendiri adalah sebuah objek
ConsoleLogger.
</object>
<objects>
</container>
Object dengan id “calc” memiliki property depedency bertipe object. Jika objek memiliki
depedency primitive type deklarasinya menjadi property name="[name]"
value="[value]"
Untuk DBMS MS Access namespace yang digunakan adalah System.Data.OleDb dan untuk SQL
Server adalah System.Data.SqlClient.
namespace OrigamiDemo
{
public class CustomerDataAcces
{
private ConnectionService cs;
private SqlCommand cmd;
private IDataReader rdr;
namespace OrigamiDemo
{
public class ConnectionService : IDisposable
{
private string connectionString;
private SqlConnection conn;
Programmatic Injection
namespace OrigamiDemo
{
public class DepedencyRegistry : IRegistry
{
private ConnectionService connectionService;
ObjectContainer.RegisterObject("cda", typeof(CustomerDataAcces),
depedency);
ObjectContainer.RegisterDepedency(depedency);
}
P a g e | 16
Client
cda.GetAllCustomer();
registry.Dispose();
Declarative Injection
Configuration.xml
Client
ObjectContainer.SetApplicationConfig("Configuration.xml");
cda.GetAllCustomer();
P a g e | 17
BAB 3
Data Access
Kebanyakan aplikasi level enterprise menyimpan informasi ke salah satu jenis database relasional.
Akibatnya, aplikasi tersebut membutuhkan perintah-perintah untuk mengeksekusi SQL atau stored
procedure. Perintah tersebut digunakan untuk mengupdate data dan me-retrieve data dalam berbagai
bentuk. Developer sering menemukan duplikasi kode untuk membuka koneksi database, menutup
koneksi atau meng-assign parameter ke database command.Tidak jarang developer harus
menggunakan beberapa class hanya untuk menampilkan satu record data.
Origami menyediakan framework untuk Data Access yang menyediakan kumpulan class dan interface
yang mengenkapsulasi beberapa pattern dan best practice yang berhubungan dengan desain data
access layer dengan menyediakan fungsionalitas untuk melakukan operasi-operasi database secara
umum dengan kode yang jauh lebih sedikit dan efesien. Dengan demikian produktivitas developer
diharapkan dapat ditingkatkan.
Menurut Wikipedia, Data Access Layer (DAL) adalah layer dari sebuah program komputer yang
menyediakan kemudahan akses bagi data yang tersimpan di persistent storage seperti relational
database.
Sebuah data access layer framework sebaiknya memiliki functional requirements sebagai berikut :
Database Independence
Database independence berarti sebuah DAL memiliki service yang sama untuk berbagai macam DBMS.
Tidak peduli jenis DBMS yang digunakan. Sebuah framework DAL yang baik mampu mengakses SQL
Server, Oracle, DB2, MySQL dan DBMS lainnya. Idealnya jika terjadi perubahan implementasi DBMS,
tidak akan meneybabkan perubahan yang berarti pada aplikasi, cukup dengan mengedit konfigurasi data
provider nya saja di XML.
mampu menyimpan transient object menjadi persistent ke database atau sebaliknya mengkosntruksi
transient object dari peristent data di database.
CRUD Service
CRUD adalah kumpulan method yang bertanggung jawab terhadap manipulasi dan query data pada
sebuah relational DBMS. CRUD akronim dari Create, Read, Update, dan Delete.
Query Servcie
R pada CRUD Service adalah Read, ini artinya sebuah DAL framework harus menyediakan mekanisme
untuk me-retrieve persistent data dari database. Selain itu harus menyediakan mekanisme query
kompleks dengan berbagai kriteria tertentu.
Transaction Management
Memanage transactional object dalam satu unit of work
Berikut ini adalah class dan interface utama dari Origami Data Access
Query
DataSource IDataContext
P a g e | 19
while (rdr.Read())
{
Console.WriteLine(rdr["CustomerId"].ToString());
Console.WriteLine(rdr["CompanyName"].ToString());
}
rdr.Dispose();
Origami Way
dataSource.Provider = "System.Data.SqlClient";
dataSource.ConnectionString = @"Data Source=XERIS\SQLEXPRESS;"
+ "Initial Catalog=Northwind;Integrated Security=True";
IDataContext dx = DataContextFactory.CreateInstance(dataSource);
rdr.Dispose();
IDataContext dx = DataContextFactory.CreateInstance(dataSource);
string sql="SELECT * FROM Customers";
return customer;
}
}
Origami menyediakan akses ke basis data secara universal. Untuk mengubah tipe DBMS yang digunakan
tinggal mengubah Provider dan Connection String. Berikut ini daftar connection string untuk database
populer :
Untuk lebih lengkapnya silahkan kunjungi http://connectionstrings.com untuk informasi lebih lanjut.
Selain mespesifikasikan DataSource secara programatic, Origami juga mendukung penulisan konfigurasi
data source lewat XML (disarankan menggunakan pendekatan ini), sehingga jika terjadi perubahan pada
connection string atau pada provider implementasi DBMS cukup mengedit konfigurasinya saja, tanpa
harus meng-compile ulang code nya.
Secara programatic :
IDataContext dx = DataContextFactory.CreateInstance(dataSource);
ObjectContainer.SetApplicationConfig("Configuration.xml");
IDataContext dx=ObjectContainer.GetObject<IDataContext>("dx");
Configuration.xml
<objects>
</container>
Pengaturan objek lewat konfigurasi XML menggunakan fitur Origami Container sudah dibahas di bab 2
dan lebih lanjut lagi dipembahasan mengenai Data Access Depedency Injection.
P a g e | 22
Method Keterangan
ExecuteReader() Method yang digunakan untuk mengeksekusi perintah SQL SELECT
Parameter : Sql
Contoh :
ExecuteReader("SELECT * FROM Employees")
Parameter : Sql
Contoh :
ExecuteNonQuery("DELETE FROM Employees WHERE EmployeeID=1")
Parameter : Sql
Contoh :
ExecuteReader("SELECT * FROM Employees")
Buka Koneksi
dataSource.Provider = "System.Data.SqlClient";
dataSource.ConnectionString = @"Data Source=XERIS\SQLEXPRESS;"
+ "Initial Catalog=Northwind;Integrated Security=True";
IDataContext dx = DataContextFactory.CreateInstance(dataSource);
P a g e | 23
IDataContext adalah interface Origami yang berisi method-method data access helper. Berikut isi dari
interface tersebut :
DbCommandWrapper CreateCommand();
DbCommandWrapper CreateCommand(CommandWrapperType cmdWrapperType,
string cmdText);
Transaction BeginTransaction();
}
P a g e | 24
ExecuteReader()
ExecuteNonQuery()
dx.ExecuteNonQuery(sql);
ExecuteDataSet()
ExecuteScalar()
ExecuteObject()
ExecuteList()
Origami menyediakan satu class yang sangat powerfull bernama Query. Class ini mengenkapsulasi
perintah-perintah SQL CRUD (Create, Read, Update, Delete) dan method-method ADO.NET seperti
ExecuteReader(), ExecuteNonQuery(), ExecuteDataSet(), dan ExecuteScalar(). Class tersebut
menyediakan pula method ExecuteObject() dan ExecuteList() yang merupakan fitur ORM (Object
Relational Mapping) dari Origami.
Query diatas akan menghasilkan perintah SQL berikut : SELECT * FROM Customers WHERE
CustomerId='ALFKI'.
SELECT
INSERT
UPDATE
DELETE
Aggregate Query
MAX
AVG
SUM
Menariknya, dalam satu chained method, kita bisa memanggil method ExecuteReader(), atau method
lainnya. Contoh :
ExecuteReader()
while (rdr.Read())
{
Console.WriteLine(rdr["CustomerId"].ToString());
Console.WriteLine(rdr["CompanyName"].ToString());
}
ExecuteScalar()
ExecuteNonQuery()
Presentation Origami
GUI,
Web
Business Entity
Data Access
User Interface
Pada pendekatan layered architecture, biasanya aplikasi ini dipecah menjadi 3 layer yaitu :
Presentation, Business Entity dan Data Access layer.
Presentation layer bertanggung jawab dengan tampilan (user interface), Business Entity atau model
berisi logika business/domain permasalahan dan Data Access bertanggung jawab untuk
memanipulasi tabel-tabel di basis datanya. Dengan pemisahan ini aplikasi tidak tergantung dengan user
interface nya (Console, WinForm, Web/ASP.NET) atau pilihan DBMS (SQL Server, Oracle, MySQL),
sehingga apabila terjadi perubahan dikemudian hari karena suatu hal, developer tidak harus menulis
ulang program dari awal.
Berdasarkan guidelines Microsoft Pattern & Practices Group ada 5 cara untuk merepresentasikan
business Entity yaitu : XML, DataSet, Typed DataSet, Business Entity Object, dan CRUD Business
Entity Object .
Metode Keterangan
XML Format data terbuka yang bisa diintegrasikan dengan beragam aplikasi
lain. XML Business entity dapat direpresentasikan dalam bentuk XML
Document Object Model (DOM)
DataSet Cache tabel dalam memori
Typed DataSet Class yang diturunkan dari ADO.NET yang menyediakan strong method,
event, dan property untuk mengakses tabel dan kolom di DataSet
Business Entity Object Entity class yang merepresentasikan business entity. Class ini berisi
enkapsulasi field, property, dan method.
CRUD Business Object Entity class yang memiliki kemampuan CRUD (Create, Read, Update,
Delete)
Representasi paling dinamis dari tabel diatas adalah dengan menggunakan Business Entity Object yang
diimplementasikan dalam bentuk Entity Class. Bisanya entity class cukup berisi field dan property saja.
Contoh :
namespace Northwind.Model
{
public class Customer
{
private string customerId;
private string companyName;
private string contactName;
private string address;
private string phone;
private string fax;
}
}
Jika menggunakan .NET Framework 3.5, penulisan property dapat disingkat sebagai berikut :
namespace Northwind.Model
{
public class Customer
{
public string CustomerId { get; set; }
}
}
P a g e | 30
3.6 Repository
Menurut Martin Fowler ,
"A Repository mediates between the domain and data mapping layers, acting like an in-memory domain
object collection. Client objects construct query specifications declaratively and submit them to
Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from
a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the
appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of objects
persisted in a data store and the operations performed over them, providing a more object-oriented view
of the persistence layer. Repository also supports the objective of achieving a clean separation and one-
way dependency between the domain and data mapping layers."
Repository mengenkapsulasi method-method untuk manipulasi dan query data dalam sebuah class yang
berkorespondensi dengan model/business entity. Sebuah repository biasanya memiliki method CRUD
(Create, Read, Update, Delete) seperti : FindById(), FindAll(), Save(), Update(), dan Delete() seperti yang
didefenisikan di interface IRepository<T> generic sebagai berikut :
Defenisikan interface masing-masing class repository yang mewarisi generic interface IRepository<T>
namespace Northwind.Repository
{
public interface ICustomerRepository : IRepository<Customer>
{
}
}
namespace Northwind.Repository.Implementation
{
public class CustomerRepository : ICustomerRepository
{
private IDataContext dx;
private string tableName = "Customers";
Contoh Lain :
Save()
return dx.ExecuteNonQuery(q.GetSql());
}
Update()
return dx.ExecuteNonQuery(q.GetSql());
}
Delete()
return dx.ExecuteNonQuery(q.GetSql());
}
P a g e | 33
Origami tidak memposisikan diri sebagai ORM framework, namun bisa menerapkan salah satu fitur nya,
yaitu Data Mapper. Perbedaanya, mapping di Origami dilakukan secara programatic (hand code),
sedangkan pada ORM framework umumnya dilakukan secara otomatis dengan menggunakan metadata
baik berupa custom attribute atau XML. Contoh ORM Framework populer adalah NHibernate, dan
Entity Framework.
Dengan menggunakan data mapper, cara menampilkan data akan sesuai dengan gaya object oriented.
Berikut ini perbedaannya
Tanpa mapping :
while (rdr.Read())
{
Console.WriteLine(rdr["CustomerId"].ToString());
Console.WriteLine(rdr["CompanyName"].ToString());
}
Menggunakan mapping :
cust.CustomerId = rdr["CustomerId"].ToString();
cust.CompanyName = rdr["CompanyName"].ToString();
cust.ContactName = rdr["ContactName"].ToString();
cust.Address = rdr["Address"].ToString();
cust.Phone = rdr["Phone"].ToString();
return cust;
}
}
Jika salah satu field dalam tabel yang dimapping memperbolehkan NULL value, maka lakukan mapping
seperti berikut :
namespace Northwind.Repository.Mapping
{
public class CustomerMapper : IDataMapper<Customer>
{
public Customer Map(IDataReader rdr)
{
Customer customer = new Customer();
return customer;
}
}
}
Project structure
Business Entity
Presentation
Data Access
Disisi client class-class Repository diakses lewat interface nya. Pemrograman melaui interface ini
menjadikan client tidak tergantung dengan layer data access, sehingga jika terjadi perubahan pada
metode akses data di repsository, layer presentation sama sekali tidak perlu diubah.
P a g e | 36
3.8 Relationship
Relational DBMS memiliki tabel-tabel yang saling beralasi. Relational DBMS yang berbasis aljabar
relasi memiliki tipe relasi yang disebut Asosiasi. Hubungan ini terbagi menjadi 4 jenis, yaitu : hubungan
one-to-one, one-to-many, many-to-one dan many-to-many. Sebelum merelasikan tabel harus
dilakukan proses normalisasi terlebih dahulu untuk menjamin konsistensi, integritas data dan
meminimalisir redudansi.
Tidak seperti Relational DBMS yang hanya memiliki 1 jenis relasi, class memiliki 5 macam jenis
relasi yang mungkin yaitu : Asosiasi, Agregasi, Generalisasi, Depedensi, dan Realisasi .
Class Category
using System.Collections.Generic;
namespace Northwind.Model
{
public class Category
{
public int CategoryId { get; set; }
Hubungan antara tabel Categories dan Product adalah one-to-many, satu kategori mengandung banyak
produk.Representasi one-to-many di class menggunakan asosiasi dalam bentuk collection. Implementasi
collection di C# biasanya menggunakan List<T> generic, dimana T bisa diisi oleh object apa saja (dalam
hal ini T diisi oleh objek Category). Sebaliknya, di class Product berarti asosiasi nya many-to-one.
Class Product
namespace Northwind.Model
{
public class Product
{
public int ProductId { get; set; }
}
}
return category;
}
}
return product;
}
}
Jika tabel yang dimap memiliki relasi (seperti tabel produk), terlebih dahulu tabel tersebut di map di
class terpisah (class CategoryMap), selanjutnya di ProductMap class CategoryMap ini dinstantiasi
Class ProductRepository
Fluent interface query pada method FindById() dan FindAll() menggunakan statement InnerJoin untuk
merelasikan tabel Products dengan tabel Categories. Relasi dilakukan melalui foreign key CategoryId
ditabel Products. Fluent interface query pada method FindAll() akan mengenerate perintah Sql berikut :
using System.Collections.Generic;
namespace Northwind.Model
{
public class Category
{
public int CategoryId { get; set; }
Category category=dx.ExecuteObject<Category>(q.GetSql(),
new CategoryMapper());
category.Products = productRepository.FindByCategoryId(id);
return c;
}
}
return categories;
}
Dari contoh diatas terlihat jelas untuk mengimplementasikan hubungan one to many class
CategoryRepository perlu menginstantiate class yang berelasi yaitu ProductRepository. Perhatikan baik-
baik method FindById() dan FindAll() milik class CategoryRepository. Object productRepository
memanggil method FindByCategoryId().
Method ini bertugas untuk memanggil semua produk berdasarkan category id tertentu dan memiliki
return value object collection (dalam hal ini yang dikembalikan adalah List<Product>) yang kemudian di
inject ke property Products di object category.
return dx.ExecuteList<Product>(q.GetSql(),
new ProductMapper());
}
P a g e | 42
Dengan menggunakan Origami Container, objek tidak usah di-instantiasi secara langsung di code.
Container-lah yang bertanggung jawab untuk melakukan hal tersebut, kita cukup merigistrasikan objek
ke container dengan cara mendeklarasikan objek apa yang dibutuhkan beserta property dan depedency
nya jika ada pada file XML. Selanjutnya objek tersebut langsung bisa dipakai pada aplikasi
bersangkutan. Menariknya, jika ada perubahan pada pemanggilan objek atau pengaturan property dan
depedency nya, cukup di edit di konfigurasi XML nya tanpa harus menyentuh source code sama sekali.
Programatic Injection
Declarative Injection
ObjectContainer.SetApplicationConfig("Configuration.xml");
DataSource ds = ObjectContainer.GetObject<DataSource>("ds");
P a g e | 43
Semua repository class dan object dependency nya di register pada sebuah class yang bernama
DepedencyRegistry. Dependency object class-class repository bisa lebih dari satu, misalnya selain objek
dx (IDataContext) bisa juga terdapat sebuah object logger. Semua constructor dependency ini di resolve
menggunakan constructor injection.
dx = DataContextFactory.CreateInstance(ds);
object[] depedency={dx};
ObjectContainer.RegisterObject("categoryRepository",
typeof(CategoryRepository), depedency);
ObjectContainer.RegisterObject("productRepository",
typeof(ProductRepository), depedency);
ObjectContainer.RegisterDepedency(depedency);
}
registry.Dispose();
Console.ReadLine();
ds.Provider = "System.Data.SqlClient";
ds.ConnectionString = @"Source=XERIS\SQLEXPRESS;
+ "Integrated Security=True";
dx = DataContextFactory.CreateInstance(ds);
object[] dependency = { dx };
ObjectContainer.RegisterDepedency(depedency);
}
}
Console.WriteLine("\t" + p.ProductName);
}
}
registry.Dispose();
Console.ReadLine();
Screen shoot
P a g e | 46
<object id="categoryRepository"
type="Nortwind.Repository.Implementation.ICategoryRepository,
Northwind.Repository">
<constructor-arg ref="dx"/>
</object>
<object id="productRepository"
type="Nortwind.Repository.Implementation.ProductRepository,
Nortwind.Repository">
<constructor-arg ref="dx"/>
</object>
</objects>
</container>
ObjectContainer.SetApplicationConfig("Configuration.xml");
Menurut Martin Fowler, ada 4 pendekatan yang bisa ditempuh untuk menerapkan lazy load, yaitu : lazy
initialization, virtual proxy, value holder, dan ghost. Saya akan mencontohkan bagaimana menggunakan
pendekatan virtual proxy.
Virtual proxy mengharuskan property objek yang berelasi di set menjadi virtual. Tujuannya agar bisa di
override di proxy class nya.
productLoaded = true;
}
else
{
products=base.Products;
}
P a g e | 48
return products;
}
set
{
base.Products = value;
productLoaded = true;
}
}
}
Bagian yang perlu di refactoring lagi adalah CategoryMapper. Gantilah class Category menjadi
CategoryProxy
return category;
}
}
Hasil Debug
Pada gambar diatas jelas bahwa property Products pada objek c (category) baru diisi pada saat
dipanggil/dibutuhkan. Dengan demikian penggunaan virtual proxy ini dapat meningkatkan performance.
P a g e | 49
IDataContext dx = DataContextFactory.CreateInstance(dataSource);
DataContext dx=ObjectContainer.GetObject<DataContext>("dx");
while (rdr.Read())
{
Console.WriteLine(rdr["FirstName"].ToString());
}
Contoh lain
dx.ExecuteNonQuery(cmd);
ExecuteObject()
ExecuteList()
spFindCustomerById
spInsertCustomer
cmd.SetParameter("@CustomerId",DbType.String,"MSFT");
cmd.SetParameter("@CompanyName", DbType.String, "Microsoft");
cmd.SetParameter("@ContactName", DbType.String, "Bill Gates");
dx.ExecuteNonQuery(cmd);
P a g e | 51
cmd.SetParameter("@CustomerId", DbType.String,cust.CustomerId);
cmd.SetParameter("@CompanyName", DbType.String,cust.CompanyName);
cmd.SetParameter("@ContactName", DbType.String,cust.ContactName);
return dx.ExecuteNonQuery(cmd);
}
}
P a g e | 52
3.13 Transaction
Transaksi didefenisikan sebagai himpunan satu atau lebih pernyataan yang diekseskusi sebagai satu unit
(unit of work), dengan demikian dalam suatu transaksi himpunan pernyataan harus dilaksanakan atau
tidak sama sekali. Contoh jika kita ingin menghapus record yang memiliki hubungan master-detail.
Proses penghapusan record di tabel master harus disertai dengan record yang berelasi di tabel detail,
jika proses penghapusan record pada tabel master gagal proses penghapusan harus dibatalkan
seluruhnya agar integritas data tetap terjaga.
IDataContext dx=DataContextFactory.CreateInstance(ds);
Transaction tx = dx.BeginTransaction();
try
{
string[] fields1 = { "CustomerId", "OrderDate", "ShippedDate" };
object[] values1 = { 1, DateTime.Now, DateTime.Now };
dx.ExecuteNonQuery(q1.GetSql(), tx);
dx.ExecuteNonQuery(q2.GetSql(), tx);
tx.Commit();
}
catch (Exception ex)
{
tx.Rollback();
Console.WriteLine(ex.ToString());
}
P a g e | 53
Tujuan dari testing adalah memastikan software tidak memiliki bugs/kesalahan, atau setidak-
tidaknya menjamin bahwa software yang sedang dikembangkan sedikit bugs nya. Selain harus
memenuhi requirement, sebuah software hendaknya memiliki sedikit bugs, apalagi jika software yang
dikembangkan merupakan sistem kritis yang margin error nya harus sangat rendah. Software testing
berhubungan erat dengan kualitas software (software quality)
Dalam buku “Pragmatic Unit Testing” karya Andrew Hunt, disebutkan prinsip-prinsip utama dalam
membuat unit testing yang baik, yaitu :
1. Automatic
Testing harus bisa dilakukan secara otomatis dengna menggunakan tools, tertentu
2. Through
Testing harus dilakukan secara keseluruhan
3. Repeatable
Testing hasilnya tetap sama walaupun dilakukan secara berulang-ulang
4. Independent
Tidak tergantung pada modul lain
5. Independent
Menulis unit test sama prioritas nya seperti menulis source code utama
Tools untuk melakukan unit testing dapat menggunakan yang open source seperti Nunit, atau fitur built
ini IDE Visual Studio 2008 Professional/Team System.
Class Calculator memiliki dua buah method yaitu : Add(), dan Multiply(). Kedua method ini berguna
untuk menambah dan mengalikan dua buah bilangan integer. Masing-masing method memiliki return
value dengan tipe integer. Untuk melakukan test pada class tersebut buatkan sebuah test class nya :
[TestClass]
public class CalculatorTest
{
private Calculator calculator;
public CalculatorTest()
{
calculator=new Calculator();
}
[TestMethod]
public void TestAdd()
{
Assert.AeEqual(2,calculator.Add(1,1));
}
[TestMethod]
public void TestMultiply()
{
Assert.AreEqual(4, calculator.Add(2, 2));
}
}
Setelah menandai semua method yang akan ditest dengan menggunakan atribut [TestMethod],
selanjutnya panggil static class Assert , berikut method-method yang ada :
Method Keterangan
AreEqual() Membandingkan nilai expected (yang diharapkan) dengan nilai actual. Jika
sama(equal) maka return value nya true
[TestClass]
public class CategoryTest
{
private ICategoryRepository categoryRepository;
public CategoryTest()
{
ObjectContainer.SetApplicationConfig("Configuration.xml");
ObjectContainer.AddRegistry(new DepedencyRegistry());
categoryRepository= ObjectContainer
.GetObject<ICategoryRepository>("categoryRepository");
}
[TestMethod]
public void FindById()
{
Category category = categoryRepository.FindById(1);
Assert.AreEqual("Beverages", category.CategoryName);
}
[TestMethod]
public void FindAll()
{
List<Category> categories = categoryRepository.FindAll();
Assert.AreEqual("Beverages", categories[0].CategoryName);
}
[TestMethod]
public void TestSave()
{
Category category = new Category();
category.CategoryName = "Chinese Food";
Assert.AreEqual(1,categoryRepository.Save(category));
}
[TestMethod]
public void TestUpdate()
{
Category category = new Category();
category.CategoryId = 1;
category.CategoryName = "Japanese Food";
Assert.AreEqual(1,categoryRepository.Update(category));
}
P a g e | 56
[TestMethod]
public void TestDelete()
{
Category category = new Category();
category.CategoryId = 1;
Assert.AreEqual(1,categoryRepository.Delete(category));
}
}
BAB 4
Logging
Sebuah aplikasi yang masuk kategori skala enterprise seharusnya ditambahkan kemampuan
application logging untuk memonitor kondisi aplikasi yang sedang berjalan. Logging ini sangat berperan
jika suatu saat terjadi kesalahan/failure pada aplikasi, administrator atau programmer yang
bertanggung jawab dapat dengan mudah melacak kesalahan yang terjadi dan segera melakukan
perbaikan secepatnya. Umumnya log aplikasi ini disimpan disebuah file text yang dapat dibaca
dengan mudah yang berisi tanggal dan waktu kejadian beserta pesan kesalahan.
Origami menyediakan fitur logging yang cukup lengkap untuk monitoring aplikasi, diantaranya :
1. Mendukung banyak tipe logging seperti : console, file, database, event log, SMTP, trace, dan
messaging.
2. Mendukung penggunaan lebih dari satu tipe logger secara bersamaan
3. Tipe logger dapat diubah dengan hanya dengan mengedit konfigurasinya
Untuk menggunakan fitur logging di Origami, sebelumnya harus menambahkan terlebih dahulu
namespace Origami.Logging. Selanjutnya tinggal menggunakan class-class Logger yang tersedia.
Logger Keterangan
ConsoleLogger Log output dikirim ke Console
FileLogger Log output dikirim ke file
DbLogger Log ditulis ke tabel di basis data, tabel tersebut harus di buat terlebih
dahulu dengan nama LOGS
EventLogger Log ditulis ke Event Log milik Windows yang bisa diakses dari
Control Panel -> Administrative Tools -> Event Viewer
SmtpLogger Log dikirim lewat e-mail melalui protokol SMTP
TraceLogger Log dimunculkan di debug window Visual Studio.NET/Express
Edition
MessagingLogger Log dikirim ke messaging queue MSMQ
Untuk menggunakan objek loggervgunakan static class LoggerFactory untuk membuat jenis logger yang
diinginkan.
Parameter severity pada method Write menyatakan jenis pesan log yang muncul yaitu : Debug, Error,
Fatal, Information, dan Warning. Sedangkan message adalah pesan yang hendak ditulis pada log
Contoh lainnya :
File Logger
Db Logger
IDataContext dx = DataContextFactory.CreateInstance(dataSource);
Jika menggunakan DbLogger terlebih dahulu harus dibuatkan tabel “Logs” di database aplikasi. Berikut
ini adalah struktur dari tabel Logs :
Event Logger
logger.EventSource = "Application";
logger.Write(Severity.Info, "Log ini ditulis ke EventLog Windows");
Trace Logger
Smtp Logger
Messaging Logger
logger.Path = @".\Private$\MyQueue";
logger.Write(Severity.Info, "Log ini ditulis ke MS MQ");
File Logger
Trace Logger
P a g e | 60
Interface ILogger diletakkan di setiap constructor repository class, sehingga constructor memiliki dua
object dependency yaitu “dx” dan “logger”. Dua object ini diinstantiasi di class DepedencyRegistry()
dengan menggunakan constructor injection.
ds.Provider = "System.Data.SqlClient";
ds.ConnectionString = @"Source=XERIS\SQLEXPRESS;
+ "Integrated Security=True";
dx = DataContextFactory.CreateInstance(ds);
ILogger logger = LoggerFactory.CreateFileLogger(@"c:\log.txt");
ObjectContainer.RegisterObject("employeeRepository",
typeof(EmployeeRepository), depedency);
}
}
P a g e | 61
Seperti yang terlihat pada source code diatas, semua dependency diinstantiasi di
DepedencyRegistry(),object DataContext dikonstruksi melalui DataContextFactory, sedangkan objek
logger di konstruksi menggunakan LoggerFactory dengan tipe FileLogger. Semua log yang dipasang di
repository class pada contoh diatas akan disimpan ke file log.txt.
Pada dasarnya kita bebas menuliskan apa pun kedalam log. Biasanya apa yang ditulis di log adalah
“exception” atau status suatu operasi. Contoh :
result=dx.ExecuteNonQuery(q.GetSql());
}
catch(Exception ex)
{
logger.Write(Severity.Error,ex.Message.ToString());
}
return result;
}
Contoh lain :
object[] values={employee.LastName,employee.FirstName,
employee.BirthDate,employee.HireDate};
return dx.ExecuteNonQuery(q.GetSql());
}
P a g e | 62
<object id="employeeRepository"
type="Northwind.Repository.Implementation.EmployeeRepository,
Nortwind.Repository">
<constructor-arg ref="dx"/>
<constructor-arg ref="logger2"/>
</object>
</objects>
</container>
Pada konfigurasi diatas terdapat tiga buah logger yang berbeda, yaitu ConsoleLogger (logger1),
FileLogger (logger2), dan DbLogger (logger3). File Logger dan DbLogger memiliki depedency yang
masing-masing di inject di property dan constructor. Berikut ini bagaimana cara mengakses logger di
Container :
ObjectContainer.SetApplicationConfig("Configuration.xml");
BAB 5
Security
Security adalah merupakan bagian penting dari sebuah aplikasi. Tanpa adanya security aplikasi yang
bagus sekalipun akan kehilangan asset nya yang berharga, yaitu data. Ada beberapa teknik untuk
mengamankan aplikasi yang telah kita bangun diantaranya adalah melarang orang yang tidak berhak
untuk menggunakan aplikasi, atau melarang menggunakan fitur tertentu oleh user yang sudah memiliki
hak akses. Berikut ini beberapa terminologi penting dalam security :
Istilah Defenisi
Account Account mewakili seseorang, aplikasi layanan/service, atau sistem komputer
dimana diatur security dan informasi akses.
Roles Roles adalah pengelompokan logis dari account. Roles dapat digunakan untuk
pengaturan security dan diaplikasikan ke semua account yang menjadi anggota
dari roles tersebut
Permissions Izin untuk menentukan apakah roles atau account diizinkan atau ditolak
mengakses sumber daya spesifik
Authentication Proses dimana suatu entiti menyediakan credential sebagai bukti identitasnya
Authorization Proses dimana sistem menentukan apakah seorang pengguna terautentikasi
boleh mengakses sumber daya tertentu
Credential Informasi yang dibutuhkan untuk keperluan autentikasi, biasanya berisi nama
account dan password. Credential bias juga berisi sebuah sertifikat (misalya MS
Passport) atau biometrik (sidik jari, retina mata)
Confidentiality Proses untuk melindungi identitas pengguna atau isi pesan agar tidak bisa dibaca
oleh orang lain yang tidak berhak
Data Integrity Proses untuk melindungi data agar tidak diubah oleh orang lain
5.1 Authentication
Origami menyediakan tiga cara untuk melakukan authentikasi, yaitu melalui XML dan Database
XML Authentication
else {
Console.WriteLine("You're not authenticated");
}
Users.xml
Database Authentication
dataSource.Provider = "System.Data.SqlClient";
dataSource.ConnectionString = @"Data Source=XERIS\SQLEXPRESS;"
+ "Initial Catalog=Northwind;Integrated Security=True";
Untuk menggunakan database authentication sebelumnya harus membuat sebuah tabel “Users” dengan
struktur sebagai berikut :
5.2 Authorization
Seperti yang telah dijelaskan sebelumnya, authorization adalah proses dimana sistem menentukan
apakah seorang pengguna terautentikasi boleh mengakses sumber daya tertentu. Seperti
authentication, authorization pun dapat dilakukan melalui XML dan database.
XML Authorization
Console.WriteLine("authorized!");
}
}
Database Authorization
dataSource.Provider = "System.Data.SqlClient";
dataSource.ConnectionString = @"Data Source=XERIS\SQLEXPRESS;"
+ "Initial Catalog=Northwind;Integrated Security=True";
if (isAuthenticated)
{
bool isAuthorized = auth.IsUserInRole("neonerdy", "administrator");
if (isAuthorized)
{
Console.WriteLine("authorized!");
}
}
Column Name Data Type Column Name Data Type Column Name Data Type
UserId Int RoleId Int UserId Int
UserName Varchar(50) RoleName Varchar(50) RoleId Int
Password Varchar(50)
Configuration.xml
</objects>
</container>
Cara mengaksesnya :
ObjectContainer.SetApplicationConfig("Configuration.xml");
IauthenticationProvider auth=ObjectContainer
.GetObject<IAuthenticationProvider>("xmlAuth");
5.3 Cryptography
Cryptography adalah teknik untuk menyandikan (encode) sebuah pesan menjadi tidak bisa dibaca
oleh orang yang tidak berkepentingan. Teknik kriptografi menjamin kerahasiaan (confidentiality),
integritas data (data integrity), dan pengesahan (authentication). Kerahasiaan berarti bahwa data
yang dienkripsi teracak dan tersembunyi maknanya. Integritas data mencegah kerusakan data, dan
pengesahan adalah pembuktian identitas dari pengirim untuk memastikan orang yang berhak.
SymmetricCryptography crypto =
new SymmetricCryptography(SymmetricProvider.DES);
crypto.Key = "secret";
crypto.Salt = "xf09uxc6";
Source code diatas akan mengenkripsi teks “Hello World” dengan algoritma DES menjadi
ONEUFoGzbbc43X/yj/Wl2g==
Decrypt
SymmetricCryptography crypto =
new SymmetricCryptography(SymmetricProvider.DES);
crypto.Key = "secret";
crypto.Salt = "xf09uxc6";
Output :
wOw29NVUE4JxJBvKvAxHIT54mJiklUpUi3amTNOJpcYwhTZUVVx9GIj26AecJ5VUItPVcFUBi8NJFmRD
04eTUzPd+eMjkjLFc6xpSuK/y/L6skBG7g5qOD17ze4Wtk7MMWh0Lhni1jeDJ8zOeFwNmYr9Dyg+LJ+F
7nUpeDm+6MI=
Private key dan public key disimpan di file text. Untuk mendapatkan kedua kunci ini gunakan method
GenerateKeyPairs()
Output :
sQqNsWTgdUEFt6mb5y4/5Q==
Configuration.xml
<object id="asymmetric"
type="Origami.Security.Cryptography.AsymmetricCryptography,Origami">
<property name="PrivateKey" value="c:\data\private.txt" />
<property name="PublicKey" value="c:\data\public.txt" />
</object>
<object id="hash"
type="Origami.Security.Cryptography.HashCryptography,Origami">
<property name="Algorithm" value="MD5" />
<property name="Key" value="secret" />
<property name="Salt" value="xf09uxc6" />
</object>
</objects>
</container>
P a g e | 69
Symmetric Cryptography
ObjectContainer.SetApplicationConfig("Configuration.xml");
SymmetricCryptography crypto =
ObjectContainer.GetObject<SymmetricCryptography>("symmetric");
Asymmetric Cryptography
ObjectContainer.SetApplicationConfig("Configuration.xml");
AsymmetricCryptography crypto =
ObjectContainer.GetObject<AsymmetricCryptography>("asymmetric");
Hash Cryptography
ObjectContainer.SetApplicationConfig("Configuration.xml");
HashCryptography crypto =
ObjectContainer.GetObject<HashCryptography>("hash");
Lampiran
Source Code Lengkap
Configuration.xml
<object id="categoryRepository"
type="Northwind.Repository.Implementation.CategoryRepository,
Northwind.Repository">
<constructor-arg ref="dx"/>
<constructor-arg ref="logger"/>
</object>
<object id="customerRepository"
type="Northwind.Repository.Implementation.CustomerRepository,
Northwind.Repository">
<constructor-arg ref="dx"/>
<constructor-arg ref="logger"/>
</object>
<object id="employeeRepository"
type="Northwind.Repository.Implementation.EmployeeRepository,
Northwind.Repository">
<constructor-arg ref="dx"/>
<constructor-arg ref="logger"/>
</object>
<object id="productRepository"
type="Northwind.Repository.Implementation.ProductRepository,
Northwind.Repository">
<constructor-arg ref="dx"/>
<constructor-arg ref="logger"/>
</object>
</objects>
</container>
P a g e | 71
Customer
namespace Northwind.Model
{
public class Customer
{
public string CustomerId { get; set; }
}
}
Category
using System.Collections.Generic;
namespace Northwind.Model
{
public class Category
{
public int CategoryId { get; set; }
Product
using System;
namespace Northwind.Model
{
public class Product
{
public int ProductId { get; set; }
}
}
CustomerMapper
using System;
using System.Data;
using Origami.Data;
using Northwind.Model;
namespace Northwind.Repository.Mapping
{
public class CustomerMapper : IDataMapper<Customer>
{
public Customer Map(IDataReader rdr)
{
Customer customer = new Customer();
return customer;
}
}
}
CategoryMapper
using System;
using System.Data;
using Origami.Data;
using Northwind.Model;
namespace Northwind.Repository.Mapping
{
public class CategoryMapper : IDataMapper<Category>
{
public Category Map(IDataReader rdr)
{
P a g e | 73
return category;
}
}
}
CategoryProxy
using System;
using System.Collections.Generic;
using Origami.Container;
using Northwind.Model;
namespace Northwind.Repository.Mapping
{
public class CategoryProxy : Category
{
private bool productLoaded = false;
public override List<Product> Products
{
get
{
List<Product> products;
if (!productLoaded)
{
IProductRepository productRepository = ObjectContainer
.GetObject<IProductRepository>("productRepository");
products = productRepository
.FindByCategoryId(this.CategoryId);
base.Products = products;
productLoaded = true;
}
else
{
products=base.Products;
}
return products;
}
set
{
base.Products = value;
productLoaded = true;
}
}
}
}
P a g e | 74
ProductMapper
using System;
using System.Data;
using Origami.Data;
using Northwind.Model;
namespace Northwind.Repository.Mapping
{
public class ProductMapper : IDataMapper<Product>
{
public Product Map(IDataReader rdr)
{
Product product = new Product();
return product;
}
}
}
ICustomerRepository
using System;
using System.Collections.Generic;
using Origami.Data;
using Northwind.Model;
namespace Northwind.Repository
{
public interface ICustomerRepository : IRepository<Customer>
{
List<Customer> FindByName(string name);
}
}
P a g e | 75
ICategoryRepository
using System;
using Origami.Data;
using Northwind.Model;
namespace Northwind.Repository
{
public interface ICategoryRepository : IRepository<Category>
{
}
}
IProductRepository
using System;
using System.Collections.Generic;
using Origami.Data;
using Northwind.Model;
namespace Northwind.Repository
{
public interface IProductRepository : IRepository<Product>
{
List<Product> FindByName(string name);
List<Product> FindByCategory(string categoryName);
List<Product> FindByCategoryId(object id);
}
}
CustomerRepository
using System;
using System.Collections.Generic;
using Origami.Container;
using Origami.Data;
using Origami.Logging;
using Northwind.Model;
using Northwind.Repository.Mapping;
namespace Northwind.Repository.Implementation
{
public class CustomerRepository : ICustomerRepository
{
private IDataContext dx;
private ILogger logger;
private string tableName = "Customers";
this.logger = logger;
}
return dx.ExecuteList<Customer>(q.GetSql(),
new CustomerMapper());
}
return dx.ExecuteNonQuery(q.GetSql());
}
return dx.ExecuteNonQuery(q.GetSql());
}
P a g e | 77
return dx.ExecuteNonQuery(q.GetSql());
}
}
}
CategoryRepository
using System;
using System.Collections.Generic;
using Origami.Container;
using Origami.Data;
using Origami.Logging;
using Northwind.Model;
using Northwind.Repository.Mapping;
namespace Northwind.Repository.Implementation
{
public class CategoryRepository : ICategoryRepository
{
private IDataContext dx;
private ILogger logger;
private string tableName = "Categories";
private IProductRepository productRepository;
return category;
}
List<Category> categories=dx.ExecuteList<Category>(q.GetSql(),
new CategoryMapper());
return categories;
}
return dx.ExecuteNonQuery(q.GetSql());
}
return dx.ExecuteNonQuery(q.GetSql());
return dx.ExecuteNonQuery(q.GetSql());
}
}
}
ProductRepository
using System;
using System.Collections.Generic;
using Origami.Container;
using Origami.Data;
using Origami.Logging;
using Northwind.Model;
using Northwind.Repository.Mapping;
P a g e | 79
namespace Northwind.Repository.Implementation
{
public class ProductRepository : IProductRepository
{
private IDataContext dx;
private ILogger logger;
private string tableName = "Products";
result=dx.ExecuteNonQuery(q.GetSql());
}
catch (Exception ex)
{
logger.Write(Severity.Error,ex.Message);
throw ex;
}
return result;
}
result=dx.ExecuteNonQuery(q.GetSql());
}
catch (Exception ex)
{
logger.Write(Severity.Error, ex.Message);
throw ex;
}
return result;
}
P a g e | 81
result=dx.ExecuteNonQuery(q.GetSql());
}
catch (Exception ex)
{
logger.Write(Severity.Error, ex.Message);
throw ex;
}
return result;
}
}
}
P a g e | 82
CustomerUI
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Origami.Container;
using Northwind.Repository;
using Northwind.Model;
namespace Northwind.Presentation
{
public partial class CustomerUI : Form
{
enum FormState
{
New,Edit
}
public CustomerUI()
{
InitializeComponent();
customerRepository = ObjectContainer
.GetObject<ICustomerRepository>("customerRepository");
}
item.SubItems.Add(cust.CompanyName);
item.SubItems.Add(cust.ContactName);
item.SubItems.Add(cust.Address);
item.SubItems.Add(cust.Phone);
lvwCustomer.Items.Add(item);
lvwCustomer.Items.Clear();
foreach (Customer cust in custs)
{
FillListView(cust);
}
}
txtCustomerID.Text = cust.CustomerId;
txtCompanyName.Text = cust.CompanyName;
txtContactName.Text = cust.ContactName;
txtAddress.Text = cust.Address;
txtPhone.Text = cust.Phone;
}
cust.CustomerId = txtCustomerID.Text;
cust.CompanyName = txtCompanyName.Text;
cust.ContactName = txtContactName.Text;
cust.Address = txtAddress.Text;
cust.Phone = txtPhone.Text;
customerRepository.Save(cust);
cust.CustomerId = txtCustomerID.Text;
cust.CompanyName = txtCompanyName.Text;
cust.ContactName = txtContactName.Text;
cust.Address = txtAddress.Text;
cust.Phone = txtPhone.Text;
customerRepository.Update(cust);
Clear();
FillCustomer();
tabControl1.SelectedTab = this.tabPage1;
}
}
}
P a g e | 86
ProductUI
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Origami.Container;
using Northwind.Model;
using Northwind.Repository;
namespace Northwind.Presentation
{
public partial class ProductUI : Form
{
private IProductRepository productRepository;
private ICategoryRepository categoryRepsoitory;
public ProductUI()
{
InitializeComponent();
productRepository=ObjectContainer
.GetObject<IProductRepository>("productRepository");
categoryRepsoitory = ObjectContainer
.GetObject<ICategoryRepository>("categoryRepository");
}
P a g e | 87
item.SubItems.Add(p.ProductName);
item.SubItems.Add(p.Category.CategoryName);
item.SubItems.Add(p.QuantityPerUnit.ToString());
item.SubItems.Add(p.UnitPrice.ToString());
item.SubItems.Add(p.UnitsInStock.ToString());
lvwProduct.Items.Add(item);
}
lvwProduct.Items.Clear();
foreach (Product p in products)
{
FillListView(p);
}
}
lvwProduct.Items.Clear();
foreach (Product p in products)
{
FillListView(p);
}
}
P a g e | 88
}
}
P a g e | 89
Daftar Pustaka
Ariyanto, “.NET Data Access Layer Framework Undercover ”, INDC, Jakarta, 2009.
Ariyanto, “.NET Enterprise Application Programming”, INDC, Jakarta, 2008.
Eposito, Dino, “Architecting Microsoft® .NET Solutions for the Enterprise”, Microsoft Press, USA,2008.
Eric, Gamma, “Design Patterns : Element of Reusable Object-Oriented Software”, Addison
Wesley, USA, 1995.
Fowler, Martin, “Patterns of Enterprise Application Architecture”, Addison Wesley, USA, 2002.
Irwan, Djon, “Perancangan Object Oriented Software dengan UML”, Andi Yogyakarta, 2006.
Len, Fenster, “Effectife Use of Microsoft Enterprise Library : Building Blocks for Creating
Enterprise Application and Service”, Addison Wesley, USA, 2006.
Mehta, Vijay. “Pro LINQ Object Relational Mapping with C# 2008”, Apress, USA, 2008.
Microsoft, “Application Architecture for .NET : Designing Applications and Services ”, Microsoft
Corporation, USA, 2002.
Microsoft, “.NET Data Access Architecture Guide ”, Microsoft Corporation, USA, 2003.
Xin, Chen, “Developing Application Framework in .NET”, Apress, USA, 2004.
P a g e | 90
Biografi Penulis
Ariyanto, Software Engineer Petrolink Services Indonesia (www.petrolink.com).
Pada waktu senggangnya mengajar di Direktorat Program Diploma IPB program
keahlian Manajemen Informatika, sebagai koordinator dan dosen mata kuliah
Pemrograman Berorientasi Objek dan Basis Data Client Server. Saat ini tertarik
pada Object Oriented Technology, Software Engineering, dan Design Pattern.
Informasi lebih lanjut mengenai Origami Framework dan penulis bisa didapat
melalui E-mail : [email protected]