Friday, 20 March 2009

MSN Messenger API for .NET


Heres a nice library written in C# which allows you to connect to MSN Messenger and consume many of the messenger library functions

http://www.xihsolutions.net/dotmsn/

Wednesday, 18 March 2009

Creating a custom CruiseControl.NET Plugin


What's great about ccnet is that you have the ability to create custom plug-in's within visual studio using reflection. You can then compile these plugins into DLLs and place them into the ..\CruiseControl.NET\server directory.

You may have used plugin's previously, many can be found at http://ccnetplugins.sourceforge.net/, to aid your continuous integration process for managing releases and controlling versioning.

Versioning is a very important aspect of release management and continuous integration as a whole. Versioning should be maintained and traceable across the whole build process.

For me, I have the following components versioned...
- All Libraries (dll files)
- Source Repository Labels (within SourceSafe, CVS, Sub Version etc.)
- CruiseControl.NET labels (within the web interface for each component)
- The Setup Project (this will also add the version info to Add/Remove Programs etc)


So, if I install a component (MSI in this case) on a clients machine, I can trace it back to the build info, the included libraries, and also, the code in the source repository!
The process of building this standard versioning system, however, isn't quite as trivial as one would hope. Alongside our build system (MSBuild, Nant etc) we can utilise CruiseControl.NET plugin's to aid our CI process.

Here is a code snippit I have used while injects version information into a Wix3 Setup Project.

namespace ThoughtWorks.CruiseControl.s34n.VersionWixFile
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Xml;
    using Exortech.NetReflector;
    using ThoughtWorks.CruiseControl.Core;
 
    [ReflectorType("VersionWixFile")]
    public class VersionWixFile: ITask
    {
        string wixproj;
 
        [ReflectorProperty("WixFile")]
        public string WixFile
        {
            get { return wixproj; }
            set { wixproj = value; }
        }
 
        #region ITask Members
 
        public void Run(IIntegrationResult result)
        {
            // Get Version Info
            string newVersion = "v" + result.Label;
            
            // Inject Into WixProj File
            if (File.Exists(wixproj))
            {
                // Get contents of file
                StreamReader sr = new StreamReader(wixproj);
                string wixProjFile = sr.ReadToEnd();
                sr.Close();
                sr.Dispose();
 
                // Replace version info
                wixProjFile = wixProjFile.Replace("[[VERSION]]", newVersion);
 
                // Write contents of file back out
                StreamWriter sw = new StreamWriter(this.wixproj);
                sw.Write(wixProjFile);
                sw.Close();
                sw.Dispose();
            }
            else
            {
                throw new Exception(string.Format("The specified .wixproj file '{0}' does not exist.", this.wixproj));
            }
        }
 
        #endregion 
    }
}



As you can see, in this example, two references are used..

  using Exortech.NetReflector;
  using ThoughtWorks.CruiseControl.Core;



These DLLs are shipped with CruiseControl.NET, and must be imported into the current solution for your plugin.

We implement the "ITask" interface and must override the "Run" method. The IIntegrationResult parameter provides us with information about the current build, including and not limited to, the version number.
This plugin does a simple replacement, where it looks for a piece of text in the Win project called: [[VERSION]]... it then replaces this with the version of the current build.

Compile the plugin within visual studio and make sure the DLL Library begins with "ccnet." and ends with ".plugin.dll". This is a known issue with CruiseControl.NET, and the plugin wont work correctly otherwise. An example might be: ccnet.s34n.VersionWixFile.plugin.dll

Place this DLL in the "..\CruiseControl.NET\server" directory alongside the ccnet.config file.

The plugin can then be called from the ccnet.config file by using the following code...

<!-- Inject ccnet version into Wix Project File -->
<VersionWixFile>
      <WixFile>[WIX PROJECT FILE PATH]\Product.wxs</WixFile>
</VersionWixFile>


Once this has been injected into the build, we can build the Wix project using MSBuild and produce a versioned MSI Setup Project! (dont forget to restart ccnet!)

View contents of MSI files with ORCA


If you require seeking the contents of an MSI file, its quite easy with the Windows Installer 4.5 Software Development Kit.

