Friday, August 27, 2010

Tic Tac Toe Algorithm

If you are given a Tic Tac Toe board. How do you find if a specific player is a winner.

The straight forward algorithm is going to start from the first row and the first column. the algorithm will start by checking if this square is an X or if it is an O.
assume we are trying to find if X is the winner.

If this square is an X, then we will increment the number of X's found in row 1 and the number of X's found in column 1 and the number of X's found in the 270 degrees diagonal.

Because this first row and first column square is a member of all these three possibilities. in order to support this algorithm then we need a storage that will hold the number of X's found in Row 1, the number of X's found in row 2, the number of X's found in row 3, the number of X's found in column 1. the number of X's found in column 2. the number of X's found in column 3. the number of X's found in the 270 degrees diagonal and finally the number of X's found in 45 degrees diagonal.

We can create a class called Tic Tac Toe as follows.

class TicTacToe
{
private readonly int[] _rows; //array to store the number of X's found in each row
private readonly int[] _cols; //array to store the number of X's found in each column
private int _270Diagonal; //one variable to store the number of X's found in the 270 degrees diagonal
private int _45Diagonal;//one variable to store the number of X's found in the 45 degrees diagonal

private readonly int _boardSize; //Caching the board size
private readonly int _boardSizeMinusOne; //cashing the board size minus one in order to perform the subtraction only once

public TicTacToe(int boardSize) // constructor will set the rows and columns array sizes, cash the board size and calculate the boardsize - 1
{
_rows = new int[boardSize];
_cols = new int[boardSize];
_boardSize = boardSize;
_boardSizeMinusOne = _boardSize - 1;
}

//Function to add a Square taken by player X and return true if X won due to this addition
public bool AddSquare(int row, int col)
{
if (_rows[row] == _boardSizeMinusOne) return true; //Since X exist in this row, check if there were two more (or board -1). if so, adding this X will make X take all the squares in this row and hence win
_rows[row] += 1; //otherwise increase the number of X's in this row

if (_cols[col] == _boardSizeMinusOne) return true;
_cols[col] += 1;


if (row == col) //this is the 270 degrees diagonal
{
if (_270Diagonal == _boardSizeMinusOne) return true;
_270Diagonal += 1;
}

if (((row + col) == _boardSizeMinusOne)) //this is the 45 degrees diagonal
{
if (_45Diagonal == _boardSizeMinusOne) return true;
_45Diagonal += 1;
}
return false; //No winner yet
}
}





This class contains the AddSquare function which will add a square taken by X and will let us know if X has won due to this addition.

This algorithm will visit every single square only in the worst case scenario and at this time the Big O will be n to the power of 2.

in order to test this class we would create a sample board and use the class as follows

static void Main(string[] args)
{
var board = new int[3,3];
board[0, 0] = 0;
board[0, 1] = 0;
board[0, 2] = 1;

board[1, 0] = 0;
board[1, 1] = 0;
board[1, 2] = 1;

board[2, 0] = 1;
board[2, 1] = 0;
board[2, 2] = 1;

var ticTacToe = new TicTacToe(3);
for(var row = 0; row != 3; row++)
{
for (var col = 0; col != 3; col++)
{
if (board[row,col] == 1)
if (ticTacToe.AddSquare(row, col))
{
Console.WriteLine("Player 1 has won the game.");
Console.ReadKey();
return;
}
}
}

Console.WriteLine("No one won");
Console.ReadKey();
}


a better algorithm could select the squares to examine more carefully and improve the worst case scenario. If we look at the board, we find that the middle square is responsible about 4 different possibilities of winning, and if this square does not contain X, then that means 4 different possibilities are eliminated. secondly the corner squares are responsible for 3 different possibilities and if a corner square does not contain X then 3 possibilities are eliminated. so, if we start with the middle square and then the corner squares the worst case scenario will indeed be improved.

Not only that, but if we can store the importance of every square and how many possibilities it is a member of, then during the examination of the board we will find that some squares will not affect the board and hence we should not check it. here is an illustration.

