April 2005 - Posts

After having implemented a data layer in the Data project, it was time to make a real data implementation. A Sql Server 2000 implementation was the default data source, located in the Data.SqlServer project.

Enterprise Library was used to provide the data access to Sql Server. This contained a Data Access Application Block, which allows configuring the connection string through the Enterprise Library Configuration tool.

A reference to Microsoft.Practices.EnterpriseLibrary.Data was needed, together with the Configuration and Common assemblies of Enterprise Library.

Through the Enterprise Library Configuration tool, an existing App.config was loaded, where the Data Access Application Block was added. The database and server values had to be configured to the actual server being used, together with the database containing the data. Additional connection string properties could be added as well, for example, the Integrated Security property, which is set to True.



After saving this file, it was possible to create a data implementation for each Accessor interface previously defined in the Data project, as for example this code:

 

using System;

using System.Data;

using System.Collections;

 

using MediaService.Logging;

using MediaService.Objects;

using MediaService.Data.Accessors;

 

using Microsoft.Practices.EnterpriseLibrary.Data;

using Microsoft.Practices.EnterpriseLibrary.Logging;

 

namespace MediaService.Data.SqlServer {

  public class SongDataAccessor: ISongDataAccessor {

  } /* SongDataAccessor */

} /* MediaService.Data.SqlServer */


Thanks to the Enterprise Library Data Access Application Block, the Sql Server implementation used best practices from the Microsoft Patterns & Practices group, which followed Microsoft guidelines and were optimized for performance.

To get an array of objects from the database, a new Database object had to be created, after which a stored procedure was wrapped, called and read from to get for example Song objects. This was done with the following code:

 

public Song[] GetSongs() {

  Database db = DatabaseFactory.CreateDatabase("MediaServiceSqlServer");

 

  DBCommandWrapper dbCommandWrapper =

                        db.GetStoredProcCommandWrapper("GetSongs");

 

  Logger.Write("Retrieving songs.", Category.SqlServer,

                Priority.Lowest, 1, Severity.Information);

 

  ArrayList songs = new ArrayList();

  using (IDataReader dataReader = db.ExecuteReader(dbCommandWrapper)) {

    while (dataReader.Read()) {

      songs.Add(new Song(dataReader.GetInt32(0), dataReader.GetString(1),

                         dataReader.GetString(2), dataReader.GetString(3),

                         dataReader.GetString(4), dataReader.GetString(5),

                         dataReader.GetString(6), dataReader.GetInt32(7),

                         dataReader.GetInt32(8), dataReader.GetInt32(9)));

    }

  }

 

  Logger.Write(String.Format("Retrieved {0} {1}.", songs.Count,

                             (songs.Count == 1) ? "song" : "songs"),

               Category.SqlServer, Priority.Lowest, 1, Severity.Information);

 

  return (Song[])songs.ToArray(typeof(Song));

} /* GetSongs */


Updating an item by using a stored procedure which uses parameters, was done by using the following code:

 