The kit includes a utility called "Orca" which gives you the ability to right-click any MSI file, and look at its contents.


1. Install the Windows Installer 4.5 Software Development Kit

2. Go to the installation location and navigate to the "TOOLS" directory.

3. Locate "orca.msi" and install this utility.

4. Right-click any msi and "Edit with Orca".!

Tuesday, 17 March 2009

Insert GUID VBScript Code


I've recently been playing around with Wix and it involves a lot of GUID (Global Unique Identifier) creation. You can assign the following VBScript to a macro key press or toolbar button in visual studio (Menu: Tools > Macros).

Sub InsertGuid()
  Dim objTextSelection As TextSelection
  objTextSelection = CType(DTE.ActiveDocument.Selection(), EnvDTE.TextSelection)
  objTextSelection.Text = System.Guid.NewGuid.ToString.ToUpper(New System.Globalization.CultureInfo("en", False))
End Sub


The following link contains detail on how to assign it to a keypress or a toolbar button.

Assigning VBScript Macros to Toolbar Buttons or Key Sequences

Assigning VBScript Macros to Toolbar Buttons or Key Sequences


If you assign a macro to a toolbar button or key sequence, you can run the macro by clicking the button or pressing the assigned keys.

To assign a macro to a toolbar button

1. On the Tools menu, click Customize.

2. Click the Commands tab.

3. In the Category box, click Macros.

4. From the Commands box, drag the macro's name to the toolbar where you want a button for the macro.

5. In the Button Appearance dialog box, select an image for the toolbar button, and then click OK.



To assign a macro to a key sequence

1. On the Tools menu, click Customize.

2. Click the Keyboard tab.

3. In the Category box, click Macros.

4. In the Commands box, select the macro you want to assign.

5. Click in the Press new shortcut key box.

6. Press the key sequence you want to use for the macro.

7. Click the Assign button.

Monday, 16 March 2009

Visual Studio Team System 2010 CTP


So, late last year, microsoft introduced Visual Studio 2010 CTP for a preview...

I have to say, its a really great tool! Microsoft has parnered with the guys at OMG (Object Modelling Group) to introduce full UML support! You can simply create new a "Modelling Project" and create various diagrams in the WYSIWYG editor. You can also create different diagrams based on what you have drawn, and im sure, diagrams can be created from code as before. Its a slick way to reverse engineer the development ;)


Other things of interest
- Cloud Development for Azure
- Sharepoint Development
- Full silverlight support
- and more...



Download (VHD)

http://www.microsoft.com/DOWNLOADS/details.aspx?FamilyID=922b4655-93d0-4476-bda4-94cf5f8d4814&displaylang=en


Guide to extend the expiry date of the VHD (Required as of 1st Jan 2009!)
:
http://blogs.msdn.com/jeffbe/archive/2008/12/09/dealing-with-the-team-system-2010-ctp-expiration.aspx

Wednesday, 11 March 2009

Adding an Installer to a windows service


So, now you may have a windows service up and running, but you need to install it... its not as hard as yout think...

1. Goto the service designer GUI, right click, and select "Add Installer", and then .NET will create a "ProjectInstaller.cs" file.

2. Goto the "ProjectInstaller.cs" design view. You will see a ServiceProcessInstaller and a ServiceInstaller.

3. In the properties for the ServiceProcessInstaller, you can configure the Account information. Here you can define whether to run the service as a user, system user or even network service.

4. In the properties for the ServiceInstaller, you can configure the start-type (Manual, Automatic, Disabled etc.) and general settings and names for your service.

5. Once the properties have been setup, these two objects have a series of events which allow any custom actions to be performed before or after setup/uninstall etc. Populate the methods with any custom actions you may require.

6. Now create a new Windows Setup project using the standard template and add it to the current solution. Add the "primary output" from the service project. Then, right click the setup project, select 'View', then 'Custom Actions'.

7. Right click the 'Custom Actions' root node in the main tree view and 'Add custom action'. Select the primary output for the service.

8. Add suitable settings for your installer project, then your done!

Adding timers in Windows Services


So if you have tried to add a standard windows timer (System.Windows.Forms.Timer)... you may notice the timer never gets executed. I think this is a poor design flaw made by Microsoft as timers are quite a fundamental part of services in the way they are architectured and constructed.