3

2

3

2

4

2

3

2

3

In the board above, the center square has a weight of 4, and that means it is part of 4 possibilities to win the board. the possibilities are, row 2, column 2, and the diagonals. if we check this square first and it turns out it does not contain an X, then those 4 possibilities are eliminated and the weights of the affected squares can be decreased as per the diagram below

2

1

2

1

-

1

2

1

2

in the board above, the center square is not an X and that means for example for the top left corner square, there is only two possibilities that this square can be part of. the two possibilities are row 1 and column 1, because the 270 degrees diagonal that it was part of has been eliminated.

2

1

2

1

-

1

2

1

2

Now can can go ahead and pick the square which the highest weight, in case there are more than one, we can pick anyone, let's pick the top left corner and check it. let's assume we did not find an X in it. that means row 1 and column 1 has been eliminated as follows

-

0

1

0

-

1

1

1

1


if the top left corner is not an X, then we can go ahead and reduce the weights of all the squares that can make a winning situation jointly with the top left square. in this case we will decrease 1 from the weights of all the squares in row 1, all the squares in column 1 and the 270 degrees diagonal. in this case we will notice that row 1 column 1 now has a weight of zero. and that means the value of this square does not matter, whether it is an X or an O it does not matter, because row 1 can never be a row fully occupied by X, and column 2 can never be fully occupied by X. It does not matter what the value of this square is (row 1, column 2). using this technique we will be able to prune the board and eliminate a number of squares that we do not need to check.

This will affect the Big O calculated for this board since it will not be n square. I still need to calculate how exactly it will be and I should expect to see some log n in the calculation.

I will post the C# program here soon.

Wednesday, May 26, 2010

MSMQ load balancing

Microsoft does not recommend load balancing MSMQ, the reason has to do with the level of security demanded via the RPC protocol with MSMQ. The read operation will not be able to make the connection to MSMQ and will be dropped by the receiver. There are no workarounds since this would compromise the security of the connection. However, If you are really desperate to load balance the MSMQ here is one possible architecture.

In order to perform load balancing you will need to distribute the write load among the MSMQ's you have. in order to do this you will need to use a hardware load balancer like F5-BigIp

If you have two MSMQ machines then your writer application will write half of the messages to the first MSMQ and the other half to the second MSMQ. your reader application however can not use the load balancer to do the read. since this read will be a remote read which will be stopped by RPC protocol, your reader applications should be local to the MSMQ. In the diagram below


The writer application writes to the load balancer, the load balancer distributes the messages and check the health of the MSMQ server before sending a message to it. In case one of the MSMQ servers is taken down the load balancer will only forward the traffic to the active MSMQ. which should achieve your load balance and fail-over requirement. You can also add a third or fourth MSMQ to the cluster if you encounter higher load and you want to scale your architecture up. you can also take MSMQ down and your application will not be aware since it always communicate with the load balaner.

For the read operation; Typically MSMQ reading is most efficient when done locally. Having multiple readers on each local machine would provide fault-tolerance along with higher performance. That said, you should have the reader application installed directly on the MSMQ machines. This way the reader applications are performing a local read which will not compromise the RPC security. Your reader application can then process the MSMQ message do whatever it needs to do like sending the contents in email or saving to a database or whatever it is supposed to do.

Wednesday, April 14, 2010

WCF [Global Variables] and [Caching]

WCF is stateless by nature and there is no support for global variables or caching out of the box. However, You can use Caching Application Block to create and access global variables that you might need in your WCF and also to improve performance. View this Power Point Presentation to get acquainted with Caching application block if you need to, otherwise read on.

In this article I am going to discuss how to use the Caching Application Block with WCF and I will show the details and the step by step instructions to add caching to your WCF. The diagram below is a block diagram of the pieces involved



This diagram shows a WCF service running in ASPNetCompatibilityMode. When the WCF starts it will load the cache proactively with look up data. when the look up data expire cache events will fire in order to load the new data. so let's begin.

Caching application block support two modes of caching those are "Proactive" and "Reactive".

