Sunday, January 30, 2005

All my life I've been something of a boardgame nut...probably always will be.  Recently, I discovered a new boardgame that I very much enjoy and like to show to people.  It's called Carcassonne.  This game is a tile-based game in which players take turns strategically placing tiles on the table, ultimately creating a large map of cities, roads, and farmlands.  The game is fantastically addictive.  The game, not including its various expansions contains 72 tiles.  I had some spare cycles today and wondered if I could place all 72 tiles together to form a square board, and have all tiles legally placed.

As it turns out, this was easier that I thought it might be, only taking about 10-15 minutes.  One primary goal was to set the board up such that it was completely contained; that is, set up such that no cities and roads led off of the board.  Well, the result wasn't quite what I was aiming for, but I'll probably give it another try in the coming days (hrs).  Please forgive the blurriness of some of the tiles - I took the photograph at an angle so as to minimize the flash's glare and then photoshopped it with a perspective distortion and a stretch.

Update January 31st, 2005:
Here's an updated one that took a little more time.  As you can see, all of the roads and cities are completely self-contained on the board with the exception of the lower left corner.  Oh, well, it was fun while it lasted.

Sunday, January 30, 2005 5:32:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, January 28, 2005

They say practice makes perfect, and this is no exception to the rule.  You just never know what you'll find the Microsoft .NET SDK Documentation.  This is a best practice of which I've definitely grown fondle:

 

Does anyone have any best practice recommendations for 'handling' exceptions?

Friday, January 28, 2005 12:37:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Well, I finally had a free moment and I just got back in town the other night so I thought a take a moment and do some blogging.  It's been a while since I posted regarding my custom blog rating control; I've been meaning to get this up for download for some time but could never manage to - until now, not to mention that I've gotten quite a few requests to get it :).

Bear in mind, this is NOT the definitive, final release.  It is, however, enough to get started and have as a functional rating system.  Below, I've provided a bit of documentation to help you get it up and running on your site.  Please feel free to contact me if you have any questions.

The first thing you'll need to do is to run a database script against your blog database.  This script, found in the file 'DbScript.sql' does not do anything to alter existing schema.  All it does is adds a table (blog_DevstoneRating), a few store procedures (blog_DevstoneRateItem, blog_DevstoneGetItemRating, and blog_DevstoneGetTopRatedItems), and a function (blog_fnDevstoneGetPostUrl).  Be sure to change the database name to the appropriate name before running the script.  Oh, and backup your database.

The main rating control is called RatingSummary.  There is also another control that I haven't yet packaged because it's not quite finished that is called TopRatedPosts.  It is functional, but not yet friendly to all skins - I'll get it up as soon as I can.  Additionally, there is an HttpHandler and an HttpHandlerFactory class.  These provide integration into the .Text blog website.

The RatingSummary supports being embedded on a variety of pages within your blog (so that users can rate a blog post, a comment, etc).  One of the chief design tenets was that I wanted to be able to place the control on the main page along side each post, thereby providing the user a quick way to enter comments and rate the post.  Note: If a user rates a post and doesn't enter any comments it simply updates the post's rating.  However, if the user provided comments, not only is the post's rating is updated, but the user's comment is added to the list of posts for the site so it appears as a regular comment on the site.

The following examples identify a few of the changes you can make to incorporate the rating control on your site.  You will need to add the following page directive to the top of each control in which you intend to use the control:

<%@ Register tagPrefix="devstone" namespace="Devstone.Web.Blog.Controls" assembly="Devstone.Web.Blog.Controls.Rating" %>

The simple RatingSummary declaration resembles the following:

<devstone:ratingsummary runat=server visible=true />

The RatingSummary control offers a variety of properties that you can set to ensure proper behavior whereever posted.

ShowSummary (bool property):  Defaults to true.  Determines the presence of a descriptive text beneath the graphical rating, explaining the rating.

RatingBarType (RatingBarType property):  Defaults to RatingBarType.Star.  Determines the appearance of the rating control.  Valid values include Star, Dot, and Bar.