In any case, there is a workaround, we can use Threading Timers (System.Threading.Timer). These work in a similar fashion.


1. Instantiate a new System.Threading.Timer object

Timer newTimer1 = new Timer(new TimerCallback(newTimer1_Tick), null, 0, 5000);


- This requires a TimerCallback, so we will need a method called "newTimer1_Tick".
- null -> not required
- 0 -> this starts the timer immediatly (0 milliseconds)
- 5000 -> this is the interval... triggers every 5 seconds (5000 milliseconds)



2. Create the callback method...

private void newTimer1_Tick(object state)
{
            
}


- your timer logic falls within this method



3. Remember to dispose of the timers after use...


newTimer1.Dispose();

Debugging a Windows Service in Visual Studio.NET


There is an easy way to debug a windows service in .NET, without having to install it each time (then restart as its marked for deletion!!).

1. Create a new Windows Service Project using the default template.
2. Open "Program.cs"
3. In "Main()" use the following code...

Code Snippet
  1. #if (!DEBUG)
  2.     System.ServiceProcess.ServiceBase[] ServicesToRun;
  3.     ServicesToRun = new System.ServiceProcess.ServiceBase[] { new [Service Name]() };
  4.     System.ServiceProcess.ServiceBase.Run(ServicesToRun);
  5. #else
  6.     // Debug code: this allows the process to run as a non-service.
  7.     // It will kick off the service start point, but never kill it.
  8.     // Shut down the debugger to exit
  9.     [Service Name] service = new [Service Name]();
  10.     service.[Service Main Method]();
  11.  
  12.     // Put a breakpoint on the following line to always catch
  13.     // your service when it has finished its work
  14.     System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
  15. #endif
End of Code Snippet