In Proactive Caching data is loaded even before any of your WCF operations is called. This is particularly important for look up data because you want your look up data to be loaded and available to all the WCF operations at the start.

In Reactive Caching on the other hand, data is loaded into the cache via the WCF operations themselves.
To use caching application block and load data proactively you can follow the steps below.

1- Download the enterprise library from Microsoft website.
2- Create your WCF and make it support AspNetCompatibilityRequirements. (more on this here). To do so, decorate your WCF class (not the interface) with the following attribute
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

Then add this entry to your web.config inside the node system.serviceModel

3- Nowthat your WCF supports AspNetCompatibilityRequirements, then you can use global.asax. Add global.asax to your project and in the application_start load your cache.

4- Here is the code to load your cache
ICacheManager _wcfCache = CacheFactory.GetCacheManager();
_wcfCache.Add("table1", table1, CacheItemPriority.Normal, new RefreshTable1(), new ExtendedFormatTime("* * * * *"));

The first line will declare and load cache object and the second line will add an entry in the cache. This entry will be refreshed every minute using the ExtendedFormatTime expiration task
new ExtendedFormatTime("* * * * *")
and when refreshed the refresh method in a class called RefreshTable1 will be called to reload table1

The caching application block is also instrumented and that mean you can use PerfMon.exe to see how your cache is doing.


If you are new to performance counters watch this video to get your feet wet in custom counters and read this about performance counters. Here is also a sample application. The caching application block provides the following counters. Read More

Total Cache Misses - NumberOfItems64
Total Cache Hits - NumberOfItems64
Total Cache Expiries - NumberOfItems64
Total Cache Scavenged Items - NumberOfItems64
Total Cache Entries - NumberOfItems64
Total Updated Entries - NumberOfItems64
Total # of Cache Access Attempts - RawBase
Updated Entries/sec - RateOfCountsPerSecond32
Cache Scavenged Items/sec - RateOfCountsPerSecond32
Cache Expiries/sec - RateOfCountsPerSecond32
Cache Hits/sec - RateOfCountsPerSecond32
Cache Misses/sec - RateOfCountsPerSecond32
Cache Hits/sec - RateOfCountsPerSecond32
Cache Misses/sec - RateOfCountsPerSecond32
Cache Hit Ratio - RawFraction


In order to use PerfMon to see your run time cache performance you will need to use the server explorer inside your visual studio and add the keys above as displayed in the screen shots below.







After adding the instrumentation keys, you need to run PerfMon.exe and add the keys to the monitor as per the screen shots below







Then enjoy watching the performance of your cache as follows.







Wednesday, April 07, 2010

Fortify and Team Foundation Server

Do you have Team Foundation Server (TFS) and Fortify and wish they can work together automatically. This article will show one way of making fortify run every time you run a build on the Team Build server. After your build is completed a list of people will receive emails containing the fortify reports. Fortify reports will contain an fpr file that can be opened with the Audit work bench, an html file that can be opened with Internet explorer in addition to a log file.

Let's look at how we will do this.

Using Team Build we will override the "AfterComplie" target to add one Task this task will simply be an exec task. the exec task will run a batch file. This batch file will do all the fortify things. It will run fortify and email the files.

Let's see how we will do that in a step by step way.

Step 1:
-----------
Override the AfterComplie Target.


To do that, Check out your TFSBuild.Proj and just before the closing your Project element add the code highlighted in the screen shot above. in a nutshell what you need is an exec task as follows


The exec task will run fortify in from a batch file.

there are more than that in the screen shot above to use the ASPNetComplier task to combine your website dll's into one.


Step 2
---------------
Create runfortify.bat

Typically this file should look as follows

Rem 1. [CLEAN] Must clean first to clean C:\Documents and Settings\C649318\Local Settings\Application Data\Fortify\sca5.7\build
"E:\Program Files\Fortify Software\Fortify 360 v2.1.0\bin\sourceanalyzer" -b mybuild -clean



