Project Documentation

Basic Objectives

Before the features of the advadev Data Storage component are documented – here an overview on the underlying general concept:

Objective of this component is to save data objects in generic data storages. The technical solution for that is to serialize this data objects to XML and therefore save them as strings. This XML together with the following information form a data entity which could be saved in a generic way:
  • ID: Each object to be saved must provide a unique ID (which will be ensured by the Interface IGenericObject which must be implemented from each data object)
  • FullClassName: This is necessary because objects of different types may have the same ID but of course they are different objects
  • Application Key: Objective is to save object from different applications in the same data storage. And in that data storage they must be uniquely identifiable
These data entity is represented by the class GenericEntitiy. This class is also responsible for the XML serialization and XML de-serialization:

731191

The main features of this component are implementations to save such “Genric Entities” in a XML file or a SQL database or other generic data storages. Those will be realized by implementations of the interface IGenericEntityDataStorage:

731192

The actual data storages (as they should be used) are implementations of the class IDataStorage. Those classes allow type save saving of data objects. Internal those classes are converting data objects into objects of the class GenericEntity and are using a matching “Generic Entity Data Storage” class to save those:

731193

Summarized: For each data storage there is a „Generic Entity Data Storage“ which is responsible for the actual saving. Adapted to that there is a “Data Storage” which can be used to save data objects type save

Additional to that also an implementation is provided which allows to publish such data storages as WCF service and to use such a published WCF service 

Prerequisites to use this component

All data object which should be saved in data storages provided by this component must satisfy the following requirements:
  • They must implement the interface IGenericObject
  • They must be XML serializable
To implement the interface IGenericObject a class must provide an ID property of the data type string. This is a basic prerequisite to identify objects in a data storage

The XML serializability can be implemented in two ways: Either the class must implement the interface IXmlSerializable or it must provide a public default constructor and for each property to be saved a public “Getter” and “Setter”

Example Code:
public class User : IGenericObject
{

    public User()
    {
        // NOTE: default constructor necessary for deserialization
    }

    public int Id
    {
        get;
        set;
    }

    public string Name
    {
        get;
        set;
    }

    string IGenericObject.GenericObjectId
    {
        get
        {
            return Id.ToString();
        }
    }

}

Notes

Until Release advadev Data Storage 1.0.0:
  • If a data object is not serializable (or if an error occurs during serialization) the object will not be saved. No exception will be thrown and no other information about that will be provided
  • If a data object is not de-serializable (or if an error occurs during de-serialization) a previously saved object could not be read. NULL will be returned / it will not be in the result list. No exception will be thrown and no other information about that will be provided
From Release advadev Data Storage 1.1.0:
  • If a data object is not serializable (or if an error occurs during serialization) the object will not be saved and an exception will be thrown
  • It will be checked while saving an object whether it is de-serializable (or if an error occurs during de-serialization). In the case of an error an exception will be thrown. But it can still happen, that there are saved objects which could not be de-serialized (e.g. if the XML-serialization has been changed after saving the object). In this case no object will be returned (NULL or a result list without that object). No other information about that will be provided 

Feature „XML File Data Storage“

The class XmlFileDataStorage represents a data storage that saves data objects in a XML file. In the constructor a file name must be provided and this file must be writeable and readable. But it must not exist. The class provides methods to save, find and delete data objects:

731194

The data will be saved in the XML file using the following schema (example XML):
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<GenericEntities>
    <GenericEntity EntityId="17" ApplicationKey="MyTestApp" FullClassName="foo.User">
        [here goes the serialized xml code of the user with ID 17]
    </GenericEntity>
    <GenericEntity EntityId="18" ApplicationKey="MyTestApp" FullClassName="foo.User">
        [here goes the serialized xml code of the user with ID 18]
    </GenericEntity>
</GenericEntities>

Example Code:
XmlFileDataStorage myDataStorage = new XmlFileDataStorage("Demo Application", ".\\datastorage.xml");
myDataStorage.Save<User>(new User(1, "Tom"));
User user = myDataStorage.Find<User>("1");

Feature „XML Directory Data Storage“

The class XmlDirectoryDataStorage represents a data storage that saves data objects in different XML files. Separate XML files in one directory will be used for each application and each class of data objects. In the constructor a path name must be provided and this directory must be writeable and readable. But it must not exist. The class provides methods to save, find and delete data objects:

731424

The directory structure:
…\[PATH NAME]\
	[APPLICATION KEY 1]\
		[FULL CLASS NAME 1].xml
		[FULL CLASS NAME 2].xml
	[APPLICATION KEY 2]\
		[FULL CLASS NAME 1].xml
		[FULL CLASS NAME 2].xml

Example Code:
XmlDirectoryDataStorage myDataStorage = new XmlDirectoryDataStorage("Demo Application", ".\\datastorages");
myDataStorage.Save<User>(new User(1, "Tom"));
User user = myDataStorage.Find<User>("1");

