All posts by admin

Detecting Session Timeout in Asp.Net

I recently had the need in my Asp.Net Webforms application to determine if a Session Timeout had occurred while the user was logged in to the app. As you know, while working in a Line Of Business app, many users can be drawn away from the app for extended periods of time after logging in. Upon returning to the app and making their next postback (by clicking some link or button on the form), most applications will have a mechanism to check the timeout limit set in Web.config and force the user to login again if the timeout limit has been passed. This is a basic security mechanism that is broadly used in web apps, and I wanted this behavior in my application.

Well, it turns out there is no built-in event or flag in the .Net framework that indicates when a Session Timeout has occurred. As I began what I thought would be a routine Google search, I found various solutions offered up by many developers who I’m sure are much smarter than me. After filtering through all the variations and approaches I saw on the web, I have trimmed it down to a simple method that works well for me, so I wanted to offer it up here to help anyone else who may encounter this need. You can add this method to your base form or master page code behind.

This simple method will return true if a Session Timeout has occurred, or false if not. You can call this method and take the desired action if true is returned. In my case, I log the user out and redirect them to the login page, passing a querystring parameter that triggers my login page to notify the user what has happened.

Method CheckForSessionTimout():

public bool CheckForSessionTimeout()
{
  if (Context.Session != null && Context.Session.IsNewSession)
  {
    string cookieHeader = Page.Request.Headers["Cookie"];
    if ((null != cookieHeader) && (cookieHeader.IndexOf("ASP.NET_SessionId") >= 0))
     return true;
    else
     return false;
   }
   else
    return false;
}

Here is how I call the above method from the OnInit() method of my MasterPage:

if (CheckForSessionTimeout())
{
 if (Page.Request.IsAuthenticated)
 {
   FormsAuthentication.SignOut();
 }
 NavigateToLoginPage(true);
}

And here is the code for my NavigateToLoginPage() method, where the parameter true means “alert the user that a timeout has occurred” :

public void NavigateToLoginPage(bool TimeOutHasOccurred)
{
  Response.Redirect("~/Login.aspx?mode=timeout");
}

image

On the Login.aspx page, I look for the QueryString parameter of “mode” with a value of “timeout” and display this beautiful yellow <div> to tell the user what has happened.

Grid Column DataBinding feature for VFP Grids

I want to share some code from my custom grid class that creates an easy way to programmatically bind columns in a grid to a cursor that is opened in the workspace. Basically, this method binds each column’s ControlSource property to the field in the cursor that you specify. It  also handles calculated fields, Casting, and a few more things I’ll show in the code samples below.

You do have a custom grid class that you use in your apps, right? So, now just do two things to your grid class:

  • Create a new placeholder method on your grid class named SetColumnControlSources().
  • Create a new method named BindColumn() and add my code from the BindColumn() code sample below.

Now, in each instance of the grid that you use on a form or class or subclass, create the required columns on the grid and set the header captions to match what you intend to show in the grid from the cursor. Be sure to give each column a smart Name property for easy coding (see example below). You do not set the ControlSource of each column while designing the grid. That’s what my fancy BindColumn() method does for you, along with a few more things you’ll see in the code sample. You will make calls to the BindColumn() method from your SetColumnControlSources() method to do the real work. I’ll show you how…

In the SetColumnControlSources() method of each grid instance, you’ll write code like this (specific to each grid<—>cursor matching that you want to build):

Sample SetColumnControlSources() method code:

Local lcRecordSource

With this
.BindColumn(.colItem, ‘item’)
.BindColumn(.colPrint, ‘print’)
.BindColumn(.colPartNo, ‘part_no’)
.BindColumn(.colAltPartNo, ‘altpartno’)
.BindColumn(.colDwgNo, ‘dwg_no’)
.BindColumn(.colDesc, ‘desc’)
.BindColumn(.colQty, ‘qty’)
.BindColumn(.colPrice, ‘price’)
.BindColumn(.colTotal, ‘qty * _RecordSource.price’)
.BindColumn(.colLaborCost, ‘laborcost’)
.BindColumn(.colLaborHrs, ‘laborhrs’)
.BindColumn(.colMachRate, ‘laborcost / _RecordSource.laborhrs’, ‘N(10,2)’)
.BindColumn(.colMtlCost, ‘mtlcost’)
.BindColumn(.colMtlMarkup, ‘mtlmarkup’)
.BindColumn(.colPartCost, ‘laborcost + _RecordSource.mtlcost + _RecordSource.mtlmarkup’)
.BindColumn(.colTotalCost, ‘qty * (_RecordSource.laborcost + _RecordSource.mtlcost + _RecordSource.mtlmarkup)’)
EndWith

