Click here to Skip to main content
15,885,244 members
Articles / Web Development / ASP.NET
Article

Using CastleProject's ActiveRecord in Windows Services

Rate me:
Please Sign up or sign in to vote.
4.30/5 (5 votes)
16 Nov 2007CPOL3 min read 22.4K   448   16  
An article on using ActiveRecord in Windows Services

Introduction

This article's purpose is to teach you how to take advantage of CastleProject's ActiveRecord class and combine it within a Windows Service.

Background

I had a project that required me to write a Windows Service and use the existing ActiveRecord objects. I did a search on Google, but did not find anything that was exactly what I wanted. Therefore I decided to role it out myself.

Tools You Need

  • Microsoft Visual Studio 2005
  • CastleProject RC3

Preparing a Test Database

Create a new database named test. Use the following SQL to generate the test database.

SQL
USE [test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Employee](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
    [EmailAddress] [nvarchar](50) NOT NULL,
    CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)
WITH (
    PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
    IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, 
    ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

This SQL statement will create a simple table named Employee with 3 fields.

Creating ActiveRecord Class

We will now create the ActiveRecord class. Create a new class library project in Visual Studio named ActiveRecordModel. Add references to Castle.ActiveRecord and NHibernate. Then add a class file named Employee.

C#
usingCastle.ActiveRecord;
usingNHibernate.Expression;

namespaceActiveRecordModel
{
    [ActiveRecord("[Employee]", Lazy = true)]
    public classEmployee : ActiveRecordBase
    {
        #region Membersprivate int _ID;
        [PrimaryKey]
        public virtual intID
        {
            get { return_ID; }
            set { _ID = value; }
        }

        privatestring _Name;
        [Property]
        public virtualstring Name
        {
            get { return_Name; }
            set { _Name = value; }
        }

        private string_EmailAddress;
        [Property]
        public virtual stringEmailAddress
        {
            get { return_EmailAddress; }
            set { _EmailAddress = value; }
        }
        #endregion#region Methodspublic staticEmployee FindByID(int ID)
        {
            // Note that we use the property name, _not_ the column name
            return (Employee)FindOne(typeof(Employee), 
                Expression.Eq("ID", ID));
        }
        #endregion}
}

Creating Windows Service

Create a new Windows Service project in Visual Studio. Right click on Service1.cs. Add the following code in the service constructor. This is where you initialize the ActiveRecord framework. Add references to the ActiveRecordModel.dll file created in our ActiveRecordModel class library. Add references to Castle.ActiveRecord, Castle.Core, Nhibernate and System.Configuration.Install.

C#
publicService1()
        {
            InitializeComponent();
            try{
                XmlConfigurationSource src = newXmlConfigurationSource(
                    "appconfig1.xml");
                System.Reflection.Assembly modelAssembly = 
                    System.Reflection.Assembly.Load("ActiveRecordModel");
                Castle.ActiveRecord.ActiveRecordStarter.Initialize(
                    newAssembly[] { modelAssembly }, src);
            }
            catch(Exception ex)
            {
                EventLog.WriteEntry(ex.Message + "\n" + 
                    ex.InnerException.Message, EventLogEntryType.Error);
            }
           
        }

I will retrieve 1 record of Employee and output the result in the event log when the service is started. Therefore add the following code in the OnStart method.

C#
protected override voidOnStart(string[] args)
        {
            // TODO: Add code here to start 
            // your service.using (newSessionScope())
            {
                EventLog.WriteEntry("ActiveRecordWindowsService started. ");
                try{
                    Employee a = Employee.FindByID(1);
                    EventLog.WriteEntry(a.Name + ":" +
                        a.EmailAddress,EventLogEntryType.Information);
                }
                catch(Exception ex)
                {
                    EventLog.WriteEntry(ex.Message + "\n" + 
                        ex.InnerException.Message + "\n" + 
                        ex.InnerException.InnerException.Message, 
                        EventLogEntryType.Error);
                }
            }
        }

Creating ActiveRecord Configuration File

After we have created the ActiveRecord class and our Windows Service, we need to create the XML file for the ActiveRecord configuration. In our initialization code mentioned earlier, we have a line like this:

C#
XmlConfigurationSource src = new XmlConfigurationSource("appconfig1.xml");

Without providing a path in the code, Windows will look for this appconfig1.xml file in the C:/Windows/System32 directory. So, we need to create a text file named appconfig1.xml and save it in the C:/Windows/System32 directory.

XML
<?xmlversion="1.0"encoding="utf-8"?>
<activerecordisWeb="false">
<config><addkey="hibernate.connection.driver_class"
    value="NHibernate.Driver.SqlClientDriver"/>
<addkey="hibernate.dialect"value="NHibernate.Dialect.MsSql2000Dialect"/>
<addkey="hibernate.connection.provider
    "value="NHibernate.Connection.DriverConnectionProvider"/>
<addkey="hibernate.connection.connection_string"
    value="Data Source=localhost;Initial Catalog=test;
    Persist Security Info=True;User ID=sa;Password=123"/>
</config>
</activerecord>

Enable Windows Services to be Installed without Using InstallUtil

Usually when you are trying to install a Windows Service, it is more than likely that you would be using InstallUtil SomePath\ServiceName.exe and InstallUtil /u SomePath\ServiceName.exe to install/uninstall Windows Services. The following code would let users install the Windows Service directly under the command prompt by simply passing command arguments to the EXE file. The user will be able to install the service simply by typing WindowsService1.exe /install to install the service and WindowsService1.exe /uninstall to uninstall the service. Add an install.cs class file to the project.

C#
using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;

namespace WindowsService1
{
    [RunInstaller(true)]
    public classMyInstaller : Installer
    {
        public MyInstaller()
        {
            ServiceProcessInstaller spi = new ServiceProcessInstaller();
            spi.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
            spi.Password = null;
            spi.Username = null;
            ServiceInstaller si = new ServiceInstaller();
            si.StartType = ServiceStartMode.Automatic;
            si.ServiceName = "ActiveRecordWindowsService";
            this.Installers.Add(spi);
            this.Installers.Add(si);
        }
    }
}

Now, open up the Program.cs file that was created when the project was created. Change the Main function to the following:

C#
using System;
using System.Collections;
using System.Configuration.Install;

namespace WindowsService1
{
    static classProgram
    {
        /// /// The main entry point for the application.
        /// static voidMain(string[] args)
        {

            string opt = null;
            if (args.Length > 0)
            {
                opt = args[0];
            }
            if (opt != null && opt.ToLower() == "/install")
            {
                TransactedInstaller ti = new TransactedInstaller();
                MyInstaller mi = new MyInstaller();
                ti.Installers.Add(mi);
                String path = String.Format("/assemblypath={0}",
                 System.Reflection.Assembly.GetExecutingAssembly().Location);
                String[] cmdline ={ path };
                InstallContext ctx = new InstallContext("", cmdline);
                ti.Context = ctx;
                ti.Install(new Hashtable());
            }
            else if (opt != null && opt.ToLower() == "/uninstall")
            {
                TransactedInstaller ti = new TransactedInstaller();
                MyInstaller mi = new MyInstaller();
                ti.Installers.Add(mi);
                String path = String.Format("/assemblypath={0}",
                 System.Reflection.Assembly.GetExecutingAssembly().Location);
                String[] cmdline ={ path };
                InstallContext ctx = new InstallContext("", cmdline);
                ti.Context = ctx;
                ti.Uninstall(null);

            }

            if (opt == null)  
            {
                System.ServiceProcess.ServiceBase[] ServicesToRun;
                ServicesToRun = new System.ServiceProcess.ServiceBase[] 
                { 
                    new Service1() 
                };
                System.ServiceProcess.ServiceBase.Run(ServicesToRun);
            }
        }
    }
}

Creating a Record for Testing

Now we can create a record in the database for testing. Type the following SQL command to create our testing record.

SQL
INSERT INTO [test].[dbo].[Employee]
           ([Name]
           ,[EmailAddress])
     VALUES
           ('Eddie Chen',
           ,'eddie.chen@localhost')

Installing the Service

Under the command prompt, type WindowsService1.exe /install.

Screenshot - ActiveRecordWindowsService1.jpg

After this, you should see that the service has been installed like this:

Screenshot - ActiveRecordWindowsService3.gif

Testing the Service

We can now test the service by running it. After we start the service, we can check the event log to see if the service has been started successfully.

Screenshot - ActiveRecordWindowsService2.jpg

History

  • 16 November, 2007 -- Original version posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Delta Electronics
Taiwan Taiwan
Eddie is a system analyst currently working for Delta Electronics.

Comments and Discussions

 
-- There are no messages in this forum --