Notes:
Until Release advadev Data Storage 1.1.0:
  • Since the application key is used as directory name it must fit the naming requirements for directory names
From Release advadev Data Storage 1.1.1:
  • If an application key is used which does not fit the naming requirements for directory names a GUID will be used instead of the application key as directory name

Feature „Memory Data Storage“

The class MemoryDataStorage represents a data storage that saves data objects in the memory. These data are of course not saved in a persistent way. The intention of this special data storage is to use it in prototypes. There you can save data temporarily without a big effort. The class provides methods to save, find and delete data objects:

731195

Example Code:
MemoryDataStorage myDataStorage = new MemoryDataStorage("Demo Application");
myDataStorage.Save<User>(new User(1, "Tom"));
User user = myDataStorage.Find<User>("1");

Feature „SQL Server Data Storage“

The class SqlServerDataStorage represents a data storage that saves data objects in a SQL server database. This database must provide a table with the following design and the name tGenericEntities:

731196

The column „id“ is a synthetic key which is used only internal. It is defined as „primary key“ with the attribute „auto increment“

In the constructor a connection string must be provided and the access rights for the database users must be set. The class provides methods to save, find and delete data objects:

731197

Here a typical connection string:
<add name="SQLServerConnectionString"
     connectionString="Data Source=localhost\SQLEXPRESS;
                       Initial Catalog=DATABASE;User Id=USERNAME;Password=PASSWORD" />

Example Code:
SqlServerDataStorage myDataStorage = new SqlServerDataStorage("Demo Application", "SQLServerConnectionString");
myDataStorage.Save<User>(new User(1, "Tom"));
User user = myDataStorage.Find<User>("1");

Feature „Service Data Storage“

The class ServiceDataStorage represents a data storage which is published as WCF service. In the constructor the service configuration must be provided (as endpoint configuration name). The class provides methods to save, find and delete data objects:

731198

The implementation design of the component allows securing such a service by a username / password combination. These data can also be defined in the constructor. In addition to that it is designed, that a service can provide information about applications (the keys of them) using it. This is designed for an administrative purpose. To prevent that all service users can access this information it can be secured by administrator username / password credentials

The endpoint configuration of a service data storage as example:
<system.serviceModel>
  <bindings>
    <customBinding>
      <binding name="dataStorageBinding">
        <security authenticationMode="UserNameOverTransport" />
        <windowsStreamSecurity />
        <httpTransport maxReceivedMessageSize="999999999" />
      </binding>
    </customBinding>
  </bindings>
  <client>
    <endpoint name="MYSERVICE" address="http://localhost/MyDataStorageService.svc" 
              binding="customBinding" contract="advadev.DataStorage.IDataStorageService" 
              bindingConfiguration="dataStorageBinding" />
  </client>
</system.serviceModel>

Example Code:
ServiceDataStorage myDataStorage = new ServiceDataStorage("Demo Application", "MYSERVICE", "USERNAME", "PASSWORD");
myDataStorage.Save<User>(new User(1, "Tom"));
User user = myDataStorage.Find<User>("1");

For further information please have a look on the feature „Data Storage Service“

Feature „Data Storage Service“

The class DataStorageService represents a WCF service. It allows publishing one of the generic data storages as service (which can then be accessed by service data storages). In the constructor the generic data storage (an implementation of the interface IGenericEntityDataStorage) to be used must be provided. The service contract for a WCF service is represented by the interface IDataStorageService:

731199

Summary: on the client side („ServiceDataStorage“) data objects will be converted into objects of the class GenericEntity. Those will be transmitted with the WCF service. And on the server side („DataStorageService“) this “Generic Entitiy” objects will be saved in a „Generic Entity Data Storage“

Example configuration for a data storage which is published as web service:
<system.serviceModel>
  <bindings>
    <customBinding>
      <binding name="binding">
        <security authenticationMode="UserNameOverTransport"/>
        <windowsStreamSecurity />
        <httpTransport maxReceivedMessageSize="999999999" />
      </binding>
    </customBinding>
  </bindings>
  <behaviors>
    <serviceBehaviors>
      <behavior name="MemoryDataStorageServiceBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
        <serviceCredentials>
          <userNameAuthentication userNamePasswordValidationMode="Custom" … />
        </serviceCredentials>
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <services>
    <service name="advadev.DataStorage.Demo.Web.MemoryDataStorageService" 
             behaviorConfiguration="MemoryDataStorageServiceBehavior">
      <endpoint address="" binding="customBinding" bindingConfiguration="binding" 
                contract="advadev.DataStorage.IDataStorageService" />
    </service>
  </services>
</system.serviceModel>

Additional information

More Information is available in my blog: click here. Unfortunately it is at the moment only available in german

Thomas Gysser | www.advadev.de | advadev.blogspot.de
... advanced development

Last edited Sep 19, 2013 at 7:41 AM by advadev, version 18