*– Other fancy stuff you can do in addition to the above —

lcRecordSource = this.RecordSource

If !Empty(this.RecordSource)
this.colItem.DynamicFontUnderline = ‘iif(‘ + lcRecordSource + ‘.divider=.t., .t., .f.)’
this.colprice.DynamicCurrentControl = ‘iif(‘ + lcRecordSource + ‘.no_quote, [lblNoQuote], [Text1])’
EndIf

Notice how we can build calculated columns that are not even in the cursor, and easily setup a Cast() to control decimals and some DynamicXXX formatting too. Plus, it gives me one nice code window to see all my column binding without having to use the Property Sheet to see what each column is bound to.

So the above is *your* code, and now here’s *my* custom BindColumn() method code that you need to add to your grid class to handle the code you’ll write like the above. This methods assigns the Column.ControlSource property, expanding any _RecordSource references, and also handles the optional Cast() function (see code for .colMachRate above to see how to specify a Cast() format in the third parameter of the BindColumn method).

BindColumn() method code:

Procedure BindColumn()  (Add this method to your grid class)

Lparameters toColumn, tcBindExpression, tcCast

Local lcFieldExpression, lcBindExpression, lcRecordsource

If Vartype(toColumn) = ‘O’ and Upper(toColumn.baseclass) = ‘COLUMN’
lcRecordsource = toColumn.parent.RecordSource

If !Empty(lcRecordsource) and !Empty(tcBindExpression)
  lcFieldExpression = Alltrim(Strtran(Upper(tcBindExpression), ‘_RECORDSOURCE’, lcRecordSource))

  *– Combine RecordSource.FieldExpressiopn
  lcBindExpression = lcRecordSource + ‘.’ + lcFieldExpression

  *– Wrap in Cast() statement if casting was passed in
  If Vartype(tcCast) = ‘C’
   lcBindExpression = ‘Cast(‘ + lcBindExpression + ‘ as ‘ + tcCast + ‘)’
  EndIf

  *– Finally, set controlsource on column…
  toColumn.ControlSource = lcBindExpression
EndIf

Else

Return

EndIf

Finally, to make it all work, you simply set the RecordSource property on the grid and then call SetColumnControlSources():

thisform.Grid1.RecordSource = ‘csrDataCursor’

thisform.Grid1.SetColumnControSources()

 

I found having this in place to be an effective way to handle times when I need to kill the cursor, rebuild it, and then re-bind to it.

Like this:

thisform.Grid1.RecordSource = ‘’

*—Now rebuild the cursor

thisform.Grid1.RecordSource = ‘csrDataCursor’

thisform.Grid1.SetColumnControSources()

 

So there you go. Several tricks could be used to pass in the cursor field that you want to bind to.  I’ve also thought about including a provision for passing in the Header caption too.

Enjoy, revise, and post comments to share any other ideas you have for extending this.

Model, View Model, View – No way (for now)…

I get all the Model <—> ViewModel <—> View stuff.  It’s great theory, but come on! A View Model class that has the same exact properties as the stinkin’ Model that it is wrapping, just so we can say “I used MVVM”.

My little Asp.Net CRUD app is binding the UI controls directly the data properties on a BusinessObject.Entity, where the Entity is a Typed class from a LinqToSql query. (My BO’s are based on the West Wind wwLinqToSql Business Object Wrapper from the West Wind Web Tools for Asp.Net ).  And guess, what… It works! It loads and saves data when the user clicks the buttons.  Imagine that. I’ll be darned if I’m gonna wrap a ViewModel class around that data Entity so I can bind my UI controls to that ViewModel, rather than hooking straight to the Entity properties.  Just too much stinkin’ code required.

I’ve also added a few additionally needed "presentation properties" into my Business Objects to *supplement* the Entity properties that came from the data base row. And, yes, when working with my BO’s, you have to access some properties right off the BO (the custom presentation properties I added) and some come from the main BO.Entity (the real data from the database row). So, you do have to know where to get the data you are after. By doing this, most of my UI binding is against the BusinessObject.Entity properties, and a few UI bindings go against the supplemental presentation properties I’ve added right on the BO.