public void UpdateSongPlayCount(Int32 songId) {

  Database db = DatabaseFactory.CreateDatabase("MediaServiceSqlServer");

 

  DBCommandWrapper dbCommandWrapper =

                        db.GetStoredProcCommandWrapper("UpdateSongPlayCount");

  dbCommandWrapper.AddInParameter("@songId", DbType.Int32, songId);

 

  Logger.Write(String.Format("Updating play count for song: {0}.", songId),

               Category.SqlServer, Priority.Lowest, 1, Severity.Information);

 

  try {

    db.ExecuteNonQuery(dbCommandWrapper);

  } catch (Exception ex) {

    Logger.Write(String.Format("Failed to update play count for song: {0}.

                                Error: {1}", songId, ex.ToString()),

                 Category.SqlServer, Priority.Highest, 1, Severity.Error);

  }

} /* UpdateSongPlayCount */


Using stored procedures made it possible to have another layer of abstraction. This made it easy changing an existing stored procedure to keep track of statistics, without having to change any code of the implementation. At the same time, using stored procedures also protected against Sql Injection attacks. After all Accessors were implemented, it was possible to use this implementation by deploying the SqlServer dll and selecting it as data source.
with 8 comment(s)
Filed under:
Any application using data benefits from having a separate data layer. This enables the administrator to select which data source to use. It also makes your application have an advantage, making it easier to sell.

Besides from the advantages for the end-users, it’s also best practices to separate the data layer from your presentation and business logic layer.

To provide the data layer to the application a Data project was added. The layers above the data layer never accessed the real data implementations, but worked with objects which implemented certain data interfaces. This way, it was possible to define all possible data related methods in an interface and afterwards implement them in a real implementation.

A logical grouping was applied when creating the interfaces, starting from a generic IDataAccessor from which every other interface inherited from.

 

using System;

 

namespace MediaService.Data.Accessors {

  public interface IDataAccessor {

  } /* IDataAccessor */

} /* MediaService.Data.Accessors */

 

One of the logical sections was for example everything related to Song objects:

 

using System;

 

using MediaService.Objects;

 

namespace MediaService.Data.Accessors {

  public interface ISongDataAccessor: IDataAccessor {     

    Song[] GetSongs();

    Song[] GetQueue();

    Song[] GetMostPlayed(Int32 numberOfSongs);

    Song[] GetMostPopular(Int32 numberOfSongs);

  } /* ISongDataAccessor */

} /* MediaService.Data.Accessors */


Since the other projects did not have a reference to the real data implementations, but only to the Data project, this project had to take care of loading the correct implementation. Loading the correct class in the real implementation is done by using factories. For every Accessor interface a factory exists, returning an instance of the data implementation, using the following code:

 

using System;

using MediaService.Data.Accessors;

 

namespace MediaService.Data.Factory {

  internal class SongFactory: Factory {

    internal static ISongDataAccessor Create() {

      return Factory.Create(Accessor.Song) as ISongDataAccessor;

    } /* Create */

  } /* SongFactory */

} /* MediaService.Data */


In the Data project, there was one Factory class, responsible for loading the correct assembly containing the data implementation and instantiating the correct Accessor class. This was done by using Reflection together with Configuration to retrieve the location. The location consisted out of the class name and the assembly name, separated by a comma, as for example the location for the SongDataAccessor:

 

<SongDataAccessor>

  MediaService.Data.SqlServer.SongDataAccessor,MediaService.Data.SqlServer

</SongDataAccessor>


This location data was retrieved by configuration, after which it was separated into assembly and class parts and loaded with Reflection with the following code:

 

using System;

using System.Reflection;

 

using MediaService.Configuration;

using MediaService.Data.Accessors;

 

using Microsoft.Practices.EnterpriseLibrary.Configuration;

 

namespace MediaService.Data.Factory {

  internal enum Accessor {

    Song

  } /* Accessor */

 

  internal class Factory {

    internal static IDataAccessor Create(Accessor accessorType) {

      DatabaseData configData = LoadConfiguration();

 

      if (configData == null) {

        throw new ApplicationException("Could not load configuration.");

      }

 

      String blockToLoad = String.Empty;

      switch (accessorType) {

        case Accessor.Song: blockToLoad = configData.SongDataAccessor; break;

      }

 

      if (blockToLoad == String.Empty) {

        throw new ApplicationException(String.Format(

                  "Type entry not found for {0}.", accessorType.ToString()));

      }

 

      Int32 index = blockToLoad.IndexOf(",");

      string typeToLoad = blockToLoad.Substring(0,index);

      string assemblyToLoad = blockToLoad.Substring(typeToLoad.Length + 1,

                              blockToLoad.Length - typeToLoad.Length - 1);

      return (IDataAccessor)Assembly.Load(

                            assemblyToLoad).CreateInstance(typeToLoad);

    } /* Create */

 

    private static DatabaseData LoadConfiguration() {

     ConfigurationManager.ClearSingletonSectionCache("databaseConfiguration");

     return ConfigurationManager.GetConfiguration(

                           "databaseConfiguration") as DatabaseData;

    } /* LoadConfiguration */

  } /* Factory */

} /* MediaService.Data.Factory */


All of the Factories were marked internal because they are just meant for internal workings of the data layer, while all Accessors remain public because they had to be accessible to implement in the real data implementation.

Besides the Accessor interfaces, the Data project also exposed one public class, named Dalc. This class contained static properties for each logical data section, returning an instantiated Accessor from the configured data source.

 

using System;

 

using MediaService.Data.Accessors;

using MediaService.Data.Factory;

 

namespace MediaService.Data {

  public class Dalc {

    public static ISongDataAccessor Song {

      get { return SongFactory.Create();  }

    } /* Song */

  } /* Dalc */

} /* MediaService.Data */


After this, it was possible to access data by adding a reference to the Data project, adding a real data implementation assembly to the deployed location and configuring it. For example, the following code retrieved all songs from the data source:

 

using MediaService.Objects;

using MediaService.Data;

using MediaService.Data.Accessors;

 

namespace MediaService.Web {

  public class Media {

    public Song[] GetSongs() {

      return Dalc.Song.GetSongs();

    } /* GetSongs */


With this data layer, all details about data access are contained in the real data implementations, while nowhere else there is specific data source code. The entire application works on data objects, which implement the data interfaces, while under the hood, the correct data source is selected through the configuration file.
with 3 comment(s)
Filed under:
The Pocket PC I recently received was completely in French, so I figured 'I'll just change this to English'.

It can't be that hard, can it? Apparently it was trickier then I thought.

The Pocket PC has the OS in it's ROM, and it has limited ROM, so no multilanguages in there.

It quickly became obvious to me the ROM had to be flashed with an English version, but where to get it?

I didn't buy the Pocket PC, so asking Dell to give me an English one probably would fail, and from various messageboards I discovered they won't do it anyway.

So, where to get it? From the Dell site I guessed, in the download section there was an English update for Windows Mobile 2003 Second Edition.

Since this update just flashes the ROM and puts the new version in it, I guessed this was ok.

But when trying to flash it, it started complaining about being the wrong language.

Apparently French can only be upgraded to French, and since I don't speak French fluently this wasn't practical :)

So, search engine to the rescue. I found this post on Aximsite, a site dedicated to Dell Axim resources.

It seemed logical, get the English and French ROM, make the updater believe the English ROM is actually a French language, and flash.

The process looked obvious to me, so, let's get started!

I opened up the French ROM and English ROM in a hex editor and located the differences:



Note:

This is different from the forum post! It's not the first 7 lines you have to copy paste.

Pasting the first 7 lines results in an Integrity Check error. It's enough to change everything before the "AXIM30".

After having modified the English ROM with the new header, I saved it to the French updated directory, overwriting the original French ROM update. (So, now you have a filename which indicates it's a French ROM, but it's actually the English ROM with the French header)

I did the same for the other image (there is a C and an N image).

Now I ran the updater, which did not give me an error about Integrity Check anymore, and also not about wrong language.

It succesfully updated the ROM and after the Pocket PC restarted, everything was English!

So, now I have an English Pocket PC :)

Ofcourse, the disclaimer on my blog applies especially to this post, as this is not something you should do quickly if you have no technical skills.

So: I (David Cumps) cannot be held responsible for any damage what-so-ever that might come from this post. You do this at your own risk.
with 28 comment(s)
Filed under: ,
A while ago I blogged about Alternate Data Streams and how they are hidden from the users.

At that time, you could presume when an ADS was present, it was something special, because not many normal files have an ADS attached to it.

But yesterday I got an interesting question about XP SP2 showing a Security Warning when you want to execute something downloaded from the internet.

We guessed Alternate Data Streams were used, so I checked this out and it turns out XP SP2 indeed adds an ADS when you download a file from the Internet.

This stream is called Zone.Identifier and contains the following information:

D:\Tmp>more < TestZip.zip:Zone.Identifier
[ZoneTransfer]
ZoneId=3

Since SP2 did this, it probably means it's a modification to Internet Explorer.

So, I got the Firefox 1.0.3 and downloaded a file with the default settings, and as I guessed, no ADS with Zone.Identifier.

(I believe Firefox doesn't have such thing as Zones, but it would be nice if Firefox added this ADS to let the new Security Warning, informing you it's a downloaded file, come up).
Yesterday I gave a presentation about eID in .NET, if somebody is interested I have uploaded the presentation together with some sample code to my personal website: Cumps.be

The purpose of this session is to give an idea about what's possible with the eID card in .NET and what is needed to get it working.

Some background information about eID is provided, after which four possible usage scenarios are described and what is needed to build them.

Note: The code are just technical tryouts, not ment to go straight into production :) Provided "AS IS".
Yesterday I got invited by Microsoft France to Paris, to the Wax Club, to see the French Visual Gaming Finals.