ShowRatingLink (bool property):  Defaults to true.  Determines if the link allowing users to rate the post is to be shown.

PostId (int property):  Defaults to -2 (autodetermine).  If you explicitly place the post id on the control, the user will be guided to rate a particular post.  If left as autodetermine (-2), the RatingSummary control attempt to read the post id from the url.  If it cannot, it returns -1 (invalid).

PostLink (string property):  The url to the post being rated.

PostType (PostType property):  Defaults to PostType.BlogPost.  The value of this property determines the text displayed to the user describing what they are rating.

Alignment (HorizontalAlign property):  Defaults to HorizontalAlign.Left.  Determines the alignment of the control.

Rated (bool readonly property):  Returns whether the particular post has been rated by the user.

Now, in order to get the control to work properly, you must make a few changes to the web.config file.  Within the <HandlerConfiguration/HttpHandlers /> node, add the following patterns (NOTE: see the previous post for further details on how to set these up properly if you have a multiple-blog site vs a single-blog site.  These tags are for a multiple-blog site):

   <HttpHandler pattern="^(?:/(\w|\s|\.)+/img/\d\.\d{2}/(?:Star|Dot|Bar)\.dspx)$" type="Devstone.Web.Blog.Controls.RatingHandlerFactory, Devstone.Web.Blog.Controls.Rating" handlerType="Factory" />
   <HttpHandler pattern="^(?:/(\w|\s|\.)+/rate/(?:Star|Dot|Bar)/[12345]/\d+\.dspx)$" type="Devstone.Web.Blog.Controls.RatingHandlerFactory, Devstone.Web.Blog.Controls.Rating" handlerType="Factory" />

Then add the following to the <appSettings /> section, substituting the proper values:

<!-- Devstone Settings -->
<add key="Devstone.DbConnectionString" value="..." />
<add key="Devstone.SendEmail" value="true" />
<add key="Devstone.SmtpServer" value="..." />
<add key="Devstone.Email" value="...
" />
<add key="Devstone.EmailSender" value="...
" />
<add key="Devstone.EmailSubjectHeader" value="Blog Rating" />

The following are examples as they might appear to enable a user to rate various post types:

Comments.ascx:

<devstone:ratingsummary runat=server alignment=right postType="Comment" postId="<%#((Dottext.Framework.Components.Entry)Container.DataItem).EntryID %>" visible=true />

Day.ascx:

<devstone:ratingsummary runat=server alignment=right postId="<%# ((Entry)Container.DataItem).EntryID %>" postLink="<%# ((Entry)Container.DataItem).Link %>" visible=true />

Download: RatingControl.zip

For more information, please see the previous posts:

Part I:  From Vague Concept to Less-Vague Concept
Part II:  Integrated with .Text

Have fun!

Friday, January 28, 2005 5:13:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, January 26, 2005
As others have noted, Megan Davis offers a great guide to running a utility called sysprep on virtual machines.  If you use Virtual Machines like I do (which is for just about everything), you'll not want to miss this!
Wednesday, January 26, 2005 3:31:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, January 23, 2005

I've often marvalled at this, but never really considered it or given it much thought.  As you may be aware, if you open up Sql Server's Enterprise Manager, connect to a remote database server and select 'New Database' it will allow you to designate the target location for the database (.mdf) and log (.ldf) files.  It displays a dialog box containing the drives and folders on the remote computer as though you were browsing the computer locally.

It does this even if you have no user access rights on the remote computer - Windows authentication is not required.  How does it do it?  I used to think it used some internal Sql Server magic.  Later I wondered if it might use WMI, but WMI would require you to authenticate to the remote machine to browse its directory structure.  You don't get a Windows token by logging in to a Sql Server as 'sa' ;)  Again, I didn't really consider it or give it much thought.