So, I don’t mind some bit of a hybrid ViewModel approach, but not a separate class where I have to re-host every single property that is on the Entity. And, since this is done on the Business Object class level, all these supplemental  "presentation properties" can still be accessed by other UI apps that work with the same Business Object wrapper classes.

From a theoretical standpoint, sure, it breaks a few rules. But from a real world impact, we are talking about only a handful of supplemental properties. In all the BOs I’ve built (Customer, Invoice, Quote, Shipper, User, Employee, etc.), maybe I’ve added 3 to 5 additional properties on each one to serve what is usually one view, but sometimes two or three different views at the most. If things really get crazy, there might be as many as 10 presentation properties to handle all the views. It still seems like less of an overall burden on the application as a whole to add a few presentation properties right on the BO, rather than dropping an entire Model-to-ViewModel Mapper implementation on my app (homegrown or commercial). Talk about a burden.

Now look, these additional properties will be implemented somewhere. Why not stick them onto something that already exists (the BO) as little light-weight tag-a-longs, rather than create an entirely free-standing ViewModel object, where I put these innocent properties and then I have to REPLICATE all the real properties from the Model too. Is that how this magic ViewModel character makes things "cleaner"? Yuck! Oh, wait, I almost forgot… but look how clean my BO is! No thanks.

Here’s a use case from my app… I want to bind a UI control to the Customer Name for an Invoice Object that I have pulled from the database. Well, rather than attempting to bind through the main Invoice Entity and into the Customer sub-Entity (which LinqToSql handles nicely for me BTW) I’ve added a presentation property on the BusinessObject to access the Customer Name easily, and also guard against several null object cases that can arise.

Example: Attempting to bind a UI control to directly to this property (see below) could crash the UI generation if the Entity object or Customer Entity is null:

busInvoice.Entity.CustomerEntity.Name

Since it’s possible that the busInvoice object’s .Entity property is not even saturated yet, or that the CustomerEntity is null, this could cause problems generating the UI.  And, I certainly don’t want to test for all the potential problems in my UI pages every time I want to display that property. So, I added a property on the busInvoice object to host that value and deal will all the required testing.

Something like:

public string CustomerName
{
get
   {
     if (this.Entity != null && this.Entity.CustomerEntity != null)
       return this.Entity.CustomerEntity.Name;
     else
       return "";
   }
}

Anyway, back to my main rant about going overboard with ViewModels…