My team mate, ZogStriP, participated in the High School competition there, so it was very exiting!

It was also a very good experience to learn french ;) And to get to know Paris, where the people are really crazy in traffic. Apparently, stop signs are just for decoration... Green or red, it all means the same :p

They played the games before and played the replay files on big screen, which were also recorded by a french television station. The station is on sattelite and is called GameOne, I don't know yet when they will broadcast it. I'll have to find someone who can digitally record it, because they interviewed me as well :p

So, the High School competition: there were 2 pools, one with 3 games and one with 6. Our best competitor was Z² who lost with a very little difference each time.

In the end, our dll won the High School competition! Resulting in a PDA for my team mate (I'm too old for High School ;p).

But here is where something special happened, he gave me the PDA!

He recently became MVS in France and just received one as well. Isn't it a nice gesture? Microsoft France made a very good choice making him MVS, he really deserves it with this kind of attitude, a real teamplayer. (So, for all French companies reading my blog, go to his blog and check it out, he would be a great asset for your company!)

After this, it was time for the Open Division.

There, our bot had a hard time. We lost the quarter finals by 1 point, due to a bug causing the AI to stop :/ So, chances for 1st and 2nd were gone. Finally we ended up at the fourth place, because the same bug occured again in the next game, which is really a shame.

One thing is sure, being 4th already is good, especially in France, the country of Visual Gaming, now we only have to fix this bug :p Result of ending on 4th place: A fingerprint reader and I also got interviewed, in English :p This is really a nice example of "dissolving boundaries" :)

