Wednesday, February 28, 2007

Central Coast Code Camp

Ok so the site is ugly so far since I don't have time to get a graphic designer to help out...but I've got this grand vision of bringing the code camp concept to the California Central Coast so that we don't have to drive forever to go to conferences or catch up on new technology or pay bunches of bucks...with that in mind:

http://www.centralcoastcodecamp.com

I've started preliminary work on finding a facility, and you can see from the Manifesto that there will be a lot of legwork to get enough volunteers and support from local companies to make this happen. But you've got to start somewhere and one thing I learned when I started the San Luis Obispo .NET User Group was sometimes you have to draw your line in the sand and just have a meeting to get things started.

This is going to be open to technologies of all types so this will be a good way for me to reach out to my development brethren amongst the heavy Java/PHP developers in the area and try to get us all together.

It's either going to be great fun or a great disaster! But either way it's going to be great.

Rob

Wednesday, February 21, 2007

Sorting Generic Lists

One of the things I like best about the use of Generics is the ability to define your own sorting functionality and apply it to a List. Much in the same way you can predefine your own Find mechanism using predicates, you can establish a way to sort your list of Generics when they don't contain native datatypes such as int or string.

In this example we'll take a look at how to sort a Generic list using the IComparer interface.

First of all, let's establish a class of type Dog, and give it three properties. The first property we'll call Species, and the next property we'll call Age. The final property we'll call Name.

public class Dog
{
private int _age;
private string _species;
private string _name;

public string Name
{
get{ return _name; }
set{ _name = value; }
}
public int Age
{
get{ return _age; }
set{ _age = value; }
}
public string Species
{
get{ return _species; }
set{ _species = value; }
}
}

Now that we have that we can create a list of four dogs like so:

Dog max = new Dog();
max.Age = 8;
max.Species = "Labrador"
max.Name = "Max"

Dog spike = new Dog();
spike.Age = 3;
spike.Species = "Rottweiler"
spike.Name = "Spike"

Dog princess = new Dog();
princess.Age = 5;
princess.Species = "Poodle"
princess.Name = "Princess"

Dog wolfy = new Dog();
wolfy.Age = 10;
wolfy.Species = "Husky"
wolfy.Name = "Wolfy"

List<Dog> dogs = new List<Dog>();

dogs.Add(max);
dogs.Add(spike);
dogs.Add(princess);
dogs.Add(wolfy);

Now I'd like to be able to sort a few different ways, and I can do this by providing an object that implements an IComparer interface of type Dog, like so:

public class DogAgeComparer : IComparer<Dog>
{

}

Now that I have my class, let's implement the interface:

public class DogAgeComparer : IComparer<Dog>
{
#region IComparer<Dog> Members

public int Compare(Dog x, Dog y)
{
return x.Age.CompareTo(y.Age);
}

#endregion
}

Now that we have that, we can sort our list based on the dog's age:

dogs.Sort(new DogAgeComparer());

This will sort the list in the appropriate order of age.

Similarly, we can use a different object for Name and have that available as well.

public class DogNameComparer : IComparer<Dog>
{
#region IComparer<Dog> Members

public int Compare(Dog x, Dog y)
{
return x.Name.CompareTo(y.Name);
}

#endregion
}

Now sort the list:

dogs.Sort(new DogNameComparer());

And there you have it! Quick and easy sorting of your objects.

Happy sorting!

 

Rob

Friday, February 09, 2007

Dynamically Controlling Windows Services Using SC.exe

There are many instances where you would like to have remote control over Windows Services.  In fact, during deployments, you might want to even have the ability to remove and reinstall Windows Services on the fly, or even go so far as to install multiple copies of the same service under different names and/or configurations.

These requirements go beyond the ability of the native installation procedures that are included with Visual Studio or the framework (such as InstallUtil.exe).  However, with SC.exe, you can have complete control over Windows Services, and even install them with different names and so forth.

SC.exe comes with the Resource Kit and runs from the command line.  It takes a variety of arguments, including a command, the service name, the path to the file, the display name, and the machine to execute against.

sc [Servername] Command Servicename [Optionname= Optionvalue...]

It's important to note that the space after the "=" in the Optionname key value pair DOES exist and is not a typo!  You'll see that in the examples below.  Most of us have a tendency (myself included) to look at that and assume there's no way that the space should be there, but it is.

The servername is optional;  if not provided this will run against the local machine.

There are many commands you can give, but the important ones are:

Start
Starts a service
Stop
Sends a Stop request to a service.

Create
Creates a service (adds it to the registry).
Delete
Deletes a service (from the registry).

It's important to note that the ServiceName here is the actual ServiceName, NOT the Display Name, which is generally what you use when issuing Net Start commands.

So, if we wanted to stop the BlogReaderService on BlogBox1 from BlogBox2, at the command line on BlogBox2 we would enter:

sc BlogBox1 Stop BlogReaderService

There are several options available as well for the executable.  Here are a few of the important ones.

start=boot, system, auto, demand, disabled
Start type for the service. Option values include types used by drivers.
(default = demand)

binPath=(string)
Path name to the service binary file. There is no default for this parameter. This string must be supplied.

DisplayName=(string)
A string that can be used by user-interface programs to identify the service.

So let's assume that during deployment I want to stop, delete, create, and start my BlogReaderService.  My BlogReaderService.exe sits in my c:\temp folder.  I want the BlogReaderService to start automatically, and want its DisplayName to be MyBlogReaderService.  Assuming I am on BlogBox2 and I want this to occur on BlogBox1, the four commands would look like this:

sc BlogBox1 Stop BlogReaderService

sc BlogBox1 Delete BlogReaderService

sc BlogBox1 Create BlogReaderService start= auto binPath= c:\temp\blogreaderservice.exe DisplayName= MyBlogReaderSerivce

sc BlogBox1 Start BlogReaderService

Note the spaces after the "=" in the command line...

Now that I have that, let's assume I have a second copy of blogreaderservice.exe sitting in c:\temp2 with it's own blogreaderservice.exe.config pointed a different datasource.  Now I want to install it, but I need a different service name and display name and start it because the service is already there from the exe in c:\temp.  That command line would look like this.

sc BlogBox1 Create SecondBlogReaderService start= auto binPath= c:\temp2\blogreaderservice.exe DisplayName= MySecondBlogReaderSerivce

sc BlogBox1 Start SecondBlogReaderService

And there you are...two copies of the service installed under different names.

Have fun!

Rob

Monday, February 05, 2007

Stack Reflections

If you haven't noticed by my choice of presentation topics, I'm a big fan of Reflection. I like the flexibility and scalability it allows me to build into my applications. There are also some neat little tricks you can use with it, in conjunction with the stack trace, to better track your errors and debugging statements.

First of all, how would you like to be able to write a trace statement that shows your methods called without having to remember to code the method names? This can be accomplished by "walking the stack trace" during a method call and using the reflected method information from the stack to determine what method called your function. It works something like this:

I'm going to write a method called TraceMethodStart with no parameters. This method will load up the stack trace, walk the stack frame back one level, and then write out to Trace the method name and module name of the method that called the TraceMethodStart function.

public void TraceMethodStart()
{
System.Diagnostics.StackTrace currentStack = new System.Diagnostics.StackTrace();
string sMethod = "Unknown method";
string sClass = "Unknown type";

//make sure I have frames
if (currentStack.FrameCount > 0)
{
//get the method of the frame one up from me

System.Reflection.MethodBase oBase = currentStack.GetFrame(1).GetMethod();
sMethod = oBase.Name;
sClass = oBase.DeclaringType.ToString();
}

if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Trace.Write("Starting: " + sClass + " " + sMethod);


}

Now in my GetRob() function I do this:

namespace Sltc
{
public class Rob
{
public void GetRob()
{
TraceMethodStart();
}
}
}

And a "Starting: Sltc.Rob GetRob" will appear in our trace statements.

Now that's useful. But it would be even more useful if we knew what was being passed to the function for parameters. Using the params keyword we can extend this function to accept a variable list of arguments so that we can call it from anywhere in our code and get passed any number of arguments. This will allow us to include the variables the function was given when it was called.


public void TraceMethodStart(params object[] oParms)
{
System.Diagnostics.StackTrace currentStack = new System.Diagnostics.StackTrace();
string sMethod = "Unknown method";
string sClass = "Unknown type";

//make sure I have frames
if (currentStack.FrameCount > 0)
{
//get the method of the frame one up from me

System.Reflection.MethodBase oBase = currentStack.GetFrame(1).GetMethod();
sMethod = oBase.Name;
sClass = oBase.DeclaringType.ToString();
}

if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Trace.Write("Starting: " + sClass + " " + sMethod);


foreach(object obj in oParms)
{
if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Trace.Write("Parm: " + oParm.ToString());
}
}

Now if you are in a method like so, you can do this:

function MyMethod(string s, int i)
{
TraceMethodStart(s, i);
}

Another handy thing you can do with this is to grab the cause for exceptions. A lot of times the stack trace is huge and it's difficult to track down or even remember to write code to track where your exceptions are occuring. However, if you were to create your own exception, you could use a similar code sequence to grab the cause of the trouble:

public class SLTCException : System.Exception
{

private string _sClass = "Unknown";
private string _sMethod = "Unknown";

public SLTCException() : base()
{
System.Diagnostics.StackTrace currentStack = new System.Diagnostics.StackTrace();
if (currentStack.FrameCount > 0)
{
System.Reflection.MethodBase oBase = currentStack.GetFrame(1).GetMethod();
_sMethod = oBase.Name;
_sClass = oBase.DeclaringType.ToString();
}
}
}

Happy stacking!

Rob

Thursday, February 01, 2007

Rock n Roll Code Camp Presentations

Hey all,

I spoke at the Rock n Roll Code Camp (http://www.socalcodecamp.com) this past weekend and it went very well. I'm considering giving the same talk / pair of talks in San Diego later this year, or I might come up with a new couple of talks, not sure yet. Always tough when the big hitters take the most common topics. Maybe I'll flesh out the Generics talk I gave to the User Group a few months ago so that it's a full hour and give that if no one else pipes in on it!

Anyway, here are links to the ppt and code for the two talks I gave:

Packaging in .NET 3.0: http://www.sanluistech.com/samples/packaging1.zip
Reflection in .NET: http://www.sanluistech.com/samples/reflectiondemo.zip

Have at them, and send me any questions you might have...

Rob