Rem 2. [TRANSLATE] Must translate second to create the intermediary Fortify Files. Must build solution first and use the Dll's folder of the solution. use -libdirs to reference any external dll's
"E:\Program Files\Fortify Software\Fortify 360 v2.1.0\bin\sourceanalyzer" -b mybuild -vsversion 8.0 -libdirs "C:\Documents and Settings\tfsservice\Local Settings\Temp\[ProjectName]\fortify\Sources\Main\Source\KPHC.Integration.WebUI\Bin" "C:\Documents and Settings\tfsservice\Local Settings\Temp\[ProjectName]\fortify\Sources\Main\Source\KPHC.Integration.WebUI\Bin" -debug -logfile "C:\Documents and Settings\tfsservice\Local Settings\Temp\[ProjectName]\fortify\Sources\Main\Source\fortifyTranslate.log"


REM [SCAN] and create an fpr and xml file in addition to logs
"E:\Program Files\Fortify Software\Fortify 360 v2.1.0\bin\sourceanalyzer" -b mybuild -scan -f "C:\Documents and Settings\tfsservice\Local Settings\Temp\[ProjectName]\fortify\Sources\Main\Source\FortifyIssues.fpr" -html-report -debug -logfile "C:\Documents and Settings\tfsservice\Local Settings\Temp\[ProjectName]\fortify\Sources\Main\Source\fortifyScan.log"

RunFortify.exe "C:\Documents and Settings\tfsservice\Local Settings\Temp\[ProjectName]\fortify\Sources\Main\Source\FortifyIssues.fpr" "C:\Documents and Settings\tfsservice\Local Settings\Temp\[ProjectName]\fortify\Sources\Main\Source\FortifyIssues.html" "C:\Documents and Settings\tfsservice\Local Settings\Temp\[ProjectName]\fortify\Sources\Main\Source\fortifyScan.log" "myemail@mydomain.com"



you will notice that the batch file also runs a program called RunFortify.exe this is a program that I created, all it does is to email the fpr, html and log files to a specific email address. I am not going to discuss this exe in this post. you can create your own exe that does that or use TFS to email the files.

Tuesday, March 16, 2010

SharePoint unexpected error problem

One of the weired problem with sharepoint is the error below. Sharepoint does not let you change an existing list to add columns to it or edit your wikipages. The error given is "An unexpected error has occurred"
Trying to solve this problem you would normally think that you want more details about the error. in order to get more details you would need to change this custom error page and see the full call stack. in order to do this you would change web.config CustomErrors settings and the call stack settings. the web.config is the web.config of your default website. so go ahead and change these two settings as follows.
CallStack="true"
customErrors mode="Off"
After you change these two settings and try to add a column to your list in sharepoint or modify an existing wikipage sharepoint will tell you more details about the error and you know what the error was? it was in validateRequest=true setting. Sharepoint does not like this setting to be true. so go ahead and change it to false as follows
validateRequest="false"
this will basically tell sharepoint to not validate the request for inclusion of javascript which will make your sharepoint subject to XSS attacks but it will solve your problem of not being able to modify existing sharepoint webparts like wikipedia and list columns. Weired but this is how to solve it.

Thursday, March 04, 2010

Cross Domain Solution is JSONP

If you encounter the cross domain problem then you should use JSONP. It seems JSONP is going to be adopted in .Net 4 (reference: http://bendewey.wordpress.com/2009/11/24/using-jsonp-with-wcf-and-jquery/)

to use JSONP download the classes
JSONPBehavior
JSONPBindingExtension
JSONPEncoderFactory
JSONPBindingElement

from

and implement the solution as explained in

you can download the code demonstrating the entire solution from aliayman.com/download/crossdomainJSONP.zip

Friday, January 22, 2010

Network Load Balance and Layer 3 Switch



TO load balance servers in your network you have few options as follows

1- Buy a hardware load balancer like the one sold by http://www.coyotepoint.com/
2- Use software load balancer and here you have two options
a) Use Windows 2003 NLB (Network Load Balance) which is free but very old technology.
b) Use a third party software like Linux Virtual Server (LVS) http://www.linuxvirtualserver.org/ or any third party software
3- Write your own load balance component
4- Use DNS Round robin. Please do not use DNS round robin because of the drawback mentioned in this link http://en.wikipedia.org/wiki/Round_robin_DNS

