April 2004 Entries
First post in a while...illness and other stuff I'll blog about later...but to mark Poem in your pocket day...a bit early, here's one from one of my homies - Robert Burns (born just down the read from where I was - we all speak like this you know!).
To A Louse
Robert Burns
ON SEEING ONE ON A LADY'S BONNET AT CHURCH
Ha! whare ye gaun, ye crowlin ferlie!
Your impudence protects you sairly:
I canna say but ye strunt rarely Owre gauze and lace;
Tho' faith, I fear ye dine but sparely On sic a place.
Ye ugly, creepin, blastit wonner,
Detested, shunned by saunt an' sinner,
How daur ye set your fit upon her,
Sae fine a lady!
Gae somewhere else and seek your dinner,
On some poor body.
Swith, in some beggar's haffet squattle;
There ye may creep, and sprawl, and sprattle
Wi' ither kindred, jumpin cattle,
In shoals and nations;
Whare horn or bane ne'er daur unsettle
Your thick plantations.
Now haud ye there, ye're out o' sight,
Below the fatt'rels, snug an' tight;
Na faith ye yet! ye'll no be right
Till ye've got on it,
The vera tapmost, towering height
O' Miss's bonnet.
My sooth! right bauld ye set your nose out,
As plump an' grey as onie grozet:
O for some rank, mercurial rozet,
Or fell, red smeddum,
I'd gie ye sic a hearty dose o't,
Wad dress your droddum!
I wad na been surprised to spy
You on an auld wife's flainen toy;
Or aiblins some bit duddie boy,
On's wyliecoat; But Miss's fine
Lunardi!—fie! How daur ye do't?
O Jenny, dinna toss your head, An' set your beauties a' abread!
Ye little ken what cursed speed
The blastie's makin!
Thae winks and finger-ends, I dread,
Are notice takin!
O, wad some Power the giftie gie us
To see oursels as others see us!
It wad frae monie a blunder free us
An' foolish notion:
What airs in dress an' gait wad lea'e us,
And ev'n Devotion!
You can read more about it
here. So, on 30th April, put a poen on your blog and link to others...
like these. I like this particular poem for a few reasons - it's in the dialect of my part of Scotland (it's a bit broader being so old...but basically the same), Mr Kelly, my favourite teacher in School taught us it - one of the best teachers I ever had and it has a great line -
O, wad some Power the giftie gie us
To see oursels as others see us!
Translation,
Oh would some power the gift to give us to see ourselves as others see us.
Which I think is a very nice sentiment - the poem is basically (to me) a warning that even though you might put on heirs and graces you can never really know how others percieve you.
I've done this in a few ways in the past, ranging from custom XML templates with XSLT / Regular Expressions to screen scraping -
this is just the simplest and cleanest way I've seen to do this (also a very nice example of using the RenderControl method...). Actually, be sure to check out the rest of the content on
this blog, some really handy stuff on there...
I've written previously that I've been hunting for a decent way to do web site search (specifically for CMS 2002 but just in general too...). I have been looking at Lucene.NET (which is in .TEXT 0.96) and a few other options. One interesting (and low cost - $39.99) option seems to be
this. Essentially it provides a web crawler extension for Index Server, anyone tried this, any other options for low cost site search (as distinct from DB search / file-system based ones) I should consider?
Well, after a bit of playing I've got something working now, I'm no Win32 coder but this seems to work:
A sudden problem has occurred on my blog and I'm not sure why...RSS feeds work fine, but the actual homepage does not, tried reindexing my SQL server, deleting a bunch of posts etc...still no joy! Very annoying!
UPDATE: So changing the skin seems to have cured the problem - I'll leave this boring one on for the moment, I'll upgrade to 0.95 (maybe 0.96 if I'm feeling brave) at the weekend.
This is one of these things that's been running on a background thread in my brain for about a year, I have never seen a good example of how to do this but it just seems handy (I don't know what for but it 'feels' handy). Anyway, in the Codeproject mail thingy today this article was hiding at the bottom. Now, one of the comments mentions a way to do this in C# - going to have to try to get this working!
UPDATE:Â I almost have this working (just a very slight size issue right now) the handiest info is this discussion
Â
You don't get to go to conferences. It really sucks, I would love to go to
these things (though when I worked at a previous company which did send me to the Wrox conference in Amsterdam I umm... remember very little of it!). So, the choice is, blow almost £2000 of my own money going to a conference (so conference or holiday in the Bahamas would be my choice :-|) or just don't go..guess which is more likely. Incidnetally, if there is some Microsoft person who wants a gofer during the Teched Europe - or just someone to point at and laugh at and is willing to pay for me to go that would be just lovely :-) (not very likely is it - but you have to try!)
I was doing some work on the new version of my first article last night and I got to thinking, all the code in the new version is in the same font / colours that I use in my VS.NET. So, I was showing the new version to a friend and he mentioned that most people use fixed-width fonts when coding like
profont. This got me to thinking, am I missing some trick here, I always use Verdana 8pt on a 1600x1200 120DPI screen with tuned Cleartype when I code - what's the disadvantages of this - why would I want to use a fixed-width font?
I worte a few days about reasons I'd never be an MVP - today is a great exemplar of that. So far, I've fixed a few bugs on a bespoke community application (event handlers, HTML changes, T-SQL the lot), I' have  some more work on a generic search control based on Lucene.NET for inclusion in some of our projects,I have bit more work on an HttpModule I'm writing to hook CMS2002's workflow and security systems in with an external one we require and done some initial planning on a new pitch...I'm also in the planning stage of a quick Forum control which can work inside and outside of a CMS2002 placeholder.
Well...at least it keeps me busy :-)
I sometimes wonder if I'd be happy just focussing on one area all day - I really don't know if I could handle working on a single tool day after day...maybe a job on the MS Office for Macintosh team isn't in my future ;-)
Been having a play with the new search engine of the moment,
a9...hmm...one suspects that
Amazon will be collecting a fair bit of market info from this engine (can you think of another reason they'd want to do this?). First impressions are that it's very 'feature rich' (i.e, packed with stuff I'll never use), the popup site infor thing is pretty good I have a Traffic Rank of 1369996 - which probably puts me around the realms of the native Latin speakers portal.
I've been lurking about in the ASP.NET forums a fair bit this evening and lo and behold I'm not moderated any more! Very cool - I guess I may have accidentally stumbled upon some right answers (see, you can apply JSP knowledge to ASP.NETÂ ;-))
I tried my experiment again today. I don't know about overseas but in the UK at crossings we have a green man and a red man - you walk at the green man. Now, I had believed it was commonly known that the green man doesn't appear unless you press the little button at the crossing which activates the 'wait' sign - which then triggers the crossing to change to green. Apparently this is not common knowledge (not in Edinburgh at least). Today I tried my experiment (I had a little time to spare :-)) when I arrived at the crossing, it was at red with about 20 people standing waiting to cross - but no-one had pressed the little button...so I waited...another 20 or so people joined over the next 6 minutes or so...still no-one pressed the button...I waited...a total of 10 minutes had passed and about 50 people were waiting to cross...I pushed the button, 15 seconds later, the green man appeared. Now I have never claimed to be some godlike genius but really, come on how dumb do you have to be not to realise that not pressing the button leads to the crossing not activating? (note this excludes IR sensor based crossings - of which there are a very few)
I'll be honest, this one puzzled me and I came up with some really hackneyed solutions to manage the situation where a user-uploaded file contained a virus (I develop lots of community sites which allow file uploads). Most of the solutions I came up with relied on using a FileSystemWatcher running as a service that detected when the Visrus Scanner on the server moved a file to quarantine - which works, but the fact is that even for a short period you have a virus laden file on your Web Server - sysadmins hate that! So, I was doing a little digging around and discovered
this, it's basically a virus scanner which works as an ISAPI filter, monitoring all traffic passing into and out of IIS for viruses...probably really old news to most but I though it was cool!
I was replying to this forum post I actually couldn't find a good example on how to do this - wierd, it's such a common thing to do. So, the problem is, is there a better method than using the Application object to store objects which should be available for the entire lifetime of the application? Yes, global static variables are a great way to do this. Simply, you use the global.asax.cs file to define a static property - you can then access this simply using the Global.* in your code. For example, in the global.asax.cs:
Now, in any class I can access this...like so...
Cool, no copy required, (yes I do realise I should actually be locking this first to ensure thread safety...)So, short one, but might come in handy for someone! Oh, I did a little example app which also shows using this in an HttpModule, you can
download it here
Oddly I've had a couple of email (even one from a
Microserf) asking why I thought I would never become an MVP. Well, the simple answer is - time. Keeping a blog takes relatively little time, I probably spend an hour a day max posting to this thing and leaving selacious comments on other peoples - fine, I have no problem doing that. The problem arises when I have to block out significant periods of time to do stuff. In any one day I probably have about 2 hours where I can truly devote time to doing stuff of a technical nature, usually I spend my time reading articles and / or my book d'jour (currently
Practical Cryptography which is excellent by the way). That's kind of the problem I get bored very quickly so the chances of spending enough time on one subject to be seen as any type of authority is pretty unlikely.
I do trawl through the
ASP.NET forums on occasion and hunt down questions which I feel I could answer and that no-one else has (or has answered in such a dumb way that it amounts to the same thing) - but for me this usually takes an amount of time. I tend not just to link to KB articles / provide simple Googlized information, for this reason the number of posts I make there is pretty small (in the 200s the last time I looked). I've literally spent 3-4 hours writing example projects / code before now trying to find the best solution to a problem asked in the forums.
So in short, I'll never be an MVP because I don't have the time to devote to participating in the community that would seem to be a prerequisite.
Just noticed
this article by
Paul Wilson from reading
this post on his
V1.x MasterPages Stuff. Nice, compact article on the timing of Page events in ASP.NET...very handy!
Roy clarifies his position on the whole Rory thing...(incidentally, Rory, I tried to email you but it bounced back)
My response, well, I posted an ill concieved post yesterday about the whole debacle which I have since withdrawn. Here's the response only response I'm willing to give on the whole thing - I will not enter into a debate on this - sorry!
I will never be made an MVP - so I have no vested interest in this apart from the desire to form a strong .NET community.
Sad thing is, the MVP title is worth something it's just not transparent enough and the few bad ones can tend to sour the whole barrel. It would be really nice if the community was more involved in the selection of MVPs and once they were announced, the reason for the selection was made more public.
Some current MVPs do seem to have been awarded for purely PR / other reasons - I hate to say, bribe but for some it does look that way. So, what does everyone think, should this be more open? Do you think that writing a book should justify you being made an MVP?Â
So someone who wasn't an MVP got to go (probably a few people if truth be told, just that Rory blabbed). Unfortunately, this kind of thing does leave a bad taste - not because I  have anything against Rory. Problem is, building a community; something which seems to meet Microsofts' current PR aims; requires trust, it has to have leaders of course but those leaders must be seen as having earned that position once you single out an individual for 'special treatment' it can tend to cause friction within the community. Some MVPs have pointed out that they couldn't really see the reason that Rory was asked - most MVPs work hard to earn their award, one of the (as I see it relatively few) perks is getting in on the undisclosed information at the summit, having a back-door to getting there does seem a little unfair on these people. Again, this is not an attack on anyone but Microsoft, if you're really going to build a community, transparency in the selection for your proclaimed 'community leaders' - which is how you want us to view MVPs now, right? - would be a good first step.
Someone emailed me asking when the new version of my
nested repeater article would be available - all I can say is very soon - hopefully I'll get some time to finish it this week. Anyway, the source code for the examples is complete, I'll probably add a couple more things to it when I publish the next version but these are the basics. You can download the archive
here. I the archive you'll find examples of nesting using 'member method' and 'declarative' syntaxes as well as the ItemDataBound method detailed in my earlier article.
Sorry, I had some downtime over the weeken - I was away for the Easter break and so was only able to restart just now. If you've sent me any mail over the last couple of days, chances are I haven't recieved it.
I was reading
SampoSofts blog when came across
this which links to
ILMerge, this is a little tool made by
MSRÂ (who are kind of the smartest guys at the smartest compnays - i.e., pretty smart!). What this does is combine multiple assemblies into one - why would you want to do that? Well, it can make deployment a bit easier for one and it lets you distribute a single exe instead of an exe and the 10 assemblies you you to provide most of the functionality (a lot cleaner)! Anyway, you can read more about it
here. Also just found a really cool little code snippet
here which lets you add this stuff to a post-build event in VS.NET. Currently using it for a little scheduled job where it makes it easier to manage versioning etc...
OK, let me start by saying that I enjoy working in C# / .NET more than I have any other language / framework in my working life. The problem is, that's just not enough.
The simple fact is that I've chosen to live and work in Scotland and this severly limits my choices so far as my career goes - there's just not that many jobs up here in .NET and even fewer at my current level - if I hear the phrase 'I'm afraid the client thinks you have too much experience' once more I may have to start killing recruitment leeches.
So, I'm at one of my turning points again, I have them every 3 years or so.
My position is, do I keep going with .NET / C# knowing that the chances are that this will limit my job prospects severly for the forseeable future or do I switch (in my own time for the present) back over to Java / J2EE or even C / C++ - for which there are a TON of well paid, fairly interesting jobs around here (lots of banks in Edinburgh - most of which just don't trust .NET yet).
Well, I have an Easter break coming up - could be decision time (I have just installed JBuilder X and it's looking pretty good!)
I've been doing some work on using MSCMS2002 and have had to look at ways to implement search (by default it doesn't have it and requires that you buy a much expensive Sharepoint license) well, I revisited the nLucene project - this had stalled for a while but looks like it's back in development. Interestingly, one of the contributors seems to be Scott W.  - so I wouldn't be surprised if this became integrated with .TEXT in the near future... Anyway, take a look, it does seem incredibly cool and it would seem to benefit from the tons of development already exisitng for the Jakarta-Lucene Java version, even stating that the Java docs also apply to this version!
UPDATE: As Ryan Rinaldi pointed out in the comments,.TEXT 0.96 does have Lucene.NET (the new name for nLucene) already integrated, I was having a poke around the code today and it's pretty sweet. I reall recommend you check it out if you need a simple to implement, quick search engine for your site! Oh, and the next version of .TEXT will have an awesome search engine!
Really exciting changes by the looks of it - not long now before we can actually use these features (well about a year). Anyway, a usual
an excellent article from
G. Andrew Duthie (or G. for short).
I was scouting around to find a solution to my current spam overload (I currently use Cloudmark's Spamnet but it only runs on a client) and I came across this I just think it's really interesting that MS is planning to address the Spam plague in such a proactive way - and at long last!
The real pain in the butt though is this:
Intelligent Message Filter, scheduled for release in 2004, will be available exclusively to customers enrolled in Software Assurance. If your Exchange servers and associated client access licenses (CALs) are enrolled in Software Assurance (SA) when Intelligent Message Filter is released, you will be eligible to receive one complimentary license for the Intelligent Messaging Filter software for each Exchange server license that you have enrolled in SA. To receive a complimentary license for Intelligent Messaging Filter, make sure that your company is eligible. Your SA benefits coordinator can verify your company’s eligibility by visiting the Microsoft Volume Licensing Services site.
Why are they doing this? It's my belief that the more Spam removal tools are used then the less profitable Spam will become...go on, make it free and make it widely available!
I posted my compression helper class before and realised almost instantly that it suffered from 'legacy lag' - so it'd been changed so much over the months that it was really bad!
Anyway, presented below is a modified version of that class (which I've also tried out my new formatting scheme on) as a reminder, it's just a simple wrapper around SharpZipLib.
using System;
using System.Text;
using System.IO;
using ICSharpCode.SharpZipLib;
Â
Â
namespace SerializableJob.Compression
{
           public enum CompressionType
           {
                       GZip,
                       BZip2,
                       Zip
           }
Â
           public class Compression
           {
                       public static CompressionType CompressionProvider = CompressionType.GZip;
Â
Â
                       private static Stream OutputStream(Stream inputStream)
                       {
                                   switch(CompressionProvider)
                                   {
                                               case CompressionType.BZip2:
                                                           return new ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream(inputStream);
                                               case CompressionType.GZip:
                                                           return new ICSharpCode.SharpZipLib.GZip.GZipOutputStream(inputStream);
                                               case CompressionType.Zip:
                                                           return new ICSharpCode.SharpZipLib.Zip.ZipOutputStream(inputStream);
                                               default:
                                                           return new ICSharpCode.SharpZipLib.GZip.GZipOutputStream(inputStream);
                                              Â
                                   }
                       }
                       private static Stream InputStream(Stream inputStream)
                       {
                                   switch(CompressionProvider)
                                   {
                                               case CompressionType.BZip2:
                                                           return new ICSharpCode.SharpZipLib.BZip2.BZip2InputStream(inputStream);
                                               case CompressionType.GZip:
                                                           return new ICSharpCode.SharpZipLib.GZip.GZipInputStream(inputStream);
                                               case CompressionType.Zip:
                                                           return new ICSharpCode.SharpZipLib.Zip.ZipInputStream(inputStream);
                                               default:
                                                           return new ICSharpCode.SharpZipLib.GZip.GZipInputStream(inputStream);                                                                     Â
                                   }
                       }
          Â
                       public static byte[] Compress(byte[] bytesToCompress)
                       {
                                   MemoryStream ms = new MemoryStream();
                                   Stream s = OutputStream(ms);
                                   s.Write(bytesToCompress,0, bytesToCompress.Length);
                                   s.Close();
                                   return ms.ToArray();
                       }
Â
                       public static string Compress(string stringToCompress)
                       {
                                   byte[] compressedData = CompressToByte(stringToCompress);
                                   string strOut = Convert.ToBase64String(compressedData);
                                   return strOut;
                       }
                       public static byte[] CompressToByte(string stringToCompress)
                       {
                                   byte[] bytData = Encoding.Unicode.GetBytes(stringToCompress);
                                   return Compress(bytData);;
                       }
Â
                       public string DeCompress(string stringToDecompress)
                       {
                                   string outString = string.Empty;
                                   if (stringToDecompress == null)
                                               {
                                                           throw new ArgumentNullException("stringToDecompress","You tried to use an empty string");
                                               }
                                   try
                                   {
                                               byte[] inArr = Convert.FromBase64String(stringToDecompress.Trim());
                                               outString = System.Text.Encoding.Unicode.GetString(DeCompress(inArr));
                                   }
                                   catch (NullReferenceException nEx)
                                   {
                                               return nEx.Message;
                                   }
                                   return outString;
                       }
Â
                       public static byte[] DeCompress(byte[] bytesToDecompress)
                       {
                                   byte[] writeData = new byte[4096];
                                   Stream s2 = InputStream(new MemoryStream(bytesToDecompress));
                                   MemoryStream outStream = new MemoryStream();
                                   while(true)
                                   {
                                               int size = s2.Read(writeData,0,writeData.Length);
                                               if(size>0)
                                               {
                                                           outStream.Write(writeData,0,size);
                                               }
                                               else
                                               {
                                                           break;
                                               }
                                   }
                                   s2.Close();
                                   byte[] outArr = outStream.ToArray();
                                   outStream.Close();
                                   return outArr;
                       }
           }
Â
}
Â
?>
I posted earlier about the really useful little encryption class by Ian Medvedev and mentioned that this could be factoryised pretty easy (well not really factoryised but you can switch the encryption provider). Anyway, here's what I can up with, pretty simple extension of the original allowing you to use whichever encryption type you want.
using System;
using System.IO;
using System.Security.Cryptography;
Â
namespace SerializableJob.Compression
{
           public enum EncryptionType
           {
                       DES,
                       RC2,
                       TripleDES,
                       Rijndael
           }
           public class Encryption
           {
                       public static EncryptionType Algorithm = EncryptionType.Rijndael;
                       private static SymmetricAlgorithm m_cAlg
                       {
                                   get
                                   {
                                               switch(Algorithm)
                                               {
                                                           case(EncryptionType.Rijndael):
                                                                       return Rijndael.Create();
                                                           case(EncryptionType.DES):
                                                                       return DES.Create();
                                                           case(EncryptionType.RC2):
                                                                       return RC2.Create();
                                                           case(EncryptionType.TripleDES):
                                                                       return TripleDES.Create();
                                                           default:
                                                                       return Rijndael.Create();
                                               }        Â
                                   }
           }
Â
                       public static byte[] Encrypt(byte[] clearData, byte[] Key, byte[] IV)
                       {
                                   // Create a MemoryStream that is going to accept the encrypted bytes
                                   MemoryStream ms = new MemoryStream();
                                   SymmetricAlgorithm alg = m_cAlg;
                                   alg.Key = Key;
                                   alg.IV = IV;
                                   CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write);
                                   cs.Write(clearData, 0, clearData.Length);
                                   cs.Close();
                                   byte[] encryptedData = ms.ToArray();
                                   return encryptedData;
                       }
Â
                       public static string Encrypt(string clearText, string Password)
                       {
                                   byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
                                   PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
                                               new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
                                   byte[] encryptedData = Encrypt(clearBytes, pdb.GetBytes(32), pdb.GetBytes(16));
                                   return Convert.ToBase64String(encryptedData);
                       }
Â
                       public static byte[] Encrypt(byte[] clearData, string Password)
                       {
                                   PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
                                               new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
                                   return Encrypt(clearData, pdb.GetBytes(32), pdb.GetBytes(16));
                       }
Â
                       public static void Encrypt(string fileIn, string fileOut, string Password)
                       {
                                   FileStream fsIn = new FileStream(fileIn, FileMode.Open, FileAccess.Read);
                                   FileStream fsOut = new FileStream(fileOut, FileMode.OpenOrCreate, FileAccess.Write);
                                   PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
                                               new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
                                   SymmetricAlgorithm alg = m_cAlg;
                                   alg.Key = pdb.GetBytes(32);
                                   alg.IV = pdb.GetBytes(16);
                                   CryptoStream cs = new CryptoStream(fsOut, alg.CreateEncryptor(), CryptoStreamMode.Write);
                                   int bufferLen = 4096;
                                   byte[] buffer = new byte[bufferLen];
                                   int bytesRead;
                                   do
                                   {
                                               bytesRead = fsIn.Read(buffer, 0, bufferLen);
                                               cs.Write(buffer, 0, bytesRead);
                                   } while(bytesRead != 0);
                                   cs.Close();
                                   fsIn.Close();   Â
                       }
Â
                      // Decrypt a byte array into a byte array using a key and an IV
                       public static byte[] Decrypt(byte[] cipherData, byte[] Key, byte[] IV)
                       {
                                   MemoryStream ms = new MemoryStream();
                                   SymmetricAlgorithm alg = m_cAlg;
                                   alg.Key = Key;
                                   alg.IV = IV;
                                   CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
                                   cs.Write(cipherData, 0, cipherData.Length);
                                   cs.Close();
                                   byte[] decryptedData = ms.ToArray();
      Â