Implementing a Generic Data Transfer Object in C#
 
Published: 27 Mar 2007
Abstract
This article discusses how we can implement a Data Transfer Object (DTO) in C# with code examples.
by Joydip Kanjilal
Feedback
Average Rating: 
Views (Total / Last 10 Days): 45719/ 38

Introduction

This article discusses implementation of a generic Data Transfer Object that can be used in lieu of passing instances of DataSets or Custom Business Entities from the User Interface Layer to the other layers of an application.

Introducing Data Transfer Object

A Data Transfer Object (DTO) is one that can be used to pass data across the layers of an application. In this article I will demonstrate how we can implement a generic Data Transfer Object that can be used in lieu of DataSet, DataTable or even Custom Business Entity instances to transfer data through the layers of an application.

This implementation of the DTO comprises of a generic Business Entity that can be a DataSet instance, a DataTable instance, a Custom Business Entity instance, etc. as the data container. The instances of the DTO are in turn stored in a DTO Register, which actually is a hash table that stores the DTO instances as key - value pairs, the key being the hash code of the DTO instance and the value being the DTO instance itself. This hash code is actually used to pass data across the layers of the application. Such a design promotes loose coupling, flexibility and re-usability in your architecture. I have used generics in this design to use any business entity instance as a data container.

Implementing a generic Data Transfer Object

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.

Conclusion

In this article I have illustrated how we can implement a generic Data Transfer Object in C#. Usage of a Data Transfer Object in lieu of instances of DataSet, DataTable, Custom Business, etc. would facilitate loose coupling and flexibility in your designs. We can change the type of the data container seamlessly as and when it is needed without having to change much of the application's code.



User Comments

No comments posted yet.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-03-28 5:57:36 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search