And to finish, here's a picture of ZogStriP and me (ZogStriP right, me left):



To ZogStriP: Thanks!
with 5 comment(s)
Filed under: ,
I just found the Microsoft USB Flash Drive Manager trough Ohad Israeli and when I checked for updates, I got sent to this site, which had something funny on it ;)



I think Google will like it Microsoft promotes their product above MSN Desktop Search ;)
with 2 comment(s)
Filed under:
When developing an application it’s possible to use debug mode to figure out why something is wrong, but when it’s time to deploy the application something else has to be integrated. To solution to this is logging. Implementing good logging functionality will make the Operations people who have to deploy your application happy as well, because they can integrate it into existing monitoring systems.

Enterprise Library was used to implement a flexible logging solution. Thanks to the Logging and Instrumentation Application Block it’s possible to integrate logging into your code, but decide where to output the log externally from the application. This way it’s possible to log to a flat file, a database, an email address, the event log, a message queue, WMI and custom implementations, without having to change code.

A Logging project was added to start, to provide some helper constants:

 

using System;

 

namespace MediaService.Logging {

  public struct Priority {

    public const Int32 Lowest  = 0;

    public const Int32 Low     = 1;

    public const Int32 Normal  = 2;

    public const Int32 High    = 3;

    public const Int32 Highest = 4;

  } /* Priority */

 

