We basically have an interface called IDTO, a DTO class and
a DTOStore class in this design. The IDTO interface is the base interface for
the DTO. It contains the declaration for the generic business entity type. The
following is the code for the IDTO interface.
Listing 1
using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
namespace DTOServices
{
public interface IDTO<BE>
{
BE BusinessEntity
{
get;
set;
}
}
}
This IDTO interface is implemented by the DTO class. The class
contains the implementation for the generic business entity property declared in
the IDTO interface and is sealed to prevent further inheritance. The following
is the code for the DTO class.
Listing 2
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
namespace DTOServices
{
[Serializable()]
internal sealed class DTO <BE> : IDTO <BE>
{
private BE businessEntity;
public BE BusinessEntity
{
get { return businessEntity; }
set { businessEntity = value; }
}
}
}
The DTOStore class is responsible for creating, registering
and un-registering DTO instances. The following is the code for the DTOStore
class.
Listing 3
using System;
using System.Collections;
using System.Xml.Serialization;
using System.IO;
namespace DTOServices
{
public sealed class DTOStore<BE>
{
private static Hashtable dtoRegister = null;
private static readonly object lockObj = new object();
private static int key = -1;
private DTOStore()
{
}
public IDTO <BE>CreateDTO()
{
IDTO<BE> dto = new DTO<BE>();
return dto;
}
public IDTO<BE> GetDTO(int key)
{
lock (dtoRegister.SyncRoot)
{
if (dtoRegister.ContainsKey(key))
return (IDTO<BE>)dtoRegister[key];
}
return null;
}
public bool RegisterDTO(IDTO<BE> dtoObject)
{
if (dtoRegister.ContainsKey(dtoObject.GetHashCode()))
{
return false;
}
lock (dtoRegister.SyncRoot)
{
dtoRegister.Add(dtoObject.GetHashCode(), dtoObject);
key = dtoObject.GetHashCode();
}
return true;
}
public bool UnRegisterDTO(int key)
{
if (dtoRegister.ContainsKey(key))
{
lock (dtoRegister.SyncRoot)
{
dtoRegister.Remove(key);
key = -1;
return true;
}
}
return false;
}
public static int Key
{
get
{
return key;
}
}
public static DTOStore<BE> Instance
{
get
{
lock (lockObj)
{
return Nested.dtoStore;
}
}
}
internal class Nested
{
static internal readonly DTOStore <BE>dtoStore = new DTOStore<BE>();
static Nested()
{
dtoRegister = Hashtable.Synchronized(new Hashtable());
}
}
}
}
The DTOStore class contains a hash table called DTORegister
that acts as a container of DTO instances. Note the usage of the private
constructor in the DTOStore class to prevent its instantiation.
The DTOStore class contains the following important methods:
·
CreateDTO()
·
GetDTO()
·
RegisterDTO()
·
UnRegisterDTO()
While the CreateDTO method is used to create a new DTO
instance, the GetDTO method returns an IDTO instance from the DTORegister.
Actually, it returns IDTO Instance from the DTORegister hash table corresponding
to the hash code passed to it as a parameter. The RegisterDTO method registers
an IDTO instance with the DTOStore. This implies that it stores the IDTO
instance and its hash code in the DTORegister hash table. The UnRegister method
un-registers the IDTO instance from the DTOStore, i.e., it removes the occurrence
of the IDTO instance that corresponds to the hash code passed to it as a
parameter.
Note the usage of a nested class called "Nested"
within the DTOStore class. The class "Nested" within the DTOStore
class is used to ensure that multiple threads access only one DTOStore object
one at a time. The static constructor of this class is used to instantiate the
DTOStore instance called dtoStore. This is done only once during the entire
application's lifetime. Further, a synchronized object is used here to provide
a thread safe wrapper in case of multiple reads and writes.
The DTOStore class also contains two properties, Instance
and Key. The instance property is used to access an IDTO instance and the Key
property is used to retrieve the hash code of the DTO instance. Further, note
that the DTO class was marked internal as shown in the code in listing 2. An
instance of the DTO class is accessible only using the Instance property of the
DTOStore class.
Now, the Data Transfer Object that we have implemented
earlier can be used as shown in the following code snippet.
Listing 4: Using the Data Transfer Object
DataSet dataSet = new DataSet();
//Necessary code to populate the DataSet instance with data
IDTO<DataSet> idto = DTOServices.DTOStore<DataSet>.Instance.CreateDTO();
idto.BusinessEntity = dataSet;
if (DTOServices.DTOStore<DataSet>.Instance.RegisterDTO(idto))
{
int key = DTOServices.DTOStore<DataSet>.Key;
Response.Write("The hash code is " + key.ToString());
//Necessary code to pass this key to the other layers of the application
}
else
Response.Write("Error in registering the DTO instance.");
The code in listing 4 illustrates how we can use the generic
Data Transfer Object. Note that the Data Transfer Object can be used to store a
DataSet, a DataTable, a Custom Business Entity instance or any other data
container irrespective of its type. We can assign any business entity instance
using generic type parameter as illustrated above.