Xerratus
Happily stressed out, since 1974


 
Tuesday, October 31, 2006

A few weeks ago, I posted a solution I came up with a way to utilize a remember me checkbox in .NET 2.0 that, when selected, pre-populated just the username in the username textbox during subsequent visits.  The problem I found was that signing out of FormsAuthentication wiped out any and all cookies I had set during or prior to logging a user in.  So, the simple act of looking at the cookie to see if the user wanted to be remembered became quite an ordeal.  My solution was to set/get the cookie using JavaScript.  This worked and I was happy.

This is a shot of the cookie collection when the user signs out and returns to the login page:



Notice that the count of the cookie collection is 0.

There are some skeptics out there though.  So, for them, I've created a very simple website solution that tries to set and get the remember me cookie as explained above.  Now, the solution DOES NOT work.  Once a user logs out, the remember me cookie is gone, along with the saved username, and there is no way to tell if the user had selected to have his username saved. 

The challenge is to modify the solution so that it DOES work.

Post updates in the comments.  When and if a solution is found and posted in the comments, I'll add to the solution and re-post so that we can finally get around this issue.

Note: The solution is NOT using the Login control on purpose.  The goal is to have the username pre-populated but still make them login.  From my limited usage of the Login control, it appears to actually keep the user logged in.  If you can get this solution to work with the Login control, I say go for it... and more kudos to you for doing so.

The winner receives bragging rights.

Download the solution: FormsAuthenticationRememberMeChallenge.zip (5.01 KB)

(the username and password to login into the form is "test"/"1111")

UPDATE: That was fast!  Adi has come up with a winning solution.  Congrats. 

Download it here: FormsAuthenticationRememberMeSolution.zip (5.55 KB)

Sunday, October 29, 2006

Saturday, October 28, 2006



Her name is Iki Bana Kamakazi
Thursday, October 26, 2006

While writing an email to a colleague today, Outlook 2003 underlined a passage and offered a correction.  The correction it offered didn't sound right but I clicked on it anyway to see if it looked better corrected.  It didn't.  But what I noticed next is that it again underlined the same passage and offered a correction, this time back to what it was originally.  Thinking it knows best (yeah, right), I clicked on it again and guess what?  It corrected back to the original passage and offered a "suggestion".

Original passage that "needed" correcting:



Corrected passage that also "needed" correcting:



The passage corrected back to the original:



And so I found the anomaly: The correction that corrected itself with a correction that needed to be corrected back to the original correction.
Wednesday, October 25, 2006

We've all been there.  We develop a web application that uses the querystring to pass data from a master list page to a detail page.  Usually just the ID is passed (just a good programming technique) and you even check and double check the value and type of data so that only the user who is supposed to see it, sees it.  But the temptation to change the id for the user is too great and nobody ever likes seeing any type of identifier in the querystring.

The solution I've developed simply encodes the querystring name/value pairs so that it is unreadable but can be retrieved and created with relative ease. 

Note: This is solution does not encrypt/decrypt the values.  Rather it uses Base64 encoding to render the string unreadable.  It is possible for somebody with knowledge to hack this but you're a good programmer... and you've solved for this, just as you did if a user simply changed the ID; right?

So back to the solution:

First, we need to create a simple class to encode and decode Base64 values. 

public sealed class Base64
{
    
public static string Encode(string data)
    {
        
try
        {
            
byte[] encData_byte = new byte[data.Length];
            encData_byte =
Encoding.UTF8.GetBytes(data);
            
string encodedData = Convert.ToBase64String(encData_byte);
            
return encodedData;
        }
        
catch(Exception e)
        {
            
throw new Exception("Error in base64Encode " + e.Message);
        }
    }

    
public static string Decode(string data)
    {
        
try
        {
            
UTF8Encoding encoder = new UTF8Encoding();
            
Decoder utf8Decode = encoder.GetDecoder();

            
byte[] todecode_byte = Convert.FromBase64String(data);
            
int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
            
char[] decoded_char = new char[charCount];
            utf8Decode.GetChars(todecode_byte,
0, todecode_byte.Length, decoded_char, 0);
            
string result = new String(decoded_char);
            
return result;
        }
        
catch(Exception e)
        {
            
throw new Exception("Error in base64Decode " + e.Message);
        }
    }
}

