Thursday, June 29, 2006

VS.Net debugger error

[I haven't had chance to add more posts to the continuing windows service framework yet]

I have been using VS.NET since 2003 and never had any problem till yesterday. Suddenly, it started giving message "Error while trying to run project: Unable to start
debugging. Access Denied".

After reading many blogs/groups on the web, I tried filemon, regmon, checked the user privileges -- everything seem to be fine. I was using Admin account so it had all permissions machine can think of. Finally I got to see this message:

http://tinyurl.com/47cgu
http://tinyurl.com/6sx2y
http://groups.google.com/group/microsoft.public.vsnet.debugging/browse_frm/thread/836e16d96cebcef?hl=en&lr=&ie=UTF-8&rnum=17&prev=/groups%3Fas_epq%3DMachine%2520Debug%2520Manager%26safe%3Dimages%26ie%3DISO-8859-1%26as_ugroup%3Dmicrosoft.public.vsnet.debugging%26lr%3D%26num%3D20%26hl%3Den
http://groups.google.com/group/microsoft.public.vsnet.debugging/browse_frm/thread/7ecffb30927d10c5?hl=en&lr=&ie=UTF-8&rnum=40&prev=/groups%3Fq%3D%2B%2522Machine%2BDebug%2BManager%2522%2Bgroup:microsoft.public.vsnet.debugging%26num%3D20%26hl%3Den%26lr%3D%26ie%3DUTF-8%26start%3D20%26sa%3DN

And I tried

MDM.exe /regserver

And other dll registry from:

sdm2.dll
msdbg2.dll
mscordbi.dll
pdm.dll
shell32.dll
Browseui.dll
oleaut32.dll
actxprxy.dll
msjava.dll
urlmon.dll
shdocvw.dll

Some of these registered successfuly, some of them did not.

But after this, the DEBUGGER started working.

Tuesday, June 20, 2006

Design Patterns #1.3 - Windows Service Framework - Timer Trigger

Timer Trigger

We have seen the interface and base class for trigger. Now, let's see how a sample trigger using Timer can be implemented. Windows services that need to take some actions at particular time interval can make use of this trigger.

This is the interface for Timer Trigger.

namespace Atarapi.Framework.ServiceLib
{
public interface ITimerTrigger : IServiceTrigger
{
int ElapseTime { get; set; }
TimeSpan ExWindowFrom { get; set; }
TimeSpan ExWindowTo { get; set; }
bool UseExWindow { get; }

void OnTimer(object state);
}//interface
}//namespace

The Timer trigger would need the parameters from config file for time interval at which the timer event occurs. ElapseTime is such parameter. But there are three other parameters worth mentioning:
  • ExWindowFrom, ExWindowTo - they define the execution window for the timer event. E.g. a service wants to take an action every 5 seconds from Midnight to 1 AM. This can be achieved by setting ExWindowFrom to "0:00" and ExWindowTo to "1:00". The timer events will occur only during this window. If the window is not specified, then the event will occur all the time.
  • UseExWindow - set to true/false to indicate whether to use the execution window defined above.
For the implementation of TimerTrigger, we will not list the obvious methods/properties here that you already know how to code.

SetParams() - this method is overridden from the base trigger class. Base class already reads the parameters and puts them into a NameValueCollection. So, here we will just let base class do its job and set the parameters to our internal member variables.

protected override void SetParams(System.Xml.XmlNode paramNode)
{
base.SetParams (paramNode);

_elapseTime = Converter.ToInt(this.ConfigParams["ElapseTime"]);
_delayTime = Converter.ToInt(this.ConfigParams["DelayTime"]);
if (_elapseTime <= 0)
throw new ConfigurationException(string.Format("ElapseTime parameter is invalid in node {0}", paramNode.Name));

try
{
string temp;

temp = this.ConfigParams["ExWindowFrom"];
if (temp != null && temp.Trim() != "") { _exWindowFrom = TimeSpan.Parse(temp); }

temp = this.ConfigParams["ExWindowTo"];
if (temp != null && temp.Trim() != "")
{ _exWindowTo = TimeSpan.Parse(temp); _useExWindow = true; }

}//try
catch(FormatException ex)
{
_useExWindow = false;
throw ex;
}//catch

}//SetParams


OnTimer() - This is the most important method for this trigger. It should guarantee that
  • the event should invoke the handler only during the execution time window (if configured)
  • and event should not invoke the handler if it has not finished execution from the previous event - let's say you configure event to occur every 1 second and at that time you delete some records from database. Now, deleting itself may take more than 1 second, in such instances you don't want to receive timer event while you are deleting.
Keeping in mind the 2nd bullet, we have created another method called OnTimerCritical() that guarantees that it is called only when previous event call has finished executing.

public void OnTimer(object state)
{
TimerState timerState;

if(state is TimerState)
timerState = (TimerState)state;
else
return;

if (timerState.CriticalExecuting)
return;
else
timerState.CriticalExecuting = true;

//stop timer
if (timerState.CurrentTimer != null)
timerState.CurrentTimer.Change(Timeout.Infinite, Timeout.Infinite);
try
{
if(this.UseExWindow)
{
if(TimeSpan.Compare(DateTime.Now.TimeOfDay, this.ExWindowFrom) > 0 && TimeSpan.Compare(DateTime.Now.TimeOfDay, this.ExWindowTo) <>
{
OnTimerCritical(timerState);
}//if
}//if
else
{
OnTimerCritical(timerState);
}
}//try
finally
{
if (timerState.CurrentTimer != null)
timerState.CurrentTimer.Change(this._elapseTime * 1000, this._elapseTime * 1000);
timerState.CriticalExecuting = false;
}
}//OnTimer

OnTimer() stops the timer before calling OnTimerCritical() and after its over, it starts the timer back again. (A critique can ask why is it again setting the initial delay time when restarting the timer? If you have a better approach you are welcome to pass it on)

public virtual void OnTimerCritical(TimerState obj)
{
foreach(IServiceHandler handler in this.HandlerList)
{
try
{
if (handler.GetStatus() != ServiceStatus.Running)
{
if (this.RunParallel)
handler.Invoke(null);
else
handler.Execute(null);
}//if !running
}//try
catch(Exception ex)
{
// log error....
}//catch
}//foreach
}//OnTimerCritical

This method invokes each Handler to execute its process. Depending on whether handlers should run parallel/sequential, it calls invoke() or execute() method on handler. The base class of handler has both of these methods. Invoke() calls Execute() asynchronously. This trigger does not create threads to call handlers parallely - while it could have done so. Rightnow it kind of relies on the honesty from Handlers that Invoke() will return immediately.

Remember, all above calls still don't do the job. We have to start the timer somewhere. And keeping in mind, we are working on windows service rightnow, what better place other than OnStart() of service?

public override void OnStart(string[] args)
{
if (this._timerState == null)
_timerState = new TimerState();
if (_timerState.CurrentTimer == null)
_timerState.CurrentTimer = new Timer(new TimerCallback(this.OnTimer), _timerState, this._delayTime * 1000, this._elapseTime * 1000);
else
_timerState.CurrentTimer.Change(this._delayTime * 1000, this._elapseTime * 1000);

//call base trigger start
base.OnStart(args);
}//OnStart

Similar actions should be taken on Timer object for OnPause, OnContinue, OnStop etc. Here one example for OnPause is listed.

public override void OnPause()
{
if(this._timerState != null && this._timerState.CurrentTimer != null)
this._timerState.CurrentTimer.Change(Timeout.Infinite, Timeout.Infinite);
base.OnPause ();
}

OnPause() stops the timer, similary OnStop() should stop the timer too. OnContinue() will restart the timer.

Since we have learnt about a real trigger, let's look at how Service is loading all the triggers and then invoking them. We achieve this via a class called TriggerMaster.

Monday, June 19, 2006

Design Patterns #1.2 - Windows Services Framework - ServiceTrigger class

Trigger & Handler

As we discussed earlier, the trigger indicates what type of events will be caught. But the Handler class will define the action to be taken when event (like Timer trigger) has occurred. So, each trigger can have its own Handler or a set of handlers to execute at the trigger-event.

Our base ServiceTrigger class will store this list of handler from config file and invoke those handlers when service raises the events.

Before we go further into the Trigger class, let's look at a sample config section for a service.


<configuration>
<configSections>
<section name="serviceTriggers"
type="Atarapi.Framework.ServiceLib.TriggerSectionHandler, atarapi.framework" />
</configSections>

<serviceTriggers>
<trigger disabled="false" name="MyMessages" type="Atarapi.Framework.ServiceLib.TimerTrigger, atarpi.framework">
<params>
<param name="ElapseTime" value="10" />
<param name="DelayTime" value="10" />
</params>
<handlers run="parallel">
<handler type="MyApplication.MsgProcessor.MyMsgHandler, MyMsgHandler">
<params>
<param name="Param1" value="10" />
</params>
</handler>
</handlers>
</trigger>
</serviceTriggers>
</configuration>

A service configuration section handler will be discussed later, or, let's assume you know how to write one. Important part is the service can be configured with a set of triggers and each trigger can be configured with one or more handler as above.

Here a TimerTrigger gets a timer events at every 10 seconds. It configures its own timer using the paramters passed. If you pass ElapseTime=1 then a timer event will occur at 1 second. Whenever the event occurs, trigger code will invoke the class MyMsgHandler (or any name you chose). The handlers follow a base handler class/interface so they have to have Execute method that gets called whenever trigger gets the event.

Handler can have its own set of parameters defined within its own section as shown above.

When there are multiple handlers, question is, how trigger is going to invoke each of them? Trigger looks at 'run' attribute of handler tag; that can have values
  • ran="parallel"
  • run="sequential" (default)
In case of sequential, trigger will invoke each handler one after another in the order they are listed in the config file.
In case of parallel, trigger will invoke each handler asynchronously - not waiting for one handler to finish before calling next one.


ServiceTrigger base class

namespace Atarapi.Framework.ServiceLib
{
public abstract class ServiceTrigger : IServiceTrigger
{
#region private members
private string _triggerName;
private ArrayList _handlerList;
private NameValueCollection _params;
private bool _runParallel;
#endregion


#region constructors
public ServiceTrigger()
{
_params = new NameValueCollection();
}//ServiceTrigger
#endregion

#region properties
public string TriggerName
{
get { return _triggerName; }
}
public bool RunParallel
{
get { return _runParallel; }
set { _runParallel = value; }
}
public ArrayList HandlerList
{
get { return _handlerList; }
}
protected NameValueCollection ConfigParams
{
get { return _params; }
}
#endregion
#region IServiceTrigger Members

#region service events - empty implementation
public virtual void OnContinue()
{
}

public virtual void OnCustomCommand(int command)
{
}

public virtual void OnPause()
{
}

public virtual bool OnPowerEvent(System.ServiceProcess.PowerBroadcastStatus powerStatus)
{
return false;
}


public virtual void OnShutdown()
{
}

public virtual void OnStart(string[] args)
{
foreach(IServiceHandler handler in this.HandlerList)
{
try
{
handler.OnStart();
}
catch(Exception ex)
{
// log the error
}
}
}//OnStart



public virtual void OnStop()
{
foreach(IServiceHandler handler in this.HandlerList)
{
try
{
handler.OnStop();
}
catch(Exception ex)
{
//log the error
}
}//foreach
}//OnStop

#endregion


protected virtual void SetParams(XmlNode paramNode)
{
foreach(XmlNode pnode in paramNode.ChildNodes)
{
if(pnode.Name == "param")
{
_params[pnode.Attributes["name"].InnerText] = pnode.Attributes["value"].InnerText;
}
}//foreach
}//SetParams

public virtual void LoadConfig(System.Xml.XmlNode configNode)
{
XmlAttribute xmlAttrib = configNode.Attributes["name"];
if (xmlAttrib != null)
_triggerName = xmlAttrib.InnerText;

if(configNode.HasChildNodes == false)
return;
foreach(XmlNode xnode in configNode.ChildNodes)
{
if(xnode.Name == "params")
SetParams(xnode);
if(xnode.Name == "handlers")
LoadHandlers(xnode);
}//foreach
}//SetParams


Till now, above is straight forward. This reads the config file to set parameters for the trigger itself and it loads the handler information. All events OnStart(), OnStop() etc passes on the events to the handlers.

This does not take any actions for OnContinue() or OnPause() - remember, this is base trigger class and it doesn't know what to do with them. It could pass those events to the handleres too; but it does not. It leaves it upto each derived Trigger implementations to decide what to do with the Pause/Continue events.


Loading Handlers

LoadHandlers() method loads class information about handlers and then creates instances of each handler. It creates objects for handlers and stores them into a list. This list is used to pass event-notification to each handler.

protected virtual void LoadHandlers(XmlNode hnode)
{
//get the run attribute
XmlAttribute attrib = hnode.Attributes["run"];
string run = "";
if (attrib != null)
run = attrib.InnerText;
this.RunParallel = (run == "parallel");

//init handler list
if (_handlerList == null)
_handlerList = new ArrayList();
_handlerList.Clear();

if(hnode.HasChildNodes == false) return;

//load each handler node and store it in array
foreach(XmlNode xnode in hnode.ChildNodes)
{
try
{
string typeName = xnode.Attributes["type"].InnerText;
if (typeName == "")
throw new ConfigurationException(string.Format("Handler Type is not specified trigger [{0}]", this.TriggerName));
Type htype = Type.GetType(typeName);
if (htype == null)
throw new ConfigurationException(string.Format("Handler Type [{0}] could not be loaded for trigger [{1}]", typeName, this.TriggerName));
Object obj = Activator.CreateInstance(htype);
if (obj == null)
throw new ConfigurationException(string.Format("Handler [{0}] Object could not be created for trigger [{1}]", typeName, this.TriggerName));
if(obj is IServiceHandler)
{
((IServiceHandler)obj).SetParams(xnode);
_handlerList.Add(obj);
}//if
}//try
catch (FormatException ex)
{
//handle exception
}
catch (ConfigurationException ex)
{
//handle exception
}
catch (System.NullReferenceException ex)
{
//handle exception
}
}//foreach xnode
}//LoadHandlers


There is nothing more than this in ServiceTrigger. Now, we will see what each trigger implementation does with information loaded by this base class.


Design Patterns# 1.1 Windows Service Framework using .Net

2 Cents

There could be some design patterns out there for development of windows services using .Net - that I am not aware of. This blog is to show a design pattern that I (with the conceptual ideas of other few teammates @ work) used in my last few projects and I have been happy with w/o any big troubles or short-falls.

Goal

The blogs/sample documentation that is availble on intenret generally talks about how to use .Net System.ServiceProcess.ServiceBase class and System.Configuration.Install.Installer - the installer provided by VS.Net while creating a new project.

It is not the goal of this blog to explain how to use this classes - please visit other links like below for that;

http://www.google.com/search?hl=en&q=windows+service+using+.net&btnG=Google+Search
http://www.irishdev.com/blogs/kieranlynam/archive/2006/06/16/1591.aspx

The goal of this project/blog is to:
  • develop a framework that can be reused to develop any windows service
  • make use of .config files to configure an already existing service code to develop another service
  • allow to test the business logic of the service via NUnit or such utilities separately from windows service
  • ....
Brief Overview

Among different services code, the code in Service-Installer and class derived from ServiceBase really doesn't change much other than the service name. If we are able to use the config file to instruct the service code what class/method to call when onstart/onstop etc events occur then we could reuse the same service code with different config files as different services. Of course - we have to change the service name and recompile but that's all!!

Above is the basic idea behind creating this service framework. Now let's codify into real useful set of classes and interface.

Let's try to answer a basic question - what does each service do?
  • It does a specific task at a regular time interval
  • It keeps wathing a file folder for file operations
  • It keeps wathing a database table for new records
  • It keeps a watch on network ports
  • It keeps a watch on MSMQ
  • .... (please tell me :-)
Well, each of above events are triggering the service to do some action. So we can call them TRIGGERs. A Service config file can have list of triggers that a service is receiving. And the trigger configuration can indicate what class/method to call to handle the event - let's call that Handler.

Here I will discuss two triggers - Timer trigger and File watcher trigger. I don't have others ready. A database trigger can be achieved using a Timer trigger.

Base Trigger

Following lists the base interface for a trigger. The service will call each of these methods when service gets the corresponding event.

using System;
using System.ServiceProcess;
using System.Xml;

namespace Atarapi.Framework.ServiceLib
{
///
/// Summary description for IServiceTrigger.
///
public interface IServiceTrigger : IDisposable
{
void OnContinue();
void OnCustomCommand(int command);
void OnPause();
bool OnPowerEvent(PowerBroadcastStatus powerStatus);
void OnShutdown();
void OnStart(string[] args);
void OnStop();
void LoadConfig(XmlNode paramNode);
}//interface
}//namespace

A trigger class must implement this interface. But not all trigger may have some actions on each of this events. To make this easier we will create a base ServiceTrigger that implements all these methods and other triggers can override the required events.

In the next posting #1.2, we will see the listing of base ServiceTrigger class.

Failed to Retrive data error in Crystal Reports

Its very common to receive this error "Failed To Retrieve Data" or "Failed to setup connection" or "database logon failure" when you develop reports with one db server and then put those reports in production on different database.

Following code should be used to prevent these errors:

private void _setIfDifferent(Table crTable, ConnectionInfo connInfo)
{
TableLogOnInfo crTableLogOnInfo = crTable.LogOnInfo;
if (crTableLogOnInfo.ConnectionInfo != connInfo)
{
ConnectionInfo tableInfo = crTableLogOnInfo.ConnectionInfo;
if (tableInfo.DatabaseName != connInfo.DatabaseName
|| tableInfo.ServerName != connInfo.ServerName
|| tableInfo.UserID != connInfo.UserID
|| tableInfo.Password != connInfo.Password)
{
crTableLogOnInfo.ConnectionInfo = connInfo;
crTable.ApplyLogOnInfo(crTableLogOnInfo);
}
crTable.Location = string.Format("{0}.dbo.{1}", connInfo.DatabaseName, crTable.Location.Substring(crTable.Location.LastIndexOf(".")+1));
}
}

Above function should be called for each and every table in the report, as below.

///
/// sets the database parameters for the current report document
///

///
private void _setDatabaseLogon(ReportDocument rptDocument)
{
ConnectionInfo connInfo = _getConnInfo();

/*Setting Database connection info to all DB objects in Reports*/
Database crDatabase = rptDocument.Database;
foreach(Table crTable in crDatabase.Tables)
{
_setIfDifferent(crTable, connInfo);
}//foreach

Database subReportcrDatabase = null;
if (rptDocument.Subreports.Count > 0)
{
foreach(ReportDocument objSubReport in rptDocument.Subreports)
{
subReportcrDatabase = objSubReport.Database;
foreach(Table crTable in subReportcrDatabase.Tables)
{
_setIfDifferent(crTable, connInfo);
}//foreach
}
}
}//_setDatabaseLogon


Crystal needs Table.Location - after doing the ApplyLogOnInfo() - without that the report may fail. I don't know specific case in which it fails or succeeds - but this is the correct code to dynamically change the database information in reports.

Monday, June 05, 2006

Crystal Reports XI - report could not be submitted for background processing

I tried installing the SP2 for Crystal Reports XI - but this error was not fixed. Finally I tried following and it was fixed.

int count = 2;
do
{
try
{
generate report
}
catch(Exception ex)
{
if(ex.Message.IndexOf("background processing") >=0)
{ count--;
if(count == 0) throw;
}
else throw;
}
}
while (count > 0);

Since, the error comes up randomly for some reports - submitting the same reports for generation again in case of error - generates the report successfully.

Friday, June 02, 2006

Crystal Error - Not Enough Memory and report can not be submitted for background processing

Crystal Reports XI Error - Not Enough Memory and report can not be submitted for background processing

these two errors should be fixed after downloading the service pack 2 for XI, download it from following location:

http://support.businessobjects.com/communitycs/FilesAndUpdates/boXIwin_sp2.zip.asp

Crystal Reports Error - rowset column could not be found

With the help of this article:

http://www.experts-exchange.com/Databases/Crystal_Reports/Q_21579208.html

I found that query behind the report (stored procedure) needs to have alias for the formula columns to avoid this error.

E.g. SELECT datediff(d, current_timestamp, udpatedate) from users

may give error but following should not give error:

SELECT datediff(d, current_timestamp, udpatedate) as days from users

Wednesday, May 24, 2006

SQL Indexes

In MS SQL database, let's say there is a table with fields {A, B, C, D} and you have three queries

Query 1: Searches on A & B fields
Query 2: Searches on B & C fields
Query 3: Searches on A& C fields

For a better performance you would need 3 indexes, IX_AB, IX_BC and IX_AC. Having 1 index IX_ABC will not give the same performance as having 3 indexes.

Tuesday, May 23, 2006

Security Tab in Windows XP Professional

I just found out that the Security Tab in Windows XP would be disabled by default. To see the security tab for file or folder, one needs to turn off the Simple File Sharing used by Windows by default.

Follow instructions on this page: http://support.microsoft.com/default.aspx?kbid=307874

Or

1. Click Start, and then click My Computer.
2. On the Tools menu, click Folder Options, and then click the View tab.
3. In the Advanced Settings section, clear the Use simple file sharing (Recommended) check box.
4. Click OK.

For Sharing Tab

1. Click Start, and then click Control Panel.
2. Click Performance and Maintenance, click Administrative Tools, expand Services and Applications, and then double-click Services.
3. Right-click the Server service, and then click Start.

Friday, March 17, 2006

While coding when my fingers and palm pain, I feel I should not be doing coding anymore. I have been typing since college - 1993/94 is when I started using computers heavily. Its more than 12 years. What should one achieve in 12 years?