  public struct Category {

    public const String Player    = "Player";

    public const String Remoting  = "Remoting";

    public const String Data      = "Data";

    public const String SqlServer = "SqlServerData";

  } /* Category */

} /* MediaService.Logging */


After this, a reference to the Logging project was added together with a reference to Microsoft.Practices.EnterpriseLibrary.Logging. A reference to the Enterprise Library Configuration Application Block was needed as well.

At this point it was possible to log messages by using the following construct:

 

if (randomSong == null) {

  Logger.Write("Unable to select a random song.", Category.Player,

               Priority.High, 1, Severity.Error);

} else {

  Logger.Write(String.Format("Fetched song: {0} (Random).", randomSong.Path),

               Category.Player, Priority.Low, 1, Severity.Information);

}


Similar code had been added throughout the code to provide meaningful feedback. The only thing left was configuring where the log output had to go.

Using the Enterprise Library Configuration tool, an existing App.config was loaded and the Logging and Instrumentation Application Block was added. Under Client Settings, LoggingEnabled was to True.

A new category had to be added, called Player, by right clicking on Categories and selecting New – Category. This is the name that was used in the code to specify which log the output belongs to. It was possible to define multiple categories.

To define where the output had to go to, a new sink was added, called Player Flat File Sink, by right clicking on Sinks and selecting New – Flat File Sink. Player.log was chosen as a filename, without a header.

Formatters are used to define how a single log entry had to look. By default a Text Formatter was provided, which included extensive information. To have an overview log file, a new formatter was added by right clicking Formatters and selecting New – Text Formatter. The template for this Simple Text Formatter was the following:

 

{severity}

[{timestamp}]: {message}


Finally a new destination was added by right clicking the Player category and selecting New – Destination. This destination was configured to use the Simple Text Formatter together with the Player Flat File Sink.



After this, the loggingconfiguration.config and loggingdistributorconfiguration.config files had to be copied in the Post-build event as well. At this point, the application had implemented a flexible logging strategy, where an administrator could easily decide to turn logging on or off and where the log output had to go to and which template had to be used.
To configure the solution, Enterprise Library was used. This contained a Configuration Application Block which allowed defining various configuration sources externally from the application. This approach gave to ability to switch from XML configuration files to a database without having to change anything in the code. Because of this, it was also possible to distribute the application, and let an administrator choose where it should read the configuration from. An additional advantage of using the application block was the ability to automatically detect when the configuration had changed and retrieve the new values.

The easiest way to implement configuration, was to create a new project which contained all the possible configuration sections in the solution. Each configuration section was defined by a different class.

For example, to make the port used by Remoting in the application configurable, I created a class which contained this value, together with a public property for it. This class uses the Xml namespace, because it was serialized to XML, and the application block uses the public properties to populate the configuration data.

A default constructor also had to be present for XML Serialization.

The configuration data for the player was for example contained in the PlayerData class, which looked like this:

 

using System;

using System.Xml.Serialization;

 

namespace MediaService.Configuration {

  public class PlayerData {

    private Int32 remotingPort;

 

    [XmlElement("RemotingPort")]

    public Int32 RemotingPort {

      get { return this.remotingPort; }

      set { this.remotingPort = value; }

    } /* RemotingPort */

 

    public PlayerData() { }

 

    public PlayerData(Int32 remotingPort) {

      this.remotingPort = remotingPort;

    } /* PlayerData */

  } /* PlayerData */

} /* MediaService.Configuration */


To use these values, a reference to the Configuration project had to be added, together with a reference to Microsoft.Practices.EnterpriseLibrary.Configuration. After this the configuration could be loaded with the following code:

 

using Microsoft.Practices.EnterpriseLibrary.Configuration;

 