Next, we create a QueryString class and give it an indexer to easily retrieve the values using an ordinal.  The getter returns null if the ordinal is empty, the querystring is not found or if the ordinal does not match up with any items found.  If Request.QueryString["q"] is found, we decode the string, split the pairs, loop thru each pair splitting the name/value out, and match on the ordinal.  If a match is found, we simply return the value of the item back.

public string this[string ordinal]
{
    
get
    {
        
if(ordinal == "")
        {
            
return null;
        }

        
if(HttpContext.Current.Request.QueryString["q"] == null)
        {
            
return null;
        }

        
// decodes to name/value pairs: id=1&something=what&test=true
        string decode;
        
try
        {
            decode =
Base64.Decode(HttpContext.Current.Request.QueryString["q"]);
        }
        
catch(Exception)
        {
            
return null;
        }

        
string[] pairs = decode.Split('&');

        
foreach(string pair in pairs)
        {
            
string[] item = pair.Split('=');

            
if(item[0].ToLower() == ordinal.ToLower())
            {
                
return item[1];
            }
        }

        
return null;
    }
}

For encoding, we supply a simple encode() method.

public string EncodePairs(string data)
{
    
if(data == "")
    {
        
return "";
    }

    
return Base64.Encode(data);
}

Now, for the UI:

To retrieve the querystring items, create an instance of QueryString (I chose to make it a disposable object so I could use the using pattern), check to see if the ordinal exists.  If it does, cast it to whatever datatype your system calls for.

// Retrieve the querystring values
using(QueryString q = new QueryString())
{
    IdLabel.Text = (q[
"id"] != null) ? q["id"] : "";
    NameLabel.Text = (q[
"name"] != null) ? q["name"] : "";
    ActiveLabel.Text = (q[
"active"] != null) ? q["active"] : "";
}

To encode pairs, build up the querystring like you normally would (leaving off the starting "?") and use the encode() method to encode it.  Then, append it to whatever page you are redirecting to as q=encodedstring. 

string pairs = String.Format("id={0}&name={1}&active={2}", IdTextBox.Text, NameTextBox.Text, ActiveRadioButtonList.SelectedValue);
string encoded;

// Set the querystring values
using(QueryString q = new QueryString())
{
    encoded = q.EncodePairs(pairs);
}

Response.Redirect(
"~/Default.aspx?q=" + encoded);

This is just a quick demonstration how one can use encoding to limit tampering when passing querystring data to another page.  There are many ways to achieve this without even using a querystring but for those instances where you either have to or want to, you now have another option. 

One last note:  This can be taken one step further if encryption is needed.  Just extend the QueryString class to encrypt/decrypt rather than encode/decode.  There are risks there as well but that's for you to decide.

Download the solution: QueryStringEncoding.zip (4.13 KB)
Friday, October 20, 2006

One of the subtle differences I've found while working with web projects in Visual Studio 2005 is the Global.asax code is placed in script tags within the actual .asax page, not a codebehind file, as it was with .NET 1.1.  This article describes how to set up the Global.asax file to utilize the Global.asax.cs codebehind file.

First off, go to files->add new and select the "Global Application Class" file.  You'll notice right off the bat that the option to put the code in a separate file is grayed out.  Ignore this and click "Add".

Next, go back to files->add new and select a "Class" file.  Type in the name "Global.asax.cs" and click "Add".  Visual Studio will prompt you to add this file to the App_Code directory, select "Yes" and continue. 

Now that the files are in place, we need to do some slight manipulation of the existing code to get this solution to compile.

To start, the Global class in the Global.asax.cs file needs to implement HttpApplication.

public class Global : System.Web.HttpApplication

Next, move the code within the script tags from the Global.asax file to the Global.asax.cs file -within the Global class.

void Application_Start(object sender, EventArgs e)
{
    
// Code that runs on application startup
}

...snip...

void Session_End(object sender, EventArgs e)
{
    
// Code that runs when a session ends.
}

Once the code has been moved, remove the script tags from Global.asax:

<script runat="server">
</script>

Add the following to the Application directive at the top of the same page:

CodeBehind="Global.asax.cs" Inherits="Global"

The entire contents of the Global.asax file should look like:

<%@ Application Language="C#" CodeBehind="Global.asax.cs" Inherits="Global" %>

The solution should compile and the Global events should fire correctly as well.

Download the solution: GlobalCodeBehindWebSiteExample.zip (2.25 KB)

Wednesday, October 18, 2006