In this post I am going to hilight few issues related to NLB. First of all it is an old technology and if you are doing load balancing in a professional environment you should really use a hardware appliance like the one mentioned in point 1 above. Hardware appliances offer load balancing algorithms and they check for server and application availability as well. However, if you are experimenting with load balancing or doing it at home and don't want to spend a penny then you can use NLB.

NLB basically tries to broadcast the request to all the servers in the cluster and one of the servers says I got it. and that's it. Before you even try NLB make sure the switch you have is a layer 2 switch. if your switch is a layer 3 switch your cluster will never work. to work around this issue you need to create a Layer 2 VLAN in your Layer 3 switch.

The other issue you need to examine is your network interface on your machine. open your registry on both machines and check the interface illustrated below. every machine should have a different GUID for the interface. sometimes different machines will have the same GUID because often times the operating system is installed from the same copy and every thing ends up being the same even the network interface GUID. in this case you need to uninstall your network adapter and install it again.



To create an NLB cluster
  1. To open Network Load Balancing Manager, click Start, click Administrative Tools, and then click Network Load Balancing Manager. You can also open Network Load Balancing Manager by typing Nlbmgr from a command prompt.

  2. Right-click Network Load Balancing Clusters, and then click New Cluster.

  3. Connect to the host that is to be a part of the new cluster. In Host, enter the name of the host, and then click Connect.

  4. Select the interface that you want to use with the cluster, and then click Next. (The interface hosts the virtual IP address and receives the client traffic to load balance.)

  5. In Host Parameters, select a value in Priority (Unique host identifier). This parameter specifies a unique ID for each host. The host with the lowest numerical priority among the current members of the cluster handles all of the cluster's network traffic that is not covered by a port rule. You can override these priorities or provide load balancing for specific ranges of ports by specifying rules on the Port rules tab of the Network Load Balancing Properties dialog box. ClickNext to continue.

  6. In Cluster IP Addresses, click Add to enter the cluster IP address that is shared by every host in the cluster. NLB adds this IP address to the TCP/IP stack on the selected interface of all hosts chosen to be part of the cluster. NLB doesn't support Dynamic Host Configuration Protocol (DHCP). NLB disables DHCP on each interface it configures, so the IP addresses must be static. Click Next to continue.

  7. In Cluster Parameters, type values in IP Address and Subnet mask (for IPv6 addresses, subnet mask is not needed). A full Internet name is not needed when using NLB with Terminal Services.

  8. In Cluster operation mode, click Unicast to specify that a unicast media access control (MAC) address should be used for cluster operations. In unicast mode, the MAC address of the cluster is assigned to the network adapter of the computer, and the built-in MAC address of the network adapter is not used. It is recommended that you accept the unicast default settings. Click Next to continue.

  9. In Port Rules, click Edit to modify the default port rules. Configure the rules as follows:

    In Port Range, specify a range of 3389 to 3389 so that the new rule applies only to RDP traffic.

    In Protocols, select TCP as the specific TCP/IP protocol that a port rule should cover. Only the network traffic for the specified protocol is affected by the rule. Traffic not affected by the port rule is handled by the default host.

    In Filtering mode, select Multiple host, which specifies that multiple hosts in the cluster handle network traffic for this port rule.

    In Affinity (which applies only for the Multiple host filtering mode), select None if you are planning to use TS Session Broker. Select Single if you are not planning to use TS Session Broker.

  10. Click Finish to create the cluster.

    To add more hosts to the cluster, right-click the new cluster, and then click Add Host to Cluster. Configure the host parameters (including host priority and dedicated IP addresses) for the additional hosts by following the same instructions that you used to configure the initial host. Since you are adding hosts to an already configured cluster, all the cluster-wide parameters remain the same.

    Those steps were copied from http://technet.microsoft.com/en-us/library/cc771300(WS.10).aspx



    http://www.west-wind.com/presentations/loadbalancing/networkloadbalancingwindows2003.asp