Well, as it turns out Sql Server has several extended stored procedures nestled neatly in the master database that the dialog uses to return a directory tree:  xp_availablemedia, xp_dirtree, et al.  The dialog is custom tailored to interpret the responses from these stored procedures and render a nice tree-view to the user.  Simply open a copy of Sql Profiler and monitor the SQL:BatchCompleted and you'll see all the calls to xp_dirtree.  This could be pretty helpful if you ever create a custom utility to creates databases on a remote computer without requiring the use of the Enterprise Manager.

I went through the trouble a while back to create one that utilized WMI to perform the same operation, but this would have been a heck of a lot easier and straightforward...I think I'm going to go back and retool a new one to use these instead.

Sunday, January 23, 2005 6:00:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, January 21, 2005

On the last post, I had introduced the concept of creating an IDE in which types and their instances are generated dynamically.  For a full discussion on the rationale behind the application is in the previous post, along with how properties were designed and organized.  This follow-up discussion, however, is focused on taking the semi-abstract notion of what a property is and converting that into a real type at runtime and its associated instances.

Each of the dynamically created types within the system is similar to other, related types.  For this reason, it was a good idea to define a base class.  This enables us to create a collection or array that is strongly typed to contain instances of each of the disparate types.  I decided to create this type manually in the assembly, vs. creating it dynamically so that I could utilize the strong typing within my code.  I called this base type PropertySetBase.  For consistency purposes (as well as some other more motivating reasons that I'll discuss in another article), it was decided that this base class contain no properties except for a 'Name' property.  Now, I had a special case here in which the names were predefined and not assigned within the source .ascx file.  Were that not the case, I would not even consider having the Name property there...the base class would be nothing but a blank, abstract class.  My class resembles:

public abstract class PropertySetBase {
   private string _name;

   public PropertySetBase(string name) {
      _name = name;
   }

   [ParenthesizePropertyName(true)]
   [Description(“The control identifier.  This property is readonly.“)]
   public string Name {
      get { return _name; }
   }
}

At this point, it now became necessary to take the IToolPropertyDefn instances and convert them into actual, runtime classes.  One of the most powerful, yet perhaps under-utilized aspects of the .NET framework is the ability the runtime has to generate types dynamically via the classes contained within the System.Reflection.Emit namespaces.  Probably because doing so requires knowledge of Intermediate Language (IL).

In order to generate the classes at runtime, I created a builder class.  Recall that all of the properties for a given dynamic type are defined within the ToolPropertyDefns class as flyweight objects.  Therefore, my builder could, given a tool id, resolve to the set of properties pertaining to the type and (if it's not yet created) generate the type, create an instance, and return it.  Once the type is defined, the definition is cached in a Hashtable for fast access later on, when another instance of the same type is requested.  A snippet:

internal sealed class PropertySetBuilder {
   private static Hashtable _types = new Hashtable();

   internal static PropertySetBase Build(Tools toolId) {
     
// establish the property definitions array
      IToolPropertyDefn[] props = ToolPropertyDefns.GetDefn(toolId);

     
// check to see if the type has been defined previously, if not create it
      Type type = _types[toolId] as Type;
      if ( null == type ) {
         // ...logic here to create the type
      }
   }
}

Now, in order to create definitions for these types dynamically we use various classes within the System.Reflection.Emit namespace such as AssemblyBuilder, ModuleBuilder, TypeBuilder, et al.  This functionality I decided to isolate into some private helper methods, additionally, I had to define the instances privately in the PropertySetBuilder class.

private AssemblyBuilder _asmBuilder;
private ModuleBuilder _modBuilder;

private static AssemblyBuilder getAsmBuilder() {
   if ( null == _asmBuilder ) {
      AppDomain domain = Thread.GetDomain();
      AssemblyName asmName = new AssemblyName();
      asmName.Name = “DynTypes“;
      _asmBuilder = domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
   }
   return _asmBuilder;
}

private static ModuleBuilder getModBuilder() {
   if ( null == _modBuilder ) {
      AssemblyBuilder asmBuilder = getAsmBuilder();
      _modBuilder = asmBuilder.DefineDynamicModule(“DynTypeModule“);
   }
   return _modBuilder;
}

private static TypeBuilder getTypeBuilder(string name) {
   ModuleBuilder modBuilder = getModBuilder();
   return modBuilder.DefineType(name + “PropertySet“, TypeAttributes.Class | TypeAttributes.Public, typeof(PropertySetBase));
}

These methods will create a new AppDomain, with a dynamically generated assembly, with a dynamic module into which the types will be defined.  The assembly is given permission enough to run but cannot be persisted to disc.  Additionally, the TypeBuilder defines that the types it creates will be public classes that derive from PropertySetBase.

Once this framework is established, we can go through the motions of taking our IToolPropertyDefn instances and converting them into actual, runtime properties.  Therefore, let's take our first code example above and flesh-out the if {...} block.

if ( null == type ) {
   TypeBuilder tb = getTypeBuilder(toolId.ToString());
   createCtor(tb);

   if ( null != props && props.Length > 0 ) {
      foreach ( IToolPropertyDefn defn in props ) {
         addProperty(tb, defn);
      }
   }
   type = tb.CreateType();

   // cache off the newly created type
   _types[toolId] = type;
}

The following procedures establish how to create the class constructor (so instances can be created) as well as the property/method implementation:

private static Type[] _ctorParamsString = new Type[] { typeof(string) };

private static void createCtor(TypeBuilder tb) {
   ConstructorInfo baseCtor = (typeof(PropertySetBase)).GetConstructor(_ctorParamsString);
   ConstructorBuilder ctor = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, _ctorParamsString);
   ILGenerator il = ctor.GetILGenerator();
   il.Emit(OpCodes.Ldarg_0);         // push the 'this' pointer
   il.Emit(OpCodes.Ldarg_1);         // push the string param
   il.Emit(OpCodes.Call, baseCtor);  // call the base ctor
   il.Emit(OpCodes.Ret);             // return - if omitted we get an InvalidProgramException
}

private static void addProperty(TypeBuilder tb, IToolPropertyDefn defn) {
   FieldBuilder fb = tb.DefineField(defn.PrivateName, defn.DataType, FieldAttributes.Private);
   PropertyBuilder pb = tb.DefineProperty(defn.Name, PropertyAttributes.HasDefault, defn.DataType, Type.EmptyTypes);

   // establish the description attribute
   ConstructorInfo descCi = typeof(DescriptionAttribute).GetConstructor(_ctorParamsString);
   CustomAttributeBuilder descCab = new CustomAttributeBuilder(descCi, new object[] { defn.Description });
   pb.SetCustomAttribute(descCab);

   // establish the default value attribute
   ConstructorInfo defCi = typeof(DefaultValueAttribute).GetConstructor(new Type[] { defn.DataType });
   CustomAttributeBuilder defCab = new CustomAttributeBuilder(defCi, new object[] { defn.DefaultValue });
   pb.SetCustomAttribute(defCab);

   // define the getter and setter methods
   ILGenerator il;
   if ( ( defn.Mode & PropertyMode.Read ) > 0 ) {
      MethodBuilder getter = tb.DefineMethod(“get“ + defn.Name, MethodAttributes.Public, defn.DataType, Type.EmptyTypes);
      il = getter.GetILGenerator();
      il.Emit(OpCodes.Ldarg_0);
      il.Emit(OpCodes.Ldfld, fb);  // load the private field into the return value
      il.Emit(OpCodes.Ret);
      pb.SetGetMethod(getter);
   }

   if ( ( defn.Mode & PropertyMode.Write ) > 0 ) {
      MethodBuilder setter = tb.DefineMethod(“set“ + defn.Name, MethodAttributes.Public, null, new Type[] { defn.DataType });
      il = setter.GetILGenerator();
      il.Emit(OpCodes.Ldarg_0);
      il.Emit(OpCodes.Ldarg_1);
      il.Emit(OpCodes.Stfld, fb);  // assign the string to the private field
      il.Emit(OpCodes.Ret);
      pb.SetSetMethod(setter);
   }
}

That's about all there is to it - at least for a really simple property with an underlying field.  Data gets assigned to and read from the underlying field.  The last remaining step is to create the instance from the type and return it from the Build() method created above.  The following code takes the Type as defined, calls the constructor on it, and returns the instance:

internal static PropertySetBase Build(Tools toolId) {
  
// ... code to create the type as described above
  
   ConstructorInfo ci = type.GetConstructor(_ctorParamsString);
   PropertySetBase ret = ci.Invoke(new object[] { ToolHelper.GetToolName(toolId) }) as PropertySetBase;

   // iterate through the properties and assign the default values
   // note, we cannot necessarily assign the value via the property because not all properties allow
   // writing (e.g. they are readonly).  therefore, reflect to the underlying field we created
   // and assign the value directly to it.
   if ( null != props && props.Length > 0 ) {
      foreach ( IToolPropertyDefn defn in props ) {
         FieldInfo fi = type.GetField(defn.PrivateName, BindingFlags.NonPublic | BindingFlags.Instance);
         fi.SetValue(ret, defn.DefaultValue);
      }
   }

   return ret;

}

As you can see, it's pretty easy and straightforward.  With this object suite and structure, I'm not working with an extremely diverse range of objects, but it's working remarkably well.  In the next discussion, we'll talk about how to programmatically assign values to the properties and how to reverse engineer the instances into their ASP.NET code form reliably.

Friday, January 21, 2005 9:39:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, January 20, 2005

Words that should be in the dictionary pretty soon.

splab ('splab)
adj. splab·ber; splab·best

1slang
   a: of or related to a high degree of excellence
   b: very good, fashionable
synonyms:  cool, excellent, fashionable
example: The app was definitely splab.

 

whap ('hwäp, 'wäp)
v. whapped; whap·ping

1: to assemble
2: to create, specifically in the realm of software
3: alt: whap-out: to complete
synonyms: code, develop, write
exampleWe whapped-out that app.

These new words can be combined to form from pretty elaborate sentences that will undoubtedly enhance the developer's vocabulary:

Let's whap a splab app, chap.

Thursday, January 20, 2005 6:03:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Wednesday, January 19, 2005

[Fixed spelling error 02-15-2005]

I whole heartedly agree with Jeff Atwood's post.  Therein, while quoting Rico Mariani, he talks about a developer's tendency to use OOP features that are not needed nor warranted.  Oftimes while refactoring code (mine and others'), the authors utilized language constructs (such as delegates, virtual methods, elaborate object hierarchies, etc) when the code could be simplified and made much more maintainable.

The quote that stuck in my mind more particularly was “As developers, I think we also tend to be far too optimistic in assessing the generality of our own solutions, and thus we end up building elaborate OOP frameworks around things that may not justify that level of complexity.”  How true it is!  Almost every developer I know has this tendency.  The vast majority of the time, however, the simpler, more direct approach is the best one.  “Don't spend a lot time planning for grandiose, unknown future scenarios.  Good software can evolve into what it will ultimately become.”

Amen.

Wednesday, January 19, 2005 11:59:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

One of the many things of late that has kept me from being as active on my blog as I would like to be is the looming pressure of a deadline.  We're building momentum towards releasing our application and there are quite a few loose ends that need addressing.  One of these is just about knocked out of the park - and it's one of the more difficult utility applications.

Prior to starting to work on it, I had never developed and IDE and as such, have had to delve into many obscure areas of .NET and application design that most developers shun and usually don't go.

Our application that we're writing is web-based.  It utilizes templated html in the form of controls (.ascx as well as server controls).  These User Controls (the .ascx variety) are designed to be edited and tweaked by end users (non-programmers/developers) and without the assistance of a tool such as Visual Studio.  We have, therefore, decided to create an IDE tailored towards targetting these users.

Without going into the details of the design of the application, we concluded that the best environment for the non-technical users to work would be a tool of our own creation that masked much of the complexity of .ascx controls (that is, directive tags and control tags) while providing full control fidelity and power.  A control within the .ascx might resemble <asp:literal id=litHeaderCaption ... /> but that would be too ugly (and perhaps intimidating) to display to an end user.  Instead we wanted to display [HEADERCAPTION] that acted as a cohesive unit within the editor.  That is, when a user positioned the insertion point within the tag (via keyboard or mouse), the entire tag would become selected and a set of properties would appear allowing it to be customized similar to how Visual Studio might work.  These controls would also be draggable from a toolbox (a la Visual Studio) onto the editor.

This discussion isn't focused on the richtext color syntax highlighting, the parsing of text to yield the [...] tags, nor the dragging of tools, though each of those is cool and might warrant a complete discussion (let me know if you're interested).  Instead, herein I'm going to talk about another aspect of the application that I thought was pretty incredible.

When dealing with a text string that contains a tag [HEADERCAPTION] how do you assign values to properties for an object that doesn't exist?  When the user selects the 'control' I need to render in a PropertyGrid control the public properties and their values.  Well initially, the control instance doesn't exist at all, that is, nothing is really hosting a control instance - you simply have a string.  Therefore, I had to, upon parsing out the controls, resolve which tags would be represented in the text, parse out the properties present in the <asp:... /> tag and somehow get these values into an instance of the control.  Well, this is a completely separate application from the actual product that performs the rendering of the controls in the web-world.  I need to define a class for each child constituent of my parent user control.

I decided pretty early on that I did not want to create a suite of classes representing each and every control type.  Sure this would have been a snap, and the object hierarchy is extremely straightforward, but I didn't want to have to deal with the maintenance.  After quite a bit of thought on this I decided it would not be the right approach.  If so, the code would have resulted in being a lot less maintainable and much more difficult to work with.  Instead, I decided to have every control type dynamically defined.

The first step in this was that to create a set of properties and their definitions so I could reuse them later in other class instances.  I decided to use the GoF's flyweight pattern so that I would have one set of base objects that were reusable with the mutable data in each property instance.  My code resembled the following:

[Flags()]
internal enum PropertyMode : int {
   Read       = 0x0001,
   Write      = 0x0002,
   ReadWrite  = 0x0003,
}

internal interface IToolPropertyDefn {
   Type            DataType { get; set; }
   PropertyMode    Mode { get; set; }
   string          Name { get; set; }
   string          PrivateName { get; set; }
   string          Description { get; set; }
   object          DefaultValue { get; set; }
   bool            IsMetaProperty { get; set; }
}

Then I had another class called ToolPropertyDefns that wrapped a Hashtable containing instances of ToolPropertyDefnImpl which represents instances of each of the properties in question.  The ToolPropertyDefns class can be indexed into by control type to retrieve the set of properties that pertains to the control type in question.  A snippet resembles:

internal sealed class ToolPropertyDefns {
   private static Hashtable _defns = new Hashtable();

   private ToolPropertyDefns() { }

   static ToolPropertyDefns() {
      // initialize the controls here...
      ToolPropertyDefnImpl[] defn = new ToolPropertyDefnImpl[] {
         new ToolPropertyDefnImpl(typeof(string), PropertyMode.ReadWrite, “Visible“, “_visible“,
            “Determines whether the control is visible or hidden.“, true, false);
      }
      _defns.Add(Tools.HeaderCaption, defn);

   }

   internal static IToolPropertyDefn[] GetDefn(Tools id) {
      return _defns[id] as IToolPropertyDefn[];
   }

   private sealed class ToolPropertyDefnImpl : IToolPropertyDefn {
      // define implementation here
   }
}

Once I had this class that managed the properties associated with each control type it was time to dynamically generate instances of the controls at runtime...which will be the topc for Part II of the discussion.

Wednesday, January 19, 2005 11:35:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, January 16, 2005

Back in the beginning of November I installed a CAPTCHA control to help mitigate all of the spam comments that were filtering into my blog.  These were a nuisance back then, but not yet an epidemic.  Shortly after I had installed the control I ran into some problems - namely the fact that the text was very difficult to read.  After a little battling with it I eventually removed it.  The spam had temporarily ceased anyway...until recently.

About daily now I get about 2-5 spam comment posts (either relating to poker or drugs).  Therefore, I decided to go out an search again for a CAPTCHA control that I could just drop onto a .Text blog.  It turns out that Miguel Jimenez had made some updates to his control not three days after I initially added it.  I wish I had followed up sooner and most (if not all) of these would have been avoided.  The control looks fantastic and it's a pleasure to have it on my site.

Thanks, Miguel for your great work!

Sunday, January 16, 2005 1:21:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

At long last (and I've been wanting to do this for some time now), I've added a calendar control to my home page for the blog.  I really like the look and feel of it.  I had done some searching in months past for the control and honestly never found any that I really liked and I almost resorted to creating my own.

However, yesterday I came across a few blog posts: one on Scott Willeke's site, and the second (which is really a modification to Scott Willeke's) by Alex Gorbatchev.  I am extremely pleased with the ease of deployment.  I had some styles that competed with the Alex's styles, but that was no big deal as he packaged his styles inline in the .ascx file.

I think they both did a fantastic job on the control and thank them heartily for their contributions to the .Text world.

Sunday, January 16, 2005 11:54:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, January 15, 2005

The .NET Framework is immense...it's plain huge; and it's getting bigger.  Once I feel that I sorta have a grasp on it I discover new classes and functionality.  Now this may be common knowledge, but I wasn't aware of it until recently.

A few days ago I stumbled upon a class in the System.Diagnostics namespace called ConditionalAttribute.  This attribute, when applied to a method, provides the compiler with the opportunity to selectively ignore calls to the method, depending on whether a given condition (a preprocessor constant) is met.  Note that the presence or absence of the constant doesn't determine in any way whether the method in question gets compiled - it always does (unless otherwise overridden with #if..#endif block, for example), but rather controls whether calls to the method get compiled.

For example:

[Conditional(”DEBUG”)]
public void DoSomething() {
   Console.WriteLine(”DoSomething() called...”);
}

public static void Main() {
   Console.WriteLine(“Before DoSomething() call“);
   DoSomething();
   Console.WriteLine(“After DoSomething() call“);
}

Given the previous example, in a Debug build (in which the DEBUG constant is defined by Visual Studio), the output will include all three lines, whereas in a Release build (in which the DEBUG constant is not defined), only two lines will be spit to the console.

This sure makes code look a lot cleaner than say:

public static void Main() {
   Console.WriteLine(“Before DoSomething() call“);
#if ( DEBUG )
   DoSomething();
#endif
   Console.WriteLine(“After DoSomething() call“);
}

I have some utility classes that exist in an external library (.dll) that provide some logging and tracing functionality for testing and debugging purposes; they log method entry/exit, parameters, variables, expressions, you name it.  Well, it's a pain to have calls to these logging methods always wrapped in #if..#endif blocks to conditionally compile them into a Debug vs a Release build, especially when calls might appear multiple times within a block of code.

The ConditionalAttribute class has come to the rescue.  I can now have a method that resembles the following code in my Logger.dll:

[Conditional(”LOG_ALL”)]
[Conditional(”LOG_EXPRESSION”)]
public void WriteExpression(...) {
   // ... perform the logging
}

If either LOG_ALL or LOG_EXPRESSION is defined within my calling assembly, the call to WriteExpression() gets compiled into the IL.  If neither of the two constants are defined, it's as though the call doesn't even exist.  This is pretty powerful and definitely cleans up the client code quite a bit, and makes it much more maintainable.  I really wish I had known about this sooner.

Saturday, January 15, 2005 5:29:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  |  Trackback