All of the ASP.NET web projects that I've ever worked on relied on some appSetting within the web.config file.  When ever the variable was needed, some code was used to grab the variable in question than modify the type as needed or used simple string comparisons.  The problem I found early on working on a small team was that every member had their own twist on grabbing and using the data from within the web.config file.  While no method was wrong, the differences in using the same variable degraded their integrity.  

My solution was to encapsulate the appSettings in a static class that returned the variables as properties of the correct type.  This encapsulation also isolated the place where all appSettings were obtained making changes much easier while, at the same time, normalizing their usage.  It takes a few minutes longer of up front work when adding new settings but the ease of usage diminishes that ten-fold.  

Another plus is that a missing setting won't throw an error since we check for it's existence before we actually try and cast the value.  In my experience, not all developers check first, they assume it'll be there -bad idea.  

Note: The below example is utilizing .NET 2.0 but the same results can be obtained using 1.1 by simply changing ConfigurationManager.AppSettings[""] to ConfigurationSettings.AppSettings[""].

First off, here are a few differnet appSettings that have varying usages and types:

<add key="PromoExpiration" value="11/1/2006"/>
<
add key="IntroText" value="This is some random text ..."/>
<
add key="DisplayExtra" value="true"/>
<
add key="LoopCount" value="16"/>

Next I created a class called ConfigController where the getters for the above settings are obtained.  Here are two examples; the first demonstrates a bool while the second shows an int data type:

public static bool DisplayExtra
{
    
get
    {
        
if(ConfigurationManager.AppSettings["DisplayExtra"] != null)
        {
            
return bool.Parse(ConfigurationManager.AppSettings["DisplayExtra"]);
        }
        
else
        {
            
return false;
        }
    }
}

public static int LoopCount
{
    
get
    {
        
if(ConfigurationManager.AppSettings["LoopCount"] != null)
        {
            
return int.Parse(ConfigurationManager.AppSettings["LoopCount"]);
        }
        
else
        {
            
return -1;
        }
    }
}

To further ensure that no errors are thrown, a try catch block can be used when casting the data.  In my opinion it's overkill but when you work on a project where the client can and does edit the web.config file outside of your control, exception handling might be in order.

if(ConfigurationManager.AppSettings["PromoExpiration"] != null)
{
    
try
    {
        
return DateTime.Parse(ConfigurationManager.AppSettings["PromoExpiration"]);
    }
    
catch(Exception)
    {
        
return DateTime.MinValue;
    }
}
else
{
    
return DateTime.MinValue;
}

Once the controller is in place, it's usage is as simple as:

PromoPanel.Visible = (DateTime.Now < ConfigController.PromoExpiration);

IntroLabel.Text =
ConfigController.IntroText;

ExtraPanel.Visible =
ConfigController.DisplayExtra;

for(int i = 0; i < ConfigController.LoopCount; i++)
{
    
Literal l = new Literal();
    l.Text =
String.Format("Count: {0}<br />", i);

    LoopPlaceHolder.Controls.Add(l);
}

In summary, keep access to the web.config settings in one place and return the resulting values using their respective types to ensure proper usage throughout your solution.

Download the solution: ConfigControllerWebSiteExample.zip (5.3 KB)
Monday, October 16, 2006

While installing Microsoft SQL Server Management Studio Express I was left with the puzzling dilemma below:

Am I OK with what is about to happen?  I'm not sure, but I don't really have a choice now do I.


A new service by Hidden Network, that I've noted in a prior article Want a new way to find a job... read my blog, has just ended it's Beta testing.  Over the weekend, I found out that my blog was one of the chosen to use the new service to display job postings (see the right hand side of this page under the heading "Job Postings"). 

From what I've heard, employers are signing up, posting ads, and liking the resulting applicants even from these early stages. 

For my avid readers

Continually check the listings posted under the "Job Postings" heading for new opportunities or browse for more jobs.  Even if you are not actively looking, better opportunities may be just around the corner. 

For employers interested in posting ads

Start posting jobs today.

For bloggers interested in using the service

I encourage you to create an account and try the service out.  For those who don't want to jump right in, check back for a review of Hidden Network and my opinion of the service to date.

Tuesday, October 10, 2006