namespace MediaService.Player {

  public class PlayerService : System.ServiceProcess.ServiceBase {

    private PlayerData configData = null;

 

    private void LoadConfiguration() {

      ConfigurationManager.ClearSingletonSectionCache("playerConfiguration");

      try {

        this.configData = ConfigurationManager.

                        GetConfiguration("playerConfiguration") as PlayerData;

      } catch (Exception ex) {

        this.configData = new PlayerData(4000);

      }


And to receive notifications the following code had to be added:

 

protected override void OnStart(string[] args) {

  ConfigurationManager.ConfigurationChanged += new

  ConfigurationChangedEventHandler(ConfigurationManager_ConfigurationChanged);

} /* OnStart */

 

private void ConfigurationManager_ConfigurationChanged(object sender,

                                            ConfigurationChangedEventArgs e) {

  this.LoadConfiguration();

  // Check new values and perform possible actions

} /* ConfigurationManager_ConfigurationChanged */


At this point, all code needed for configuration was done. Now the Enterprise Library Configuration tool had to be used to configure the application’s configuration source.

First, a new application had to be defined by using File – New Application. Then the Configuration Application Block had to be added through Action – New - Configuration Application Block. After this, a new configuration section was added by right clicking on the new application block and selecting New – Configuration Section.

This new section was called playerConfiguration, as it is in the code, and uses an XML Storage Provider and an Xml Serializer Transformer, both added by right clicking the new section and selecting them from the New menu.

The only thing that still had to be changed was the XML Storage Provider, playerConfiguration.config had to be given as a FileName. After this, the configuration had to be saved.



The XML file used for configuration was the following:

 

<?xml version="1.0" encoding="utf-8"?>

<playerConfiguration>

  <xmlSerializerSection type="MediaService.Configuration.PlayerData,

                              MediaService.Configuration,

                              Version=1.0.0.0,

                              Culture=neutral,

                              PublicKeyToken=null">

    <PlayerData xmlns:xsd="http://www.w3.org/2001/XMLSchema"

                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

      <RemotingPort>4000</RemotingPort>

    </PlayerData>

  </xmlSerializerSection>

</playerConfiguration>


The only thing left to make sure the application loaded the configuration during testing, was to provide a Post-build event that copied the configuration file. To do this, in the project’s properties, under the Common Properties was a Build Events menu, where it was possible to define the Post-build event. The following had to be used to copy the playerconfiguration.config file:

 

copy "$(ProjectDir)playerconfiguration.config" "$(TargetDir)" >Nul


When the application was started, it would call the LoadConfiguration method, which would populate the PlayerData class and provide all configuration settings of the application. If the configuration file would be changed when the application was running, the ConfigurationChanged event would be raised and the new configuration would be used.
After everything was done on the server-side of the Remoting implementation, inside the Windows Service, it was time to add the consumer side. In the case of this project, the consumer was an ASP.NET Webservice running on the same machine.

This required little effort. First, System.Runtime.Remoting had to be referenced, together with the assembly containing the interface used for the controller object. After this it was possible retrieve the controller object with the following code:

 

private IPlayerServiceController GetPlayerServiceController() {

  return (IPlayerServiceController)Activator.GetObject(

            typeof(IPlayerServiceController),

          String.Format("tcp://{0}:{1}/MediaServicePlayerController",

          this.configData.RemotingHost,

          this.configData.RemotingPort));

} /* GetPlayerServiceController */

 

In this solution, the webservice does not need to reference the assembly containing the real controller, but only an assembly that contains the interface. The real implementation is running on the server-side, as an instantiated, marshalled object.

When the instance got returned, it was possible to use it very simple, like this code:

 

[WebMethod(Description="Stop playing the queue.")]

public void Stop() {

  this.GetPlayerServiceController().StopPlaying();

} /* Stop */

with 2 comment(s)
Filed under:
More Posts Next page »