Feedback

XMLIO – einfachstes (De)serialisieren von/zu XML-Dateien

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace DotNetExpansions.IO
{
   /// <summary>
   /// Vereinfacht das Laden, Validieren und Speichern von XML-Dateien.
   /// </summary>
   /// <remarks>
   /// The first example uses a simple business object.
   /// The second example uses a complex business object with nested object.
   /// The third example shows the use of XmlIo with a dictionary
   ///  which holds values of different types.
   ///  Note: The use of such a configuration technique is not recommended
   ///  but XmlIo is able to handle even that.
   /// The fourth example shows the usage of XSD validation with the same simple business object
   ///  from the first sample.
   /// </remarks>
   /// <example>
   /// This demo shows the use of XmlIo with a very simple business object.
   /// <code>
   /// <![CDATA[
   /// namespace SimpleConfigDemo
   /// {
   ///    public class SimpleConfig
   ///    {
   ///       public byte Dimensions { get; set; }
   ///       public int HyperspaceEntrySection { get; set; }
   ///       public string NanobotsEmitterName { get; set; }
   ///       public string PicobotControllerIP { get; set; }
   ///       public float WarpFactor { get; set; }
   ///    }
   /// }
   /// ]]>
   /// </code>
   /// </example>
   ///
   /// <example>
   /// <code>
   /// <![CDATA[
   /// using System;
   /// using System.Windows.Forms;
   /// using DotNetExpansions;
   /// 
   /// namespace SimpleConfigDemo
   /// {
   ///    class Program
   ///    {
   ///       static void Main()
   ///       {
   ///          var configManager = new XmlIo(Path.Combine(Environment.CurrentDirectory, "DemoConfig.xml"));
   ///          SimpleConfig config = CreateConfig();
   ///          Console.WriteLine("Saving Configuration...");
   ///          configManager.Save(config);
   ///          Console.WriteLine("Press any key to load the configuration."
   ///                            + Environment.NewLine);
   ///          Console.ReadKey();
   /// 
   ///          // Destroy the previously instantiated data transfer object for demonstration purposes.
   ///          config = null;
   ///          Console.WriteLine("Now loading the configuration..."
   ///                            + Environment.NewLine);
   ///          config = configManager.Load<SimpleConfig>();
   ///          ShowConfig(config);
   /// 
   ///          // Verhindert das selbsttätige Schließen des Konsolenfensters.
   ///          Console.WriteLine("nPress any key to terminate the program.");
   ///          Console.ReadKey();
   ///       }
   /// 
   ///       private static SimpleConfig CreateConfig()
   ///       {
   ///          var config = new SimpleConfig();
   ///          config.Dimensions = 7;
   ///          config.HyperspaceEntrySection = 1;
   ///          config.NanobotsEmitterName = "MyNanobotsEmitter";
   ///          config.PicobotControllerIP = "127.0.0.1";
   ///          config.WarpFactor = 10.0f;
   ///          return config;
   ///       }
   /// 
   ///       private static void ShowConfig(SimpleConfig config)
   ///       {
   ///          Console.WriteLine("Nanobots EmitterName: {0}", config.NanobotsEmitterName);
   ///          Console.WriteLine("Picobot Controller IP: {0}", config.PicobotControllerIP);
   ///          Console.WriteLine("Dimensions: {0}", config.Dimensions);
   ///          Console.WriteLine("Hyperspace Entry Section: {0}", config.HyperspaceEntrySection);
   ///          Console.WriteLine("Warp Factor: {0}", config.WarpFactor);
   ///       }
   ///    }
   /// }
   /// 
   /// /* Output:
   /// Saving Configuration...
   /// Press any key to load the configuration.
   /// 
   /// Now loading the configuration...
   /// 
   /// Nanobots EmitterName: MyNanobotsEmitter
   /// Picobot Controller IP: 127.0.0.1
   /// Dimensions: 7
   /// Hyperspace Entry Section: 1
   /// Warp Factor: 10
   /// 
   /// Press any key to terminate the program.
   /// */
   /// ]]>
   /// </code>
   /// </example>
   /// This demo generates te following XML file.
   /// <example>
   /// <code>
   /// <![CDATA[
   /// <SimpleConfig xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/SimpleConfigDemo">
   ///    <Dimensions>7</Dimensions>
   ///    <HyperspaceEntrySection>1</HyperspaceEntrySection>
   ///    <NanobotsEmitterName>MyNanobotsEmitter</NanobotsEmitterName>
   ///    <PicobotControllerIP>127.0.0.1</PicobotControllerIP>
   ///    <WarpFactor>10</WarpFactor>
   /// </SimpleConfig>
   /// ]]>
   /// </code>
   /// </example>
   /// <example>
   /// This demo shows the use of XmlIo with a complex business object which contains nested objects.
   /// <code>
   /// <![CDATA[
   /// using System.Drawing;
   /// 
   /// namespace NestedConfigDemo
   /// {
   ///    public class NestedConfig
   ///    {
   ///       public string MachineName { get; set; }
   ///       public UiConfig UiSettings { get; set; }
   ///       public UserConfig UserSettings { get; set; }
   ///       public DalConfig DalSettings { get; set; }
   /// 
   ///       public class UiConfig
   ///       {
   ///          public Size WindowSize { get; set; }
   ///          public Point WindowLocation { get; set; }
   ///          public Color BackgroundColor { get; set; }
   ///          public Color TextColor { get; set; }
   ///       }
   /// 
   ///       public class UserConfig
   ///       {
   ///          public string FirstName { get; set; }
   ///          public string LastName { get; set; }
   ///          public string Email { get; set; }
   ///       }
   /// 
   ///       public class DalConfig
   ///       {
   ///          public string ConnectionString { get; set; }
   ///       }
   ///    }
   /// }
   /// ]]>
   /// </code>
   /// </example>
   ///
   /// <example>
   /// <code>
   /// <![CDATA[
   /// using DotNetExpansions;
   /// 
   /// namespace NestedConfigDemo
   /// {
   ///    using System;
   ///    using System.Drawing;
   ///    using System.Windows.Forms;
   /// 
   ///    class Program
   ///    {
   ///       static void Main()
   ///       {
   ///          var configManager =
   ///          new XmlIo(Path.Combine(Environment.CurrentDirectory, "DemoConfig.xml");
   ///          NestedConfig config = CreateConfig();
   ///          configManager.Save(config);
   ///          config = null;
   /// 
   ///          try
   ///          {
   ///             config = configManager.Load<NestedConfig>();
   ///             ShowConfig(config);
   ///          }
   ///          catch(InvalidOperationException problem)
   ///          {
   ///             Console.WriteLine(problem.Message);
   ///             Console.WriteLine(problem.Data);
   ///          }
   /// 
   ///          // Verhindert das selbsttätige Schließen des Konsolenfensters.
   ///          Console.WriteLine("nPress any key to terminate the program.");
   ///          Console.ReadKey();
   ///       }
   /// 
   ///       private static NestedConfig CreateConfig()
   ///       {
   ///          var config = new NestedConfig();
   ///          config.DalSettings = new NestedConfig.DalConfig
   ///          {
   ///             ConnectionString = "Some Connection string"
   ///          };
   ///          config.MachineName = "MyComputer";
   ///          config.UiSettings = new NestedConfig.UiConfig
   ///          {
   ///             BackgroundColor = Color.White,
   ///             TextColor = Color.FromArgb(128, 0, 255),
   ///             WindowLocation = new Point(200, 100),
   ///             WindowSize = new Size(640, 480)
   ///          };
   ///          config.UserSettings = new NestedConfig.UserConfig
   ///          {
   ///             Email = "none@yourbusiness.com",
   ///             FirstName = "Santa",
   ///             LastName = "Claus"
   ///          };
   ///          return config;
   ///       }
   /// 
   ///       private static void ShowConfig(NestedConfig config)
   ///       {
   ///          Console.WriteLine("Connection string: {0}", config.DalSettings.ConnectionString);
   ///          Console.WriteLine("Machine name: {0}", config.MachineName);
   ///          Console.WriteLine("Background color: {0}", config.UiSettings.BackgroundColor);
   ///          Console.WriteLine("Text color: {0}", config.UiSettings.TextColor);
   ///          Console.WriteLine("Window location: {0}", config.UiSettings.WindowLocation);
   ///          Console.WriteLine("Window size: {0}", config.UiSettings.WindowSize);
   ///          Console.WriteLine("First name: {0}", config.UserSettings.FirstName);
   ///          Console.WriteLine("Last name: {0}", config.UserSettings.LastName);
   ///          Console.WriteLine("Email address: {0}", config.UserSettings.Email);
   ///       }
   ///    }
   /// }
   /// /* Output
   /// Connection string: Some Connection string
   /// Machine name: MyComputer
   /// Background color: Color [White]
   /// Text color: Color [A=255, R=128, G=0, B=255]
   /// Window location: {X=200,Y=100}
   /// Window size: {Width=640, Height=480}
   /// First name: Santa
   /// Last name: Claus
   /// Email address: none@yourbusiness.com
   /// 
   /// Press any key to terminate the program.
   /// */
   /// ]]>
   /// </code>
   /// </example>
   /// <example>
   /// This demo creates the following XML file.
   /// <code>
   /// <![CDATA[
   /// <NestedConfig xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/NestedConfigDemo">
   ///   <DalSettings>
   ///     <ConnectionString>Some Connection string</ConnectionString>
   ///   </DalSettings>
   ///   <MachineName>MyComputer</MachineName>
   ///   <UiSettings>
   ///     <BackgroundColor xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Drawing">
   ///       <d3p1:knownColor>164</d3p1:knownColor>
   ///       <d3p1:name i:nil="true" />
   ///       <d3p1:state>1</d3p1:state>
   ///       <d3p1:value>0</d3p1:value>
   ///     </BackgroundColor>
   ///     <TextColor xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Drawing">
   ///       <d3p1:knownColor>0</d3p1:knownColor>
   ///       <d3p1:name i:nil="true" />
   ///       <d3p1:state>2</d3p1:state>
   ///       <d3p1:value>4286578943</d3p1:value>
   ///     </TextColor>
   ///     <WindowLocation xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Drawing">
   ///       <d3p1:x>200</d3p1:x>
   ///       <d3p1:y>100</d3p1:y>
   ///     </WindowLocation>
   ///     <WindowSize xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Drawing">
   ///       <d3p1:height>480</d3p1:height>
   ///       <d3p1:width>640</d3p1:width>
   ///     </WindowSize>
   ///   </UiSettings>
   ///   <UserSettings>
   ///     <Email>none@yourbusiness.com</Email>
   ///     <FirstName>Santa</FirstName>
   ///     <LastName>Claus</LastName>
   ///   </UserSettings>
   /// </NestedConfig>
   /// ]]>
   /// </code>
   /// </example>
   /// <example>
   /// This demo shows the use of XmlIo with a dictionary which holds values of different types. Note: The use of such a configuration technique is not recommended but XmlIo is able to handle even that.
   /// <code>
   /// <![CDATA[
   /// // In case someone uses this kind of configuration storage (which is not recommended).
   /// using System.Collections.Generic;
   /// using System.Drawing;
   /// using System.Runtime.Serialization;
   /// 
   /// namespace ConfigListDemo
   /// {
   ///    [KnownType(typeof(Point))]
   ///    [KnownType(typeof(Size))]
   ///    [KnownType(typeof(Color))]
   ///    public class ConfigDictionary
   ///    {
   ///       public ConfigDictionary()
   ///       {
   ///          if(Configuration == null)
   ///             Configuration = new Dictionary<string, object>();
   ///       }
   /// 
   ///       public Dictionary<string, object> Configuration { get; set; }
   ///    }
   /// }
   /// ]]>
   /// </code>
   /// </example>
   ///
   /// <example>
   /// <code>
   /// <![CDATA[
   /// using System;
   /// using System.Drawing;
   /// using System.Windows.Forms;
   /// using DotNetExpansions;
   /// 
   /// namespace ConfigListDemo
   /// {
   ///    class Program
   ///    {
   ///       static void Main()
   ///       {
   ///          var yourConfig = CreateConfig();
   ///          var xmlIo = new XmlIo(Path.Combine(Environment.CurrentDirectory, "YourConfig.xml");
   ///          Console.WriteLine("Saving configuration");
   ///          xmlIo.Save(yourConfig);
   ///          yourConfig = null;
   ///          try
   ///          {
   ///             Console.WriteLine("Trying to load your config data...");
   ///             yourConfig = xmlIo.Load<ConfigDictionary>();
   ///             ShowConfig(yourConfig);
   ///          }
   ///          catch(InvalidOperationException problem)
   ///          {
   ///             Console.WriteLine(problem.Message);
   ///             Console.WriteLine(problem.Data);
   ///          }
   /// 
   ///          // Verhindert das selbsttätige Schließen des Konsolenfensters.
   ///          Console.WriteLine("nPress any key to terminate the program.");
   ///          Console.ReadKey();
   ///       }
   /// 
   ///       private static ConfigDictionary CreateConfig()
   ///       {
   ///          var config = new ConfigDictionary();
   ///          config.Configuration.Add("Integer", 1);
   ///          config.Configuration.Add("Double", 3.141592654);
   ///          config.Configuration.Add("String", "Hello world");
   ///          config.Configuration.Add("Point", new Point(100, 200));
   ///          config.Configuration.Add("Size", new Size(1024, 768));
   ///          config.Configuration.Add("RGB-color", Color.FromArgb(128, 0, 255));
   ///          config.Configuration.Add("named color", Color.Fuchsia);
   ///          return config;
   ///       }
   /// 
   ///       private static void ShowConfig(ConfigDictionary configDictionary)
   ///       {
   ///          foreach(var keyValuePair in configDictionary.Configuration)
   ///          {
   ///             Console.WriteLine("Your {0}: {1}", keyValuePair.Key, keyValuePair.Value);
   ///          }
   ///       }
   ///    }
   /// }
   /// /* Output:
   /// Saving configuration
   /// Trying to load your config data...
   /// Your Integer: 1
   /// Your Double: 3,141592654
   /// Your String: Hello world
   /// Your Point: {X=100,Y=200}
   /// Your Size: {Width=1024, Height=768}
   /// Your RGB-color: Color [A=255, R=128, G=0, B=255]
   /// Your named color: Color [Fuchsia]
   /// 
   /// Press any key to terminate the program.
   /// */
   /// ]]>
   /// </code>
   /// </example>
   /// <example>
   /// This demo creates the following XML file.
   /// <code>
   /// <![CDATA[
   /// <ConfigDictionary xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ConfigListDemo">
   ///   <Configuration xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
   ///     <d2p1:KeyValueOfstringanyType>
   ///       <d2p1:Key>Integer</d2p1:Key>
   ///       <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:int">1</d2p1:Value>
   ///     </d2p1:KeyValueOfstringanyType>
   ///     <d2p1:KeyValueOfstringanyType>
   ///       <d2p1:Key>Double</d2p1:Key>
   ///       <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:double">3.141592654</d2p1:Value>
   ///     </d2p1:KeyValueOfstringanyType>
   ///     <d2p1:KeyValueOfstringanyType>
   ///       <d2p1:Key>String</d2p1:Key>
   ///       <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:string">Hello world</d2p1:Value>
   ///     </d2p1:KeyValueOfstringanyType>
   ///     <d2p1:KeyValueOfstringanyType>
   ///       <d2p1:Key>Point</d2p1:Key>
   ///       <d2p1:Value xmlns:d4p1="http://schemas.datacontract.org/2004/07/System.Drawing" i:type="d4p1:Point">
   ///         <d4p1:x>100</d4p1:x>
   ///         <d4p1:y>200</d4p1:y>
   ///       </d2p1:Value>
   ///     </d2p1:KeyValueOfstringanyType>
   ///     <d2p1:KeyValueOfstringanyType>
   ///       <d2p1:Key>Size</d2p1:Key>
   ///       <d2p1:Value xmlns:d4p1="http://schemas.datacontract.org/2004/07/System.Drawing" i:type="d4p1:Size">
   ///         <d4p1:height>768</d4p1:height>
   ///         <d4p1:width>1024</d4p1:width>
   ///       </d2p1:Value>
   ///     </d2p1:KeyValueOfstringanyType>
   ///     <d2p1:KeyValueOfstringanyType>
   ///       <d2p1:Key>RGB-color</d2p1:Key>
   ///       <d2p1:Value xmlns:d4p1="http://schemas.datacontract.org/2004/07/System.Drawing" i:type="d4p1:Color">
   ///         <d4p1:knownColor>0</d4p1:knownColor>
   ///         <d4p1:name i:nil="true" />
   ///         <d4p1:state>2</d4p1:state>
   ///         <d4p1:value>4286578943</d4p1:value>
   ///       </d2p1:Value>
   ///     </d2p1:KeyValueOfstringanyType>
   ///     <d2p1:KeyValueOfstringanyType>
   ///       <d2p1:Key>named color</d2p1:Key>
   ///       <d2p1:Value xmlns:d4p1="http://schemas.datacontract.org/2004/07/System.Drawing" i:type="d4p1:Color">
   ///         <d4p1:knownColor>73</d4p1:knownColor>
   ///         <d4p1:name i:nil="true" />
   ///         <d4p1:state>1</d4p1:state>
   ///         <d4p1:value>0</d4p1:value>
   ///       </d2p1:Value>
   ///     </d2p1:KeyValueOfstringanyType>
   ///   </Configuration>
   /// </ConfigDictionary>
   /// ]]>
   /// </code>
   /// </example>
   /// <example>
   /// This last example shows the usage of the XSD validation with the same simple business object from the first sample.
   /// <code>
   /// <![CDATA[
   /// using System;
   /// using System.Windows.Forms;
   /// using DotNetExpansions;
   /// 
   /// namespace SchemaValidationDemo
   /// {
   ///    class Program
   ///    {
   ///       static void Main()
   ///       {
   ///          var configManager =
   ///             new XmlIo(Path.Combine(Environment.CurrentDirectory, "DemoConfig.xml");
   /// 
   ///          var config = new SimpleConfig();
   ///          config.Dimensions = 7;
   ///          config.HyperspaceEntrySection = 1;
   ///          config.NanobotsEmitterName = "MyNanobotsEmitter";
   ///          config.PicobotControllerIP = "127.0.0.1";
   ///          config.WarpFactor = 3.141592654;
   /// 
   ///          // Save config =========================================================
   /// 
   ///          Console.WriteLine("Saving Configuration...");
   ///          configManager.Save(config);
   ///          Console.WriteLine("Press any key to validate the configuration."
   ///                            + Environment.NewLine);
   ///          Console.ReadKey();
   /// 
   ///          // Validaion ===========================================================
   /// 
   ///          configManager.ValidationEvent += ConfigManagerValidationEvent;
   ///          ValidateConfig(configManager);
   ///          Console.WriteLine("Press any key to load the configuration."
   ///                         + Environment.NewLine);
   ///          Console.ReadKey();
   /// 
   ///          // Load config =========================================================
   /// 
   ///          // Destroy the previously instantiated data transfer object for demonstration purposes.
   ///          config = null;
   ///          Console.WriteLine("Now loading the configuration..."
   ///                            + Environment.NewLine);
   ///          try
   ///          {
   ///             config = configManager.Load<SimpleConfig>();
   ///             ShowConfig(config);
   ///          }
   ///          catch(InvalidOperationException problem)
   ///          {
   ///             Console.WriteLine(problem.Message);
   ///             Console.WriteLine(problem.Data);
   ///          }
   /// 
   ///          // Verhindert das selbsttätige Schließen des Konsolenfensters.
   ///          Console.WriteLine("nPress any key to terminate the program.");
   ///          Console.ReadKey();
   ///       }
   /// 
   ///       private static void ValidateConfig(XmlIo configManager)
   ///       {
   ///          bool isValid = configManager.FileIsValidWith("DemoConfig.xsd");
   ///          if(isValid)
   ///             Console.WriteLine("XML-File is valid.");
   ///          else
   ///             Console.WriteLine("XML-File is invalid.");
   ///          return;
   ///       }
   /// 
   ///       static void ConfigManagerValidationEvent(object sender, System.Xml.Schema.ValidationEventArgs e)
   ///       {
   ///          Console.WriteLine(e.Severity + ": " + e.Message);
   ///       }
   /// 
   ///       private static void ShowConfig(SimpleConfig config)
   ///       {
   ///          Console.WriteLine("Nanobots EmitterName: {0}", config.NanobotsEmitterName);
   ///          Console.WriteLine("Picobot Controller IP: {0}", config.PicobotControllerIP);
   ///          Console.WriteLine("Dimensions: {0}", config.Dimensions);
   ///          Console.WriteLine("Hyperspace Entry Section: {0}", config.HyperspaceEntrySection);
   ///          Console.WriteLine("Warp Factor: {0}", config.WarpFactor);
   ///       }
   ///    }
   /// }
   /// 
   /// ]]>
   /// </code>
   /// </example>
   ///
   /// <example>
   /// This is the XSD file content for validation.
   /// <code>
   /// <![CDATA[
   /// <?xml version="1.0" encoding="utf-8"?>
   /// <xs:schema xmlns:i="http://www.w3.org/2001/XMLSchema-instance" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/SchemaValidationDemo" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   ///    <xs:element name="SimpleConfig">
   ///       <xs:complexType>
   ///          <xs:sequence>
   ///             <xs:element name="Dimensions" type="xs:unsignedByte" />
   ///             <xs:element name="HyperspaceEntrySection" type="xs:unsignedInt" />
   ///             <xs:element name="NanobotsEmitterName" type="xs:string" />
   ///             <xs:element name="PicobotControllerIP" type="xs:string" />
   ///             <xs:element name="WarpFactor" type="xs:double" />
   ///          </xs:sequence>
   ///       </xs:complexType>
   ///    </xs:element>
   /// </xs:schema>
   /// ]]>
   /// </code>
   /// </example>
   /// <seealso cref="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.knowntypeattribute.aspx"/>
   /// <seealso cref="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx"/>
   public class XmlIo
   {
      #region Fields

      private static bool fileIsValid = true;
      private string fullFilename;

      #endregion Fields
      #region Events

      /// <summary>
      /// Tritt bei einem Validationsfehler ein.
      /// </summary>
      public event ValidationEventHandler ValidationEvent;

      #endregion Events
      #region Constructors

      /// <summary>
      /// Initialisiert eine neue Instanz der <see cref="XmlIo"/> Klasse.
      /// </summary>
      /// <param name="fullFilename">Der voll qualifizierte Dateiname (Pfad mit Dateiname und Extension)</param>
      public XmlIo(string fullFilename)
      {
         if(IsValidFullFilename(fullFilename))
            this.fullFilename = fullFilename;
         else
            throw new ArgumentException("fullFilename is invalid");
      }

      /// <summary>
      /// Initialisiert eine neue Instanz der <see cref="XmlIo"/> Klasse.
      /// </summary>
      /// <param name="filepath">Der Dateipfad, unter dem die XML-Datei abgelegt werden soll.</param>
      /// <param name="filename">Der Name der XML-Datei inklusive Extension.</param>
      [Obsolete("Dieser Konstruktor existiert nur noch für die Abwärtskompatibilität.", false)]
      public XmlIo(string filepath, string filename)
      {
         Filepath = ValidateFilepath(filepath);
         Filename = ValidateFilename(filename);
         fullFilename = Path.Combine(filepath, filename);
      }

      #endregion Constructors
      #region Properties

      /// <summary>
      /// Gibt den Pfad zur XML-Datei zurück.
      /// </summary>
      public string Filepath { get; private set; }

      /// <summary>
      /// Gibt den Namen der XML-Datei zurück.
      /// </summary>
      public string Filename { get; private set; }

      #endregion
      #region Public Methods

      /// <summary>
      /// Lädt eine XML-Datei für ein beliebiges business object.
      /// </summary>
      /// <typeparam name="T">Der Typ des Business-Objekts.</typeparam>
      /// <returns>Das Business-Objekt</returns>
      public T Load<T>() where T : class
      {
         var filePermissions = new FileIOPermission(
            FileIOPermissionAccess.Read, fullFilename);
         filePermissions.Assert();

         var fs = new FileStream(fullFilename, FileMode.Open, FileAccess.Read);
         var reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
         var ser = new DataContractSerializer(typeof(T));
         var config = ser.ReadObject(reader);
         fs.Close();
         return config as T;
      }

      /// <summary>
      /// Speichert eine XML-Datei für ein beliebiges Business Object.
      /// </summary>
      /// <typeparam name="T">Der Typ des Business Objects (die Angabe ist optional).</typeparam>
      /// <param name="businessObject">Das Business Object</param>
      public void Save<T>(T businessObject) where T : class
      {
         var filePermissions = new FileIOPermission(
            FileIOPermissionAccess.Write, fullFilename);
         filePermissions.Assert();

         var writer = new XmlTextWriter(fullFilename, Encoding.UTF8);
         if(writer == null)
            throw new NullReferenceException();
         writer.Formatting = Formatting.Indented;
         var ser = new DataContractSerializer(businessObject.GetType());
         ser.WriteObject(writer, businessObject);
         writer.Close();
      }

      /// <summary>
      /// Validiert eine XML-Datei mittels der angegebenen XSD-Datei.
      /// </summary>
      /// <param name="validationSchemaFilename">Die XSD-Datei</param>
      /// <returns><c>true</c> wenn die XML-Datei gültig ist, anderenfalls <c>false</c>.</returns>
      public bool FileIsValidWith(string validationSchemaFilename)
      {
         var filePermissions = new FileIOPermission(
            FileIOPermissionAccess.Read, fullFilename);
         filePermissions.Assert();

         var xmlReaderSettings = new XmlReaderSettings();
         xmlReaderSettings.Schemas.Add(
            null, Path.Combine(Path.GetDirectoryName(fullFilename), validationSchemaFilename));
         xmlReaderSettings.ValidationType = ValidationType.Schema;
         xmlReaderSettings.ValidationEventHandler += XmlValidationEventHandler;
         var config = XmlReader.Create(fullFilename, xmlReaderSettings);
         while(config.Read()) { }
         xmlReaderSettings.CloseInput = true;
         return fileIsValid;
      }

      #endregion Public Methods
      #region Private Methods

      private static bool IsValidFullFilename(string fullFilename)
      {
         return !string.IsNullOrEmpty(fullFilename) && Directory.Exists(Path.GetDirectoryName(fullFilename));
      }

      private string ValidateFilename(string filename)
      {
         if(!IsValidEntry(filename))
            throw new ArgumentException();
         if(!filename.EndsWith(".xml"))
            throw new ArgumentException("Filename-extension is either missing or wrong. It must be .xml");
         this.Filename = filename;
         return filename;
      }

      private string ValidateFilepath(string filepath)
      {
         if(!IsValidPath(filepath))
            throw new DirectoryNotFoundException();
         if(filepath.EndsWith(@""))