This morning I downloaded IE7 RC1 from Microsoft.  It's apparently coming out soon and I'd like to check out the sites that I work on to make sure all of the formatting looks and acts like it should (I've only found one minor thing so far).

Upon opening it, I found out right away that I did not like the new font-enhancement (ClearType).  Ironically enough, I do use an LCD screen here at work and at home but I've just never liked ClearType.  To me and my eyes, it appears fuzzy almost blurry.  This to me seems to cause eye strain rather than help it.  But this is just me... I know a lot of people who love it and I'm not knocking it.

Without ClearType:

With ClearType:

So you can imagine my reaction when I first opened IE7 to see everything in ClearType.  Wanting to check out all of the new features and check out my sites with the new browser, I didn't try to disable ClearType right away.  So about 10 minutes later (I went fast) I set out to turn it off. 

My first inclination was to go to "Tools" then fonts but it wasn't there and rightfully so; ClearType is a font-enhancement not an actual font (from what I've read).  Next was to go to the "Advanced Settings" from within "Internet Options".  There simply, about half way down under "Multimedia" was the option "Always use ClearType for HTML".  Unchecking that option then restarting IE7 brought back the font I know and love.


Advanced Settings:

UPDATE: As noted by some readers; before turning ClearType off try and fine tune it first.  There is a web version that works quite well or you can download an XP PowerToy to do the same.

Monday, October 09, 2006

The first rule of the Men's Room is, you do not talk in the Men's Room.

The second rule of the Men's Room is, you DO NOT talk in the Men's Room.

Third rule of the Men's Room, someone says "hi" or tries to talk to you, the bathroom break is over.

Fourth rule, only two guys at or near the urinals.

Fifth rule, one person taking a shit at a time, fellas.

Sixth rule, no sitting down to pee.

Seventh rule, standing at the urinal acting like your peeing to avoid walking out with somebody else will go on as long as it has to.

And the eighth and final rule, if this is your first time in the Men's Room, you have to use the urinal.

 

"I'm half asleep again; I must've left a floater in the toilet." - Narrator

Friday, October 06, 2006

Although I like Live Writer and I've been using it lately, I have issues with some of its functionality. 

Currently in Beta, Live Writer (review from techcrunch) enables blogger's such as myself to easily add/edit/delete entries on one or multiple blogs on many platforms from one central location.  With that said and knowing it's still a Beta release, most of my qualms with it below may or may not be fixed (enhanced) in the final release.

These issues include:

  • When uploading images (.jpgs doesn't seem to be an issue with .gifs - haven't tried .pngs) Live Writer takes my original image and reprocesses it and runs some type of filter on it - why I do not know - leaving behind a grainer, blurrier version of the original. 

Original image:

Image enhanced by Live Writer:

I don't care why it does it, just give me the option to skip it if I don't want it. 

  • Pasting does not preserve certain color formatting.  Now this one is a double edge sword.  Nobody likes it when Word "styles" pasted text into a document.  All of the <font> tags and CSS styles are bloated and it NEVER seems to get it right.  Recently I discovered a macro for Visual Studio.NET that allows me to copy code keeping the original color formatting even using simple styles to do so.  The nice thing about it is that it gives me two options; copy as html or copy as a style.  The former is self descriptive, the latter is nicer in that you can paste the text into a notepad and it has NO html but paste it into a ANY rich textbox editor and the style is there.  My problem is that the Windows Live Writer rich text editor is the ONLY one I've found that does NOT paste the style properly.  I can still do it however if I select to copy as HTML, switch to HTML view then paste but I'd rather not have to do it that convoluted way.
  • There is a lovely dropdown from which I can select one or many categories for the current entry but there is no way to add a new category.
  • While posting yesterday I noticed a fatal error that kept popping up when I actually published a post but it didn't crash the program and went away when I closed the program later and reopened it.  Unfortunately I didn't take a screen shot of it but if I run into it again I will update this post with it.

That's about it.  The pros way out number the cons on this one.  If you post from work and home, try using folder share and syncing your "My Weblog Posts" folder in "My Documents".  Any posts you draft at home will be available for you at for when you get to work and vice-versa.

Thursday, October 05, 2006

Well to be fair, it's not just my blog it's mine and other blogs thanks to the new service hiddennetwork.com.   

 

Basically, Hidden Network - currently in beta (from the maker of The Daily WTF, which I am an avid reader) will display job ad's solely on blogs (tech blogs for now I believe).  Paying per 1000 impressions plus a per successful referrer bonus, makes this service inviting. 