4. Replace [Service Name] with the class name of your service.
5. Add a method to your [Service Name].cs file (which is also called from "OnStart(string[] args)". This method will contain all of the logic which is debugged. Reference this method in "Program.cs"
6. Set the compiler to DEBUG mode, and start putting some breakpoints in!!


The same applies for VB.NET users

Sorting an Array of Custom Objects in C#


This post discusses two methods of sorting custom objects within C#.
---------------------------------------------------------------------
Consider a simple case of sorting an array of strings in C#. We can simply call the Sort() method to sort the array.
Code Snippet
  1. ArrayList carArray = new ArrayList();
  2. carArray.Add("Corvette");
  3. carArray.Add("Honda");
  4. carArray.Add("BMW");
  5. carArray.Sort();
End of Code Snippet


If you observe the contents of the array after the Sort(), you will notice that the elements are sorted alphabetically ie., "BMW," "Corvette," "Honda."

However, consider a Car Class as shown in Listing 2.
Code Snippet
  1. class Car
  2. {
  3.   public string Make { set; get; }
  4.   public int Year { set; get; }
  5.   public string Location { set; get; }
  6. }
End of Code Snippet


If you create an ArrayList of car objects and try to Sort() it, it would throw an exception. You will need to have the Car class implement the IComparable interface and define the CompareTo method to be able to sort custom objects.


Method 1: Implementing the IComparable Interface

Step 1: Implement the IComparable interface
Code Snippet
  1. class Car : IComparable
End of Code Snippet


Step 2: Define the CompareTo method.

In this example we will be sorting by the Make property of the Car Class.
Code Snippet
  1. public int CompareTo(object obj)
  2. {
  3.   if (obj is Car)
  4.   {
  5.     Car c2 = (Car)obj;
  6.     return Make.CompareTo(c2.Make);
  7.   }
  8.   else
  9.     throw new ArgumentException("Object is not of type Car.");
  10. }
End of Code Snippet


That is it! We are now ready to test if our sorting works.

Step 3: Test Sorting by Make.
Code Snippet
  1. Car objCar = new Car();
  2. ArrayList carArray = new ArrayList();
  3.  
  4. objCar.Make = "BMW";
  5. objCar.Year = 2008;
  6. objCar.Location = "Florida";
  7. carArray.Add(objCar);
  8. objCar = null;
  9.  
  10. objCar = new Car();
  11. objCar.Make = "Honda";
  12. objCar.Year = 1996;
  13. objCar.Location = "Illinois";
  14. carArray.Add(objCar);
  15. objCar = null;
  16.  
  17. objCar = new Car();
  18. objCar.Make = "Corvette";
  19. objCar.Year = 2006;
  20. objCar.Location = "California";
  21. carArray.Add(objCar);
  22. objCar = null;
  23.  
  24. carArray.Sort();
End of Code Snippet


You will now observe that the carArray is sorted alphabetically by Make.

Note: Sometimes instead of using the ArrayList, it is possible that you are working with an object array. You can use the C# built in Adapter() method as shown below.

To convert from an array to ArrayList use:
Code Snippet
  1. ArrayList carArray = ArrayList.Adapter(carObjectArray);
End of Code Snippet

To convert from an ArrayList to object array use:
Code Snippet
  1. Car[] carObjectArray = (Car[])carArray.ToArray(typeof(Car));
End of Code Snippet


Method 2: Using the IComparer Interface

Sometimes, it might be necessary to have more flexibility in your sorting, for example, to provide which property you want to sort the Car array by. In situations like this, we would need to use the IComparer interface and use the overloaded Sort method that takes the comparer instance as an argument.

Step 1: Create a CarComparer class that implements the IComparer interface
Code Snippet
  1. class CarComparer: IComparer
  2. {
  3.   public enum ComparisonType
  4.   {
  5.     Make = 1, Year, Location
  6.   }
  7.  
  8.   public ComparisonType ComparisonMethod
  9.   {
  10.     set;
  11.     get;
  12.   }
  13.  
  14.   public int Compare(object x, object y)
  15.   {
  16.     Car c1;
  17.     Car c2;
  18.  
  19.     if (x is Car)
  20.       c1 = x as Car;
  21.     else
  22.       throw new ArgumentException("Object is not of type Car.");
  23.  
  24.     if (y is Car)
  25.       c2 = y as Car;
  26.     else
  27.       throw new ArgumentException("Object is not of type Car.");
  28.  
  29.     return c1.CompareTo(c2, ComparisonMethod);
  30.   }
  31. }
End of Code Snippet


The main purpose of the CarComparer is to keep track of by what property we are sorting. It has a ComparisonType enum that has the property elements and an overloaded Compare method.


Step 2

Add an overloaded CompareTo to the Car class as shown in Listing 7.

Code Snippet
  1. public int CompareTo(Car c2, CarComparer.ComparisonType comparisonType)
  2. {
  3.   switch (comparisonType)
  4.   {
  5.     case CarComparer.ComparisonType.Make:
  6.       return Make.CompareTo(c2.Make);
  7.     case CarComparer.ComparisonType.Year:
  8.       return Year.CompareTo(c2.Year);
  9.     case CarComparer.ComparisonType.Location:
  10.       return Location.CompareTo(c2.Location);
  11.     default:
  12.       return Make.CompareTo(c2.Make);
  13.   }
  14. }
End of Code Snippet


That is it, we are done. We now have added the ability to sort by Make, Year or Location. Let us test it out.

Step 3
Code Snippet
  1. Car objCar = new Car();
  2. ArrayList carArray = new ArrayList();
  3.  
  4. objCar.Make = "BMW";
  5. objCar.Year = 2008;
  6. objCar.Location = "Florida";
  7. carArray.Add(objCar);
  8. objCar = null;
  9. objCar = new Car();
  10. objCar.Make = "Honda";
  11. objCar.Year = 1996;
  12. objCar.Location = "Illinois";
  13. carArray.Add(objCar);
  14. objCar = null;
  15.  
  16. objCar = new Car();
  17. objCar.Make = "Corvette";
  18. objCar.Year = 2006;
  19. objCar.Location = "ZZ";
  20. carArray.Add(objCar);
  21. objCar = null;
  22.  
  23. CarComparer carComparer = new CarComparer();
  24. carComparer.ComparisonMethod = CarComparer.ComparisonType.Location;
  25. carArray.Sort(carComparer);
End of Code Snippet


We use the overloaded Sort method that takes an instance of the CarComparer class. To sort by other properties, change the ComparisonMethod as shown below.

Code Snippet
  1. carComparer.ComparisonMethod = CarComparer.ComparisonType.Year
End of Code Snippet



Conclusion
This article demonstrates different ways of sorting an array of custom objects. It provides a step-by-step approach in using the IComparable interface and in creating a Comparer class for sorting.

Monday, 9 March 2009

Get your Business and Data Layers talking!


The following sections present the options for passing business entity data to and from your data access logic components, in addition to the advantages and disadvantages of each approach. This information will help you to make an informed choice based on your specific application scenario.


Passing Scalar Values As Inputs and Outputs


The advantages of this option are as follows:

* Abstraction. Callers must know about only the data that defines the business entity, but not a specific type or the specific structure of the business entity.
* Serialization. Scalar values natively support serialization.
* Efficient use of memory. Scalar values only convey the data that is actually needed.
* Performance. When dealing with instance data, scalar values offer better performance than the other options described in this document.


The disadvantages of this option are as follows:


* Tight coupling and maintenance. Schema changes could require method signatures to be modified, which will affect the calling code.
* Collections of entities. To save or update multiple entities to a Data Access Logic Component, you must make separate method calls. This can be a significant performance hit in distributed environments.
* Support of optimistic concurrency. To support optimistic concurrency, time stamp columns must be defined in the database and included as part of the data.



Passing XML Strings As Inputs and Outputs


The advantages of this option are as follows:


* Loose coupling. Callers must know about only the data that defines the business entity and the schema that provides metadata for the business entity.
* Integration. Accepting XML will support callers implemented in various ways—for example, .NET applications, BizTalk Orchestration rules, and third-party business rules engines.
* Collections of business entities. An XML string can contain data for multiple business entities.
* Serialization. Strings natively support serialization.

The disadvantages of this option are as follows:

* Reparsing effort for XML strings. The XML string must be reparsed at the receiving end. Very large XML strings incur a performance overhead.
* Inefficient use of memory. XML strings can be verbose, which can cause inefficient use of memory if you need to pass large amounts of data.
* Supporting optimistic concurrency. To support optimistic concurrency, time stamp columns must be defined in the database and included as part of the XML data.



Passing DataSets As Inputs and Outputs

The advantages of this option are as follows:

* Native functionality. DataSets provide built-in functionality to handle optimistic concurrency (along with data adapters) and support for complex data structures. Furthermore, typed DataSets provide support for data validation.
* Collections of business entities. DataSets are designed to handle sets and complex relationships, so you do not need to write custom code to implement this functionality.
* Maintenance. Schema changes do not affect the method signatures. However, if you are using typed DataSets and the assembly has a strong name, the Data Access Logic Component class must be recompiled against the new version, must use a publisher policy inside the global assembly cache, or must define a element in its configuration file. For information about how the runtime locates assemblies, see How the Runtime Locates Assemblies.
* Serialization. A DataSet supports XML serialization natively and can be serialized across tiers.

The disadvantages of this option are as follows:

* Performance. Instantiating and marshalling DataSets incur a runtime overhead.
* Representation of a single business entity. DataSets are designed to handle sets of data. If your application works mainly with instance data, scalar values or custom entities are a better approach as you will not incur the performance overhead.



Passing Custom Business Entity Components As Inputs and Outputs


The advantages of this option are as follows:

* Maintenance. Schema changes may not affect the Data Access Logic Component method signatures. However, the same issues arise as with typed DataSets if the Business Entity Component is held in a strong-named assembly.
* Collections of business entities. An array or a collection of custom business entity components can be passed to and from the methods.

The disadvantages of this option are as follows:

* Supporting optimistic concurrency. To support optimistic concurrency easily, time stamp columns must be defined in the database and included as part of the instance data.
* Limited integration. When using custom business entity components as inputs to the Data Access Logic Component, the caller must know the type of business entity; this can limit integration for callers that are not using .NET. However, this issue does not necessarily limit integration if the caller uses custom business entity components as output from the Data Access Logic Component. For example, a Web method can return the custom Business Entity Component that was returned from a Data Access Logic Component, and the Business Entity Component will be serialized to XML automatically using XML serialization.