Monday, December 14, 2009

Speedup your page load with Ajax

Sometimes you are stuck with a heavy aspx page, lots of computation is happening at the server side or large database transaction, the bottom line your page takes a long time to load. You can use ajax and WCF to enhance the response perceived by the user as follows.

1- Display the page to the user without any data
2- Show progress indicator telling the user that the page is being prepared
3- Send ajax request to your WCF
4- When data is ready show it to the user


Here is how.
Using Java script call a method on the page load as follows
body onload="onload()"


Implement your onload in a script tag in the header section as follows

function onload() {
var svc = new Ayman();
svc.DoWork("Test", OnGreetingComplete, OnError);
}


create your WCF service by using the template Ajax enabled WCF (you may need to install service pack 1 for VS 2008 if you can not see this template in the add new item dialog box)
then write your service code, something like the following

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Ayman
{
[OperationContract]
[WebGet]
public string DoWork(string str1)
{

Thread.Sleep(1000);
return "Hello";

}


in your script block implement the two functions,

function OnGreetingComplete(result) {

$get("dispGreeting").innerHTML = result;
document.all.Pro.style.display = 'none'
}

function OnError(result) {
alert(result.get_message());
}

note that, I have an html label called dispGreeting and when the Ajax call returns the greeting is displayed to the user. and there is a div called Pro which gets hidden when the Ajax call is completed.

It is interesting that your WCF will also receive all the cookies in the request and if you want to find out what cookies you got you can get the current HttpContext as follows

HttpContext context = HttpContext.Current;

and then browse through your cookies or get a specific cookie as follows
HttpCookie cookie = context.Request.Cookies["YourCookieName"];


to download the code for this post please click this link




Saturday, November 01, 2008

mp3 metadata


iPhone music is pretty cool isn’t it. Specially there are lots of free mp3’s out there. It is only inconvenient though to download an mp3 and find that iPhone have blank author name, album and song title. Pretty much the only thing that has a value if the mp3 file name, sounds common, eh? Well I found a nice tool that enabled a geek like me and probably like yourself to edit the mp3 tags from the command line, don’t you just like the command line?

This tool is called Id3, and can be found at
http://home.wanadoo.nl/squell/id3.html

This page also contains a bunch of very useful commands for this tool and the one I certainly use the most is

for %x in (*.mp3) do id3 -a "MyArtist" -l "AlbumName" -g "MyGenre" -t"%f" %x

This command will iterate through my music and change the artist, album name and genre to the ones I specify and then use the file name as the title.

I do this with the music I download off of the internet and they usually lack title, artist and/or album



Thursday, October 30, 2008

Multithreading and events



Don't you just love Multi-threading, well, I love to see my processor being efficiently used and close to at least 70% utilization. even though threads are dangerous however, using threads carefully will allow your user interface to always be responsive.
Nowthat, we will live with threads, those threads will certainly need to talk to the user interface thread. There are many ways for them to start chit chatting and my prefered way is events.
In this mechanism, a thread will raise an event and anyone who is subscribed to this event will receive the event data and will have a chance to process it.
Here is how to do that.
Let's say you have a calls called "Communicator" which will be processed in a thread and need to raise an event when the thread is done. what you need to do is
1- Define a delegate and an event as follows
//Delegate
public delegate void AlertSentHandler(object sender, SentAlertEventArgs e);
//Event
public event AlertSentHandler AlertSent;
2- Raise the event at the proper time as follows
onAlertSent(this,new SentAlertEventArgs(DateTime.Now.ToString()));
3- Since you are using a helper function called onAlertSent then you need to write it as follows
Protected void onAlertSent(object sender, SentAlertEventArgs e)
{
if (AlertSent != null)
AlertSent(sender, e );
}
The onAlertSent method is checking if the delegate is not null (There are subscribers to the event) and then call the delegate itself as shown above.

Now this event is sent because someone will probably care that the thread is done. those who care that the thread is done should subscribe to the event. To subscribe to this event simply subscribe as follows
cm.AlertSent += new Communicator.AlertSentHandler(cm_AlertSent);
and that is...!!!!!
Note: The above topic is different from serializing the threads (incorrectly called Synchronizing the threads). When you need threads to wait for each others you may want to use the serialization techniques, one of them is the ManualResetEvent
which you may declare like this

static ManualResetEvent threadSerializer = new ManualResetEvent(true );
and make your threads WaitOne like this
threadSerializer.WaitOne();
and set and reset like this
threadSerializer.Reset();
//Do thread work
threadSerializer.Set();
There is a complete and good article about this type of serialization techniques in these links

Wednesday, October 29, 2008

My Notes from "About Face" Book

As I am reading this book called "About Face" I remember David Platt's quote about blindly implementing a customer's requirement in software.
He is saying "Imagine a patient who visits his doctor with a horrible stomachache. "Doctor," he says, "it really hurts. I think it's my appendix. You've got to take it out as soon as possible." Of course, a responsible physician wouldn't perform the surgery without question. The patient can express the symptoms, but it takes the doctor's professional knowledge to make the correct diagnosis."

About Face book is saying

Current software, websites interface routinely
1- Make users feel stupid
2- Cause users to make big mistakes
3- Require too much effort to operate effectively
4- Don't provide an engaging or enjoyable experience

To those who do not have a design step I'd say
"You can not effectively design a house after construction begins"

Tuesday, October 14, 2008

Unhandled Exception

As I am working towards my master in information technology from Harvard university here in Cambridge, I attend a class currently taught by David Platt . The previous week assignment was about exceptions and I didn't know that there were two types of global exceptions that you can catch.

I used to know and use the event

Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(
Application_ThreadException);

I just learned that this is not necessarily going to catch all unhandled exceptions, it will only catch all unhandled exception that occur in the UI thread.

If you really want to handle all unhandled exceptions then you need to broaden your scope and implement the domain unhandled exception event as follows.

AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(
CurrentDomain_UnhandledException);

I used to know about both events but didn't really know the difference until I learned about them from my TA (Kevin).

Go to this blog for more details


Have fun catching exceptions.

Thursday, October 09, 2008

Service-Based Database

If you still like those good old days of having your database file shipped with your application instead of relying on a SQL server be installed at the client machine, then you may want to add a SQL Server Express Database to your application. It is still possible to add a file based database to your application which Microsoft calls Service-Based Database [I don't think anyone knows why is it called this] but anyway, you can add it and that's what matters.

You can add the database by right click your project and select add item, then select data from the categories box and then select Service-Based Database as per the screen shot below.


However, if you do so, you may be challenged by the error message

Failed to generate a user instance of SQL Server due to a failure in
starting the process for the user instance. The connection will be
closed.

To solve this problem you really wanna make sure you have an administrator user on your machine. it seems you must start your visual studio as an administrator rather than any other user to be able to add this database to your solution.

To do so and start your visual studio as an administrator, right click your visual studio short cut and select run as as per the screen shot below












When you do so, you will get another dialog box that will ask you to type the name of the administrator user and the password. type the administrator user account and password.



Now don't tell me I am already an administrator on my machine!! doesn't work. the user name has actually to be called "Administrator" if you're an administrator on your machine in the administrators group that doesn't help. you ask why? I don't know.

If your machine does not have an administrator user called Administrator, then create that user and add it to the administrators group so that you can type that name in the dialog above.

Some people reported that this solution worked with them


HTH

Monday, September 29, 2008

Object Identity (Make Object ID)

In Visual Studio for C# there is this cool feature (Make Object ID), which allows you to assign an ID to the object you're debugging. it is very important to note that the object has to physically exist before you can assign an ID to it. so, you can not make this at design time. Even at run time you can not create the ID before the object has been created.

Here is how to use this cool feature given the following program.

            StringCollection ls = new StringCollection();
            ls.Add("ayman");
            ls.Add("ayman");

            foreach (string ss in ls)
            {
                MessageBox.Show(ss);
            }

The foreach loop above declares a string called ss. this ss is not the same ss every time a loop cycle is created. to enjoy the pleasure of seeing this fact, you can set a break point at the foreach line, and then when the debugger stops at the foreach line click F10 once so that ss is created and then hover over the variable ss. at this time, right click and choose "Make object ID" as per the picture below (notice that the debugger has executed the foreach line already and is about to enter the foreach block)



There is also delete object Id if you care to use it.

Friday, September 12, 2008

SCSF Events (One firer and multiple (Not wanted) subscribers)

So when working with SCSF you may face a problem like this.

You have built two views as part of a module (View1 and View2). View1 fires an event that View2 is  subscribed to. this all seems very legal until now. but what if View2 and View2 are loaded and displayed more than one time. now comes the illegal part. every time any of the View1 fires the event, all instances of View2 will receive it and react to it.

To illustrate it even further, assume you have built a hospital application that consists of two views. SearchView and DisplayView. the search view allows the user to search for a patient by specifying part of the patient name. but the SearchView does not display the search result, it is the DisplpayView that displays the results after receiving the Event showResults. now when the user types part of the patient name and click search, the event ShowResults will be raised and DisplayView will receive it. DisplayView will use the EventArgs to find the patient and then display him/her. the problem happens if you loaded two of the SearchView and two of the DisplayView. now when you type part of the paient name in any of the SearchView loaded and click Search, both of the loaded DisplayView will receive this event and will display this patient.

The solution to this problem is to make your module create a new work item every time it wants to add views. then add the views (SearchView and DisplayView) to this new work item.

when you fire the event you fire the event to the subscribers within the work item.
Here is how.
in your ModuleController.cs declare a new workitem as follows

WorkItem instancewi = new WorkItem();

Next, in the AddViews method add this new workitem to the WorkItems collection of the current item

instancewi = WorkItem.WorkItems.AddNew<WorkItem>();

now when adding views add then in this new workitem as follows

instancewi.SmartParts.AddNew<WhateverYourViewIs>();


now when firing an event, you should always be limiting the scope to the work item using PublicationScope.WorkItem enumeration and specifying the current workitem as follows

WorkItem.EventTopics[WhateverYourTopicIs].Fire(this,new EventArgs(WhaeteverWahtever), WorkItem, PublicationScope.WorkItem);

This way when you fire an event from one view, only the other views that were loaded with the same view will receive this event, since they are in the same workitem.
Hope that helps.

CAB/SCSF Visualizer

So I have an announcement to make: if you are a programmer working in 2008 and you don't know the basics of SCSF and the Visualizer, and I catch you, I'm going to punish you by making you peel onions for 6 months in a submarine. I swear I will.

The SCSF/CAB visualizer allows you to see interesting facts about your Workitems. I used it recently to debug and solve a problem in an application that I will be talking about in a next post. The visualizer allows you to see what your currently loaded work items are and shows the hierarchy that the object builder have built for you.

you can still see the same thing using the usual debugger as per the screen shot below, however the visualizer will make it easier for you since you do not need to stop and look for your root workitem to examine its contents. the visualizer will grasp the root workitem for you and will monitor it at all times. 



The screen shot below shows what the Visualizer screen looks like.


The visualizer shows you the root Workitem and its known collections (Items, UIextensionSites, etc..). using the WorkItems collections within the root workitem you will be able to examine what views are loaded and the relationships between your Views and workitems

one interesting thing I notices working with the visualizer is that you can double click a view and the Visualizer will show it to you in the WorkItem Visualization window. even more, it will allow you to interact with it.

To use the visualizer you need to download CAB Visualization Tool which is a dll from here

Copy this dll into your output folder (or add it as a reference in your Shell application) and then  change your app.config (shell.exe.config) by adding the following lines appropriately within the noted sections.


all you need to do after that is to start your application, magically the visualizer will appear and will show you the details of your CAB/SCSF application. neat eh?