Personally, I don't look for a new job except when I have to.  By doing this though, opportunities that may be better than my current situation might just pass me by.  But if I could see job opportunities from respective employers throughout the day while reading other tech blogs I might be presented with an opportunity that I might not have seen otherwise.  Plus, I would stay on top of job trends, something I could only do when actively looking for a new position.

I must say, I'm anxious to see where this service goes and doubly anxious to get on their blogger network.

Wednesday, October 04, 2006

Bernadette Baker (shown on right; affectionately known as Bernie), literary agent, small business owner and friend made the local paper in an article titled Bound to books.  Here's a quick excerpt:

“I love Portland,” she says. “For our business it’s a really great place for us to be starting. If we were to go to New York right now, as a business, we would not only have to transplant our whole lives, but we would be competing in an environment that is already really competitive. In Portland we have an edge because there are a lot of creators here but not a lot of industry here. The publishers here are more niche, and it’s a small community.”

Baker believes that Portland and the surrounding area, full of talented, creative writers, is a natural place to develop more of a publishing industry.

Congrats Bernie.

Be sure to check out her site; www.bakersmark.com.


The other day I tried to add a simple "Remember me" checkbox to the login.aspx page for a site I'm working on.  Simple enough in theory that I didn't think much of it and gave myself an hour to add it in. 

Here's what I needed it to do:

  • Pre-populate the txtUserName textbox of the last user IF they checked the "Remember me" checkbox.
  • Remember the state of the "Remember me" checkbox so that the user doesn't have to check it each time they log in (or uncheck it).

Sounds simple enough right?  Just add a cookie and check it when login.aspx loads, right?  Wrong.

The problem became clear very early on; the cookies were being cleared when the user logged out.  Since my goal was to access the cookie BEFORE the user logged in, I could not rely on the cookie.  But I HAD to use a cookie, there was no way around it. 

So, after some searching and trial-and-errors, I came up with a simple solution: use JavaScript cookies.  Now it sounds like a bit of a hack but it's not really.  JavaScript has been able to read and write to cookies from the get go. 

So first we need to write some simple script that will read/write to cookies:

function CreateCookie(name, value, days)
{
    
if(days)
    {
        
var date = new Date();
        date.setTime(date.getTime() + (days*
24*60*60*1000));
        
var expires = "; expires=" + date.toGMTString();
    }
    
else var expires = "";
    
    document.cookie = name +
"=" + value + expires + "; path=/";
    
}

function ReadCookie(name)
{
    
var nameEQ = name + "=";
    
var ca = document.cookie.split(';');
    
for(var i = 0; i < ca.length; i++)
    {
        
var c = ca[i];
        
while (c.charAt(0)==' ') c = c.substring(1, c.length);
        
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
    }
    
    
return null;
}

function EraseCookie(name)
{
    CreateCookie(name,
"", -1);
}

Next, we create 2 new custom methods; one to read the cookie when the page loads and the other to write/remove the cookie when the checkbox is checked:

function CheckRememberMe()
{
    
if(ReadCookie("rememberMe") != null)
    {
        document.getElementById(
"txtUserName").value = ReadCookie("rememberMe");
        document.getElementById(
"RememberMe").checked = true;
        document.getElementById(
"txtPassword").focus();
    }
}

function ToggleRememberMe(checked)
{
    
if(checked)
    {
        CreateCookie(
"rememberMe", document.getElementById("txtUserName").value, 30);
    }
    
else
    {
        EraseCookie(
"rememberMe");
    }
}

Now, all that is left is to add an onload event to the body tag and an onclick event to the checkbox:

<body onload="CheckRememberMe();">

(note; since the checkbox value is not used anywhere but the client, I chose not to use a .NET server control)

<input type="checkbox" name="RememberMe" id="RememberMe" onclick="ToggleRememberMe(this.checked);" /><label for="RememberMe">Remember me on this computer</label>

Viola, you're done.  Simple, effective and it can be used by multiple browsers.

Tuesday, October 03, 2006

This is a quick test post using Windows Live Writer Beta

The blog engine I use (dasBlog 1.9) supports the Live Writer API and I'm liking the interface mainly due to the fact that it looks like I'm composing an email or normal document rather than posting to my blog.  I say this because more times than not, I post during work hours.

Another option I have since I use dasBlog, is the "mail to weblog" posting feature.  This feature allows me to post by simply sending an email to a preset email address that the blog engine monitors and posts when it receives it.  As much as I love this feature, the formatting is a bit off when I use Outlook.  If I had a phone with easy access to email, I would post quick features while on the road.  But for everyday posting its just not robust enough.

Which bring me back to Live Writer.  Along with the slick UI, there is the ability to save drafts and spell checking.  Long gone are the days when I type up a post, copy it into Word just to check my spelling. 

UPDATE: Two thumbs up... way up for this little item.  Not only did it keep the formatting exactly like I entered it but it also uploaded the image above for me.  I wasn't expecting that at all.  When I put it in I thought to myself "oh great, I'll have to upload the image manually".  It's that little touch that makes everything grand.


That's it! 

I've tried to keep the ad's down because I didn't want them to become to intrusive but the small ad at the top was just NOT cutting it.  Since I switched a few months back, my ad revenue dropped dramatically.  Now, after reading a top 10 ten list of google whores I'm changing my strategy -ad's out-the-ass!

Enjoy.
Monday, October 02, 2006

Recently I created my own custom macro object for dasblog 1.9 but ran into a slight problem; it acted like the dll I created wasn't there.  Following this article (Creating custom macros for dasBlog) to a "T" still faired no better.  Not wanting to spend too much time on this and thinking that I was doing something wrong, I emailed Scott Hansleman (one of the main contributers to dasBlog) to see if he could spot my problem quickly.  Scott was great and we corresponded for most of the day trying different things to try and solve it.  He took a special interest in this because he said that this was the second inquiry in the same week about this error.

2006-09-29 14:00:18 PM
1
Error:
Error executing Macro: System.ArgumentNullException: Value cannot be null. Parameter name: type at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) at newtelligence.DasBlog.Web.Core.MacrosFactory.CreateCustomMacrosInstance(SharedBasePage page, Entry item, String name) at newtelligence.DasBlog.Web.Core.TemplateProcessor.ProcessTemplate(SharedBasePage page, Entry entry, String templateString, Control contentPlaceHolder, Macros macros)
while processing .

2006-09-29 14:00:18 PM
1
Error:
Error executing macro: Test("hello", 1)|Extras. Make sure it you're calling it in your BlogTemplate with paratheses like 'myMacro()'. Macros with parameter lists and overloads must be called in this way. Exception: System.MissingMemberException: Member newtelligence.DasBlog.Web.Core.Macros.Test not found. at newtelligence.DasBlog.Web.Core.TemplateProcessor.InvokeMacro(Object obj, String expression) at newtelligence.DasBlog.Web.Core.TemplateProcessor.ProcessTemplate(SharedBasePage page, Entry entry, String templateString, Control contentPlaceHolder, Macros macros)
while processing .

From the looks of everything, it seemed that dasBlog could not find my custom class.  But why?  I made sure the changes in the web.config were correct because I thought for sure that was where the problem was.

Scott was able to duplicate the error once, then realized that he forgot to put his macro dll into the bin folder.  Emailing me again, he asked - as nicely as possible I might add - if I had forgot to put the dll in the bin directory.  Nope, I replied and even sent a screen shot of the servers bin directory.  To top it off, I sent him my solution to see if he could find anything wrong with my code or references.

While he was working away on solving this (thinking that there was something wrong with the macro factory code) I switched gears to see if building the macro using .NET framework 1.1 had anything to do with it.  I say this because the article on how to create custom dasBlog macros was using the .NET framework 2.0 so I did the same; why not, if the article did it in 2.0 why couldn't I?

Well the 1.1 solution worked!  Just then, I got another email from Scott asking if I was running dasBlog under 2.0 or not.  You see, creating macros under the 2.0 framework NEEDS dasBlog to be running under the 2.0 framework as well... DUH (as I smack myself in the forehead).

The problem all along was not with my code, not with the blog engine code but rather with the fact that I was trying to run a macro intended for .NET 2.0 under the 1.1 framework.

2 solutions presented themselves: A) Switch dasBlog to run under 2.0 or B) create the macro under 1.1.  Why is B even an option?  Because it is backward compatible with 2.0.  That's right, the 1.1 macro has more flexibility if I want to distribute this dll to others who, for one reason or another, are still running dasBlog under the 1.1 framework.

In summary, if you are trying to create a custom dasBlog macro and run into a problem, check to see that your website is running under the same .NET framework version as your solution (or lower).

A big thanks to Scott Hanselman for taking his time to help me with solve this dilema.

Sunday, October 01, 2006