So look at this sample I found from a notable Asp.Net guru.  It is a ProductView class that returns a ProductView object from a passed in Product (that you got from your DAL somewhere), and it can return a Product object from a passed in ProductView object, basically by unwrapping the ProductView object and casting the string properties back to the original data types. Look at all this code! Especially look at the ToProduct() method. Wow!  ( code from http://weblogs.asp.net/craigshoemaker/archive/2009/11/03/vm-workshop-model-view-viewmodel-mvvm-and-the-presentation-model-pattern-in-5-ui-platforms.aspx )

It looks like a maintenance nightmare.  I need more convincing that this is the way the pros do it. Perhaps I’ll be a rookie just a little bit longer.

    public class ProductEditView : IUrlSerializer
    {
        public string ProductId { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string QuantityOnHand { get; set; }
        public string Price { get; set; }
        public string ReleaseDate { get; set; }

        public string SerializeToUrlString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("productId={0}&", this.ProductId);
            sb.AppendFormat("title={0}&", this.Title);
            sb.AppendFormat("description={0}&", this.Description);
            sb.AppendFormat("quantityonhand={0}&", this.QuantityOnHand);
            sb.AppendFormat("price={0}&", this.Price);
            sb.AppendFormat("releasedate={0}", this.ReleaseDate);
            return sb.ToString();
        }

        public static ProductEditView ToProductEditView(Product product)
        {
            ProductEditView view = new ProductEditView();
            view.ProductId = product.ProductId.ToString();
            view.Title = product.Title;
            view.Description = product.Description;
            view.Price = string.Format("{0:c}",product.Price);
            view.QuantityOnHand = product.QuantityOnHand.ToString();
            view.ReleaseDate = product.ReleaseDate.ToShortDateString();
            return view;
        }
        public static Product ToProduct(ProductEditView view)
        {
            double db;
            int num;
            DateTime dt;

            Product product = new Product();
            product.Title = view.Title;
            product.Description = view.Description;

            if (double.TryParse(view.Price.TrimStart(‘$’), out db))
            {
                product.Price = db;
            }
            else
            {
                throw new ArgumentException("Price is malformed or not a valid value.");
            }

            if (int.TryParse(view.ProductId, out num))
            {
                product.ProductId = num;
            }
            else
            {
                throw new ArgumentException("ProductId is malformed or not a valid value.");
            }

            if (int.TryParse(view.QuantityOnHand, out num))
            {
                product.QuantityOnHand = num;
            }
            else
            {
                throw new ArgumentException("QuantityOnHand is malformed or not a valid value.");
            }

            product.ProductId = Convert.ToInt32(view.ProductId);
            product.QuantityOnHand = Convert.ToInt32(view.QuantityOnHand);

            product.ReleaseDate = Convert.ToDateTime(view.ReleaseDate);
            if (DateTime.TryParse(view.ReleaseDate, out dt))
            {
                product.ReleaseDate = dt;
            }
            else
            {
                throw new ArgumentException("ReleaseDate is malformed or not a valid value.");
            }

            return product;
        }

Adobe Acrobat PDF Printer output filename on 64-bit OS…

Now that I’ve moved over to Windows 7 64-bit on my primary workstation, I’m in a new world of IT support that I didn’t expect from those extra 32 bits of OS horsepower. My MicroTek scanner is not supported, my HP 2800 Business Inkjet is not supported, and I recently discovered that a technique I use in my Visual FoxPro business application to pre-define the PDF output filename when using the Adobe Acrobat PDF printer driver mysteriously does not work on Windows 64-bit. So, I want to show the remedy in case others encounter this same problem. I’m explaining this from the perspective of a Visual FoxPro application, but the issue applies to all Windows applications, and the remedy can come from many programming languages.

Background… It’s well know that you can prevent the Adobe PDF printer driver from prompting the user to choose a path and filename for the output file by programmatically setting a certain registry key with a string value that contains the desired path and filename of PDF file you want to output. I use this technique to automatically set the path and filename for my users for the various PDF reports we generate to send out to our customers and vendors.

This magic registry key is located at: HKEY_CURRENT_USER\Software\Adobe\Adobe Distiller\PrinterJobControl.  So, you create a string value under that key with the path and name of the *application* that is printing the PDf, and then you set the value of that string value to the path and filename of the PDF you want to create.

Now, the path and filename of the application that is doing the printing is not always easy to figure out, so I can’t solve that mystery here for any given app that you may be using, but I do know (and I forget where I learned this) that for a Visual FoxPro application (.exe), the path and application name can be discovered from the VFP variable “_VFP.ServerName”. Of course, it’s up to you to decide the path and filename of the PDF output file you’re want to create.

So, to bring it all together, you add a string value named after the app that is doing the printing (for instance) “C:\Program Files\Microsoft Visual FoxPro 9\vfp9.exe” and you set the value of that string value to the filename you want the PDF to be called; i.e. “C:\TEMP\JMC_PO_MS2741C.pdf”

Well, that’s how it works on good ‘ole 32-bit OS.  Now, enter into the 64-bit world…

The issue is that the *application* name that the 64-bit OS sees as doing the printing is no longer the actual exe the user is running,  but rather some odd Windows exe named “splwow64.exe” (some spooler-like thingy that actually handles the printing which I learned about here http://www.acrobatusers.com/forums/aucbb/viewtopic.php?pid=57794#p57794 ). So that’s the application name you have to use, and you do have to include the path. Since this spooler thingy exe runs from C:\Windows, the actual registry key that must therefore be created is “C:\Windows\splwow64.exe”.

PDF_Reg

So, with the PrinterJobControl registry key all programmatically setup as described above, when you actually fire off the Adobe PDF printer, the output name is already set and the user will not see the prompt dialog to choose the output path and filename.

Also, be aware that after *you* programmatically create and set the registry value, the Adobe PDF driver will actually delete that string value from the key right after the file is printed. Perhaps this is so the next app that prints won’t use the same name.

Finally, here’s the VFP code I use to set the values for both 32-bit and 64-bit OS’s. (This code uses an instance of the Registry class from the FoxPro FFC classes to work on the Windows registry). Again, this all works the same way whether you are using .Net, VFP, VB, or whatever. The main thing is to setup the registry value the right way.

   oRegTools=createobject(‘registry’)

        m.lcKeyPath = "Software\Adobe\Acrobat Distiller\PrinterJobControl"

       *– This RegKey setting works on 32-bit OS…
        oRegTools.OpenKey(@lcKeyPath, HKEY_CURRENT_USER , .T.)
        lcPrintingApplicationName = _VFP.ServerName
        oRegTools.SetKeyValue(lcPrintingApplicationName, “C:\TEMP\JMC_PO_MS2741C.pdf”)
        oRegTools.CloseKey()

        *– This is the "Application" name that the OS sees as doing the printing when running on a 64-bit OS…
        oRegTools.OpenKey(@lcKeyPath, HKEY_CURRENT_USER , .T.)
        lcSplWow64ProcessName = ‘C:\Windows\splwow64.exe’ && <— This is what the OS sees as what’s doing the printing…
        oRegTools.SetKeyValue(lcSplWow64ProcessName, “C:\TEMP\JMC_PO_MS2741C.pdf”)
        oRegTools.CloseKey()

 

Hopefully, this insight will save someone out there a little headache when working with the Adobe PDF printer driver on these super-duper 64-bit OS’es.

LINQ to SQL, Lazy Loading and Prefetching

I want to recommend this interesting article that explains times when LinqToSql’s native behavior of “Lazy Loading” is not a good thing (from a database performance standpoint), and explains a pre-fetching technique that you can can use when you want to avoid lazy loading hits to SQL Server.

It’s from the the great Rick Strahl. See his blog post at:

http://west-wind.com/Weblog/posts/38838.aspx

I also recommend that you review his LinqToSql Business Object wrapper framework and sample app that he created to show a real-world working app using the framework.

Original article and download, September 27, 2007 (read this first):

http://www.west-wind.com/WebLog/posts/160237.aspx

He also posted an update article on February 05, 2008:

http://www.west-wind.com/Weblog/posts/246690.aspx

And, Rick has continued to update the LinqToSql Business Object wrapper framework since those articles were written, and you can download the latest version which is included as part of the WestWind Web Toolkit for Asp.Net (tons of other goodies are in the entire Toolkit, so check out the free license details, which is a full working version) :

http://www.west-wind.com/westwindwebtoolkit/

 

In closing… You know, they’ve said that LinqToSql was kind of dead, but at least they did do a little work on it for .Net 4 framework. That’s encouraging to me. I think a LOT of people use LinqToSql, and I personally think it will pick up even more, rather than die off. It has a fine place in small-to-mid sized apps, and I frequently hear plenty of notables in the community speak of it.

Here’s is an article on the updates to LinqToSql that included in the .Net 4 framework:

http://damieng.com/blog/2009/06/01/linq-to-sql-changes-in-net-4

Uninstalling Visual Studio 2010 Beta 2

Why am I writing about Un-installing Visual Studio Beta 2 when it was just released yesterday, October 19, 2009? (video announcement can be seen at this link). Well, in the past whenever I’ve used the beta versions of some of Microsoft’s developer tools, I’ve found that it was impossible to uninstall them properly (or fully) when the RTM version was finally released.

Now, I know that VM’s can be used to test out beta software, and I do use VM’s on my machine, as I did when I installed VS2010 Beta 1 on a Windows 7 Beta VM running on VirualBox VM.  But sometimes I still like running right on the bare metal so I will have access to the rest of the tools I need in a full dev environment. Especially now that it’s Beta 2, I’d feel pretty good running it on my live dev machine. But, I was unsure about being able to easily remove it later when the RTM version comes out on March 22, 2010.

So, I posted a question on the Visual Studio 2010 Install and Setup forum of the newly restyled  http://www.msdn.com/forums to see if anyone could address this issue.

My question is titled Will we be able to un-install VS2010 Beta 2, when final version is released?.

Fortunately, I got a very quick reply from a MSFT moderator named Aaronru who claims a very easy and successful uninstall of VS2010 Beta 2 has been tested and WILL allow for an easy upgrade path to VS2010 RTM.

The exact reply was…

For helpful instructions on how to install Visual Studio, we’ve published some detailed instructions for installing and maintaining Visual Studio 2010 Beta 2.

If you evaluated Visual Studio 2010 Beta 1, you will be happy to hear that no reformatting is required. Additionally, simple path exists to appraise Beta 2 on the same machine. It involves uninstalling your Visual Studio 2010 Beta1 product and then installing one of the Visual Studio 2010 Beta2 offerings.  Please refer to the following blog post for more details.

As part of our Beta 2 testing, we did test the uninstall of Beta 2 to ensure that the Beta 2 could be uninstalled sufficiently to the end that you could uninstall Beta 2 and install RTM with as seamless UX as possible.

You can read the entire thread here.

So go for it! The download of VS2010 Beta 2 will be available to the public on October 21, 2009, with final RTM to be released on March 22, 2010.

To Blog or to Forum Post, that’s the question…

I’m not really sure why I’m so driven to do this, but I’ve always been a spread-the-news kind of guy for the VFP community. Any time I see something cool, or that I think others may be interest in, I make a post here-and-there to all the most popular FoxPro sites to spread the word.  So, about a month ago I cranked up this blog for the purpose of doing just that, thinking this would be a good way to go.  Now, I don’t want to compete with the existing forums, because it’s easy enough to go there and make announcements, but I have to visit UniversalThread, and  Foxite, and the ProFox and VFUG lists too, oh, and even Fox.Wikis.com, oh, and sometimes use my FoxCentral.net account. I usually have to hit all those sites with a bunch of cut-and-paste to work all the places I want to reach. Plus, after posting to forums and lists, if I need to tweak the info (corrections, add details, etc), it’s too late to edit or just too much work. And, any conversations (comments) about the topic are now spread out across all the different places and there’s no one place other readers can visit to take it all in. Plus, the formatting and image posting in a blog is much better.

So, I’m trying to decide whether it really adds any value to put this info in a blog post and try to get an audience following the blog, or just keep it old school and post in multiple places.

Your opinions please.

Crash Course to Web Development for FoxPro and Web Connection Developers

I just received an e-mail announcement for what looks like an awesome jump start class for Visual FoxPro developers to get their feet wet in the .Net Web development arena. Super-smart web maven Rick Strahl plans to give you 3 days of quick start how-to teaching on the .Net / Web development train.

You can attend live or watch on GoToMeeting. It’s a 3-day class, November 5, 2009 through November 7, 2009.

Here is a link with all the details: http://eps-software.com/EventDetail.aspx?id=37d20fbb-6632-4264-8db5-b1665904b00a

(P.S. – Does anyone want to sponsor me?)

The color of your comments

Recently I had a thought that the comments in my code may be getting in the way of me actually seeing the code itself while I’m coding. There seems to be two camps in the code commenting world: (1) Write good code and you should not need comments and (2) Write comments or else you are being lazy and no one will ever be able to work with your code. Well, I’m not here to settle that debate (I fall somewhere in the middle).

So, I had this idea of changing the COLOR of my comments from GREEN to GREY, so that I could still see them, but they would kind of fade away into the background, but would still be there if I took a harder look. I suppose the default VFP comment color must be that classic green color that I’ve been looking at for years, so I’ve changed mine to grey to help me focus better on my code, and not the comments.

Who knows, maybe one day I’ll be a real programmer and won’t even need to write comments at all.

Also, the smart one, Bo Durban, posted this hint on UT (in response to this blog post) about how you are not limited to the base 16 colors:

Did you know…If you set it programmatically, you are not limited to the base 16 colors?:

oReg = NEWOBJECT("FoxReg",HOME(2)+"classes\registry.prg")
oReg.SetFoxOption("EditorCommentColor","RGB(80,140,80,250,250,170),NoAuto,NoAuto")
SYS(3056,1)

So, here are a few screenshots to compare… Give it a try and see what you think.

Grey Comments: Green Comments:

Ruby on Birmingham

In case you’re interested, here is a link to the RubyHam users group in Birmingham, Alabama. They have monthly meetings, usually meeting on the first non-holiday Monday of the month. The meetings are around lunch time, rather than at night. I’ve never been to one the meetings, and I’ve never used Ruby, but I did see a presentation about it once and it seemed cool enough to make me want to learn more about it. I plan to go to the next meeting on September 14, 2009 just to see what it’s all about. Will I see you there?

http://tech.groups.yahoo.com/group/rubyham/

Ruby is a (non-Microsoft) language that seems to have reasonable popularity among the kids. Microsoft is working on a version for .NET called IronRuby: http://www.ironruby.net Since I am indeed a Microsoft fanboy, that will probably win my first dance.

Get involved. Enjoy. The choices are endless.