Tuesday, 10 June 2008

The Resharper cult members already know this, but for those who haven't joined yet, version 4.0 released today with VS 2008 support -- huzzah,  huzzah.  No longer able to resist the chanting and promises of eternal coolness I donned my robe and installed my free copy.

I clearly should have joined sooner.  Resharper has already changed my life.  First it pointed that I had redundant overrides  in the control I was working on, which I had really meant to delete.

Then it reminded me about the new implicit type declaration keyword var, so this...

XmlDocument SomeDoc = new XmlDocument();

becomes...

var SomeDoc = new XmlDocument();

Granted, that's not too exciting, but if your type declaration is something like...

Dictionary<SomeStrangeType,ANamespace.AnotherLongType> SomeDictionary = new Dictionary<SomeStrangeType,ANamespace.AnotherLongType>();

with var it becomes...

var SomeDictionary = new Dictionary<SomeStrangeType,ANamespace.AnotherLongType>();

Then Resharper pointed out something I didn't realize was available in C#, the object intializer?? VB.NET has long had something similar with the With statement (now with object initializer goodness too).  What's nice about this is that it saves repeating the instance name in front of the properties.  So this...

var MenuBinding = new MenuItemBinding();
MenuBinding.DataMember = MenuItemElementName;
MenuBinding.TextField = DisplayTextAttribute;
MenuBinding.NavigateUrlField = NavigationUrlAttribute;
MenuBinding.Depth = Depth;

becomes...

var MenuBinding = new MenuItemBinding
  {
     DataMember = MenuItemElementName,
     TextField = DisplayTextAttribute,
     NavigateUrlField = NavigationUrlAttribute,
     Depth = Depth
  };

I was staring at this new construct when I realized that -- it shouldn't work. The project I was working on was a Framework 2.0 project and these things were in 3.0 syntax.  But the darn thing compiles and works.  Not even a single warning.  WTF?  It turns out that since 3.0 and 3.5 are based on 2.0, these are simply compiler tricks -- there is nothing fundamentally different about the types.  Here's a blog post that explores in more detail what is happening under the covers.

Not bad for 15 minutes of tooling around.  Guess I am an official member. Where's the Koolaid?

.NET | 2.0 | 3.0 | 3.5 | Resharper
Tuesday, 10 June 2008 22:24:01 (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 
Wednesday, 09 January 2008
Headaches.  Homicidal thoughts.  Horrible alliterations.

All these things happened over the the last few days.

It all started when I needed to build 64-bit versions of a few .NET 2.0 apps (a wep app, a windows service and a passel of supporting libraries).  This is actually very simple to do. Visual Studio exposes a platform setting in the build configuration for each project.  The default platform is anycpu.  Specifying x64 sets the compiler option and instructs VS to build a 64-bit image (even on a 32-bit machine).  Of course, doing this for a bunch of projects would be dull.  Fortunately, I already have NANT scripts to build everything, so I added a platform parameter to the compiler tasks and voila, a slew of 64-bit assemblies in 194 seconds.

Dropped the gooey mess on the 64-bit machine, and by gosh the web app worked and so did the service.  Double checked that the 64-bit system was not running any 32-bit assembly in WOW mode. Nope, all 64-bit baby!  Ran the applications through their paces, and they ran perfectly.  .NET makes 64-bit apps happen with the flick of a (compiler) switch -- sweet!

Time to build the 64-bit installers for the web app and the service. Now, if 32-bit deployment projects are the 3-eyed, 9-toed, humpbacked, perpetually sniffing step-chilldren of .NET -- and they are -- 64-bit deployment projects make them look like the fairhaired, first born heirs to the kingdom. 

Just like any other app, deployment apps can be simply targeted to either platform.  But finding the toggle is bit confusing.  It is not in the same place as "normal" applications.  The platform can't be changed in the build configuration, you must select the Installer in the Solution Explorer and click F4 to expose the properties.  Selecting Properties... in the context menu for the installer does NOT expose the same set of properties.  OK, a little swearing later, and the web app installer is set to x64 bit and it builds the MSI. Woo hoo, looking good!

Time to test it on the x64 server.  An exception!  Ugghh.  BadFileImageFormat.  WTF.  Documentation time.  The error says I am trying to run a 64-bit image on a 32-bit platform, but, but, but, I'm running a 64-bit image on 64-bit platform.  Some googling, some double checking that a 32-bit assembly hadn't somehow screwed up the MSI.  More swearing. Finally stumbled across this blog post which pointed me in the right direction.

The cause turned out to be a Custom Action that updates the web.config file, sets some directory permissions and sets up the application in IIS. The Custom Action is an installer class that is kicked off by InstallUtil in the MSI.  Worked fine in 32-bit.  But, VS embeds the 32-bit version of InstallUtil in the MSI, even when a x64 platform has been targeted, hence the BadFileImageFormat exception. 

The workaround required downloading the Platform SDK and installing a tool named Orca.  Orca lets you inspect/alter the MSI guts.  Pulled the 64-bit version of InstallUtil from the x64 box and sucked it into the MSI using Orca. Saved the MSI and tried it again. And behold it worked, Custom Action and all. Thank you Chuck Norris Heath Stewart.

The service was bit trickier. I kept getting FileNotFound exceptions in the Windows directory. But I wasn't trying to install anything in the Windows directory, which was a bit perplexing.  The problem turned out to be the default directory for installing the service had a space in it.  Yes, in 2008, this is still an issue. Changed the default directory to something without spaces, and got around this error only to run into the dreaded InstallUtilLib.dll: Unknown Error., (NULL), (NULL), (NULL).  More swearing.  Well, it turns out that InstallUtil doesn't deal well with the way the installer package escapes path names when sending data to the Custom Action.  So I just sent all the properties without the surrounding quotes (since I was no longer allowing paths with spaces anyway) and the darn thing finally worked.

There's got be a better way, the whole MSI process is so cobbled together, it is astounding that anyone can create a usable installer without third party tools (and even they seem hobbled by the Windows Installer determined quirkiness) or weeks of free time.

Now, all of this could have been avoided if I hadn't used Custom Actions.  But there are no Standard Actions for:
  • setting directory or file permissions
  • setting up virtual directories in IIS
  • setting the ASP.NET version and application pool
  • updating configuration files

Also, the VS deployment project relies on a Custom Action to install the service, instead of creating a service table in the MSI.  Not sure why this is, but tis annoying to know it's there yet not exposed in the deployment project. If I had wanted to dive into Orca, I could have used to it set up the table in the MSI, but my patience had long since expired.

I'm not holding any hope that the situation will improve in the future.  As the software world becomes ever more web-centered, there is even less call for building installers.  With FTP and Xcopy it's easy enough to deploy web apps. Setting up an app in IIS manually is trivial and .NET removes most of the need for dealing with Registry foo.

If I have a client ask for install package again, I'm giving them a zip file and a page of instructions.  Infinitely quicker than dealing with Misfit Solution Installers.

2.0 | 64-bit
Wednesday, 09 January 2008 00:05:38 (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 
Thursday, 20 December 2007
I went on vacation at the end of July and returned in early August. Life restarted in fits and starts.  But somehow I neglected to get this blog started again. Now that five months have passed, I think it is time to begin again.  So without further ado...

Had a question on a forum today about how to access the top master page if you are using nested master pages.  Seemed like a good time to break out some recursion. 

protected MasterPage UltimateMaster(Page ThePage)
{
      if (ThePage.Master == null)
      {
         //no master
         return null;
      }
      else
      {
         return UltimateMaster(ThePage.Master);
      }
}

//this will call itself until it runs out of Master Pages
protected MasterPage UltimateMaster(MasterPage ThePage)
{
      MasterPage TheMaster;

      if (ThePage.Master == null)
      {
           TheMaster = ThePage;
      }
      else
      {
           TheMaster = UltimateMaster(ThePage.Master);

      }
      return TheMaster;
}
I'd add these methods to a base web page class, so I can access them from all my pages.  Then it is easy to access the ultimate master page at any time...
MasterPage TheUltimateMaster = UltimateMaster(this);
To access any custom properties or methods that have been exposed, the master page needs to be cast to its strong type...
MyUltimateMasterPageType MyMaster = (MyUltimateMasterPageType) TheUltimateMaster;
Then the ultimate master page is ready to be used...
MyMaster.AUsefulMethod("SomethingSomehting");
I haven't had the occasion to use nested master pages, but I thought I'd offer this as an early Christmas present to anyone who does.

Happy Holidays.  Merry Christmas!

.NET | 2.0
Thursday, 20 December 2007 21:15:38 (Eastern Standard Time, UTC-05:00)   #     Comments [3]  | 
Tuesday, 05 June 2007
I hate writing the same code twice.  Not just because I am a horrible typist, but because writing the same code twice means testing it twice, debugging it twice, maintaining it twice, etc.  I recently ran into a situation where this looked unavoidable.  I needed to write (a little more than) a wee bit of code that evaluated values against arbitrary conditions in the same way.  The twist was that these conditions could have different types. 

I didn't want to duplicate the code for each type. However, I also wanted it to be strongly typed, so I didn't want to resort to using the object type for everything.  Since all the types in question are numeric, I could have simply coerced everything into a decimal or a double type and written the bulk of the code against that one type.  But I didn't like this for three reasons:
  1. It would be imprecise: I wanted to compare integers to integers when I could
  2. It would require adding a layer of conversion logic
  3. It just didn't feel right.  It wasn't elegant.
Not all code is elegant, but it seems to flow much more easily and get working more quickly when it is.  So while I was counting up the types I'd need to support and contemplating the heinous sin of cut and paste coding, it occurred to me that .NET 2.0 should allow me to solve this very elegantly, using Generics

I have already fallen in love with the generic collections and have kicked the ArrayList to the curb, so it was time to figure out how to make a generic class of my own devising.

The <T> is the key...

public class OneRuleToBindThem<T>

This tells the complier that the class will be created for the specified type in <>.

So I whipped up my first generic class. The simplified version looked vaguely like this....

public class OneRuleToBindThem<T>
{
    private T mMinimumValue;
    private T mMaximumValue;
    private const string PASS = "Pass";
    private const string FAIL = "Fail";

    public OneRuleToBindThem(T MinimumValue, T MaximumValue)
    {
        mMinimumValue = MinimumValue;
        mMaximumValue = MaximumValue;
    }

    public string Evaluate(T ObservedValue)
    {
        string Result = PASS;
        if (ObservedValue > mMaximumValue)
            Result = FAIL;
        if (ObservedValue < mMinimumValue)
            Result = FAIL;

        return Result;
    }
}



That was too easy!  Let's compile it and move on...

Operator '>' cannot be applied to operands of type 'T' and 'T'  

What in the la-di-da does that mean? Shazbot.  Why can't I compare a T with a T?  They'll be the same type for pete's sake.  A little googling and reading and OK, the compiler doesn't know if a supplied type will support the given operand, so it properly throws an error.  Surely there must be a way around this, some way to reassure the compiler that only appropriate types will be used, really!

A hint from Ryan Olshan led me to check out IComparable. Ah, it is possible to constrain the types that can instantiate the class.  So I tried...

public class OneRuleToBindThem<T> where T:IComparable
{
//code you've seen before...
}

Compile and...the same errors appear in the build.  Fudgesticks.

An idea flickered.  Since I would only be using types that implement IComparable, maybe I could use the interface's CompareTo method somehow.

So, I rewrote the Evaluate method...

public string Evaluate(T ObservedValue)
{

       string Result = PASS;
        if (ObservedValue.CompareTo(mMaximumValue) > 0)
            Result = FAIL;
        if (ObservedValue.CompareTo(mMinimumValue) < 0)
            Result = FAIL;

        return Result;
    }

F5 to compile and -- hoorah.  The darn thing works, well compiles anyway.  Let's see if it actually works with a little test code...

        OneRuleToBindThem<int> AnIntegerRule = new OneRuleToBindThem<int>(4, 10);
        for (int Index = 1; Index <= 11; Index++)
        {
            Debug.WriteLine(String.Format("{0} : {1}", Index, AnIntegerRule.Evaluate(Index)));
        }

        OneRuleToBindThem<decimal> ADecimalRule = new OneRuleToBindThem<decimal>(4, 10);
        for (decimal Index = 1M; Index <= 11M; Index+= 0.2M)
        {
            Debug.WriteLine(String.Format("{0} : {1}", Index, ADecimalRule.Evaluate(Index)));
        }


Good golly.  Worked on the first, ahem, try.  Now is the time on "OOP - There it Is" when we dance.

Granted the example Evaluate method is only a few lines of code (and could be slimmer). In this example it wouldn't be too onerous to store the MinimumValue and MaximumValue as doubles, and then write an overloaded Evaluate method for each type using the appropriate convert functions.  But when Evaluate is 20+ lines of code and the class needs to support 3+ types, that's a shameful amount of cut-and-paste code. Shameful.

But with the Generic implementation, everything is strongly typed. And best of all, there's only one method to test, debug and maintain! Once again, my fear of typing led to a sweet little implementation.

Tuesday, 05 June 2007 22:46:14 (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 
Friday, 30 March 2007

There are four (development) life annoyances that I can do without:

  1. Recruiters who only use the state abbreviation to describe a job location. "Urgent need for Senior .NET Developer, Location: CA"
  2. Forum posters who demand code for entire applications. "Please send me chat server code -- urgent."
  3. Repeated requests for Interview Questions.  I've covered this elsewhere.
  4. Lazy gits who can't be bothered to learn how to read either C# or VB.NET. "Thanks for the answer, but my project is in VB.NET, I don't understand C#."
At least once a week, I'll answer a question on forum somewhere with a code example and get a "Thank you, but" response.  Often accompanied by a request to rewrite the code in their language of choice.  With perfectly named variables and smilies in the comments.

This burns my toast.  It takes enormous willpower not to simply respond "find another job you lazy git".

A) We're never talking more than 50 lines of code, usually it is around 20. 
B) 3/4 of the friggin' code is manipulating .NET Framework objects using .NET Framework methods and .NET Framework properties -- which are -- wait for it...

THE SAME FOR BOTH C# and VB.NET!


So this post is a (no longer) quick and dirty guide for figuring out how to translate C# into VB.NET (and vice versa, but frankly 92.6% of the time its a VB coder who complains).  It will become my standard response for all the future lazy gits.

Let's start at the top (of the class file that is)...

Need to reference a namespace...
ala C#: using System.Data.SqlClient;
ala VB: Imports System.Data.SqlClient

Note the ubiquitous semicolon (;).  C# statements can span pages like a sentence in Ulysses.  They don't end until the ; appears. VB statements get one line to do their business, unless they are ended with the awkward _ line continuation (underscore) which allows them to continue one more line unless they are ended with the awkward _, repeat.

A class...
ala C#: public class TheClassINeverHad
           {
             //fields, methods and properties -- oh my!
            }
ala VB: Public Class TheClassINeverHad
             'fields, methods and properties -- oh my!
          End Class
Ooooh no, C# does everything in lower case! (and its compiler is very strict about keeping it that way)
VB Capitalizes! (not that its compiler cares)

In C#, all code blocks are marked with with brackets{}.
In VB, code blocks usually go until a line that starts with End followed by the type of code block, which iin this case is Class.

Fancier class declarations...
ala C#: public abstract class TheClassINeverHad
ala VB: Public MustInherit Class TheClassINeverHad
ala C#: public sealed class TheClassINeverHad
ala VB: Public NotInheritable Class TheClassINeverHad
Why VB.NET couldn't use the more common OOP vernacular is beyond me.

Interface declarations...
ala C#: public interface IPractical
ala VB: Public Interface IPractical
Hooray, that should be clear even to the laziest git.

Extending a class...
ala C#: public class TheClassINeverHad: APracticalClass
ala VB: Public Class TheClassINeverHad
             Inherits APracticalClass
The humble colon does a lot here in C#.  The VB syntax leaves nothing to doubt.

Implementing an interface...
ala C#: public class TheClassINeverHad: IPractical
ala VB: Public Class TheClassINeverHad
             Implements IPractical
or interfaces...
ala C#: public class TheClassINeverHad: IPractical, IRidiculous
ala VB: Public Class TheClassINeverHad
             Implements IPractical
             Implements IRidiculous
The colon does everything! 

Extending and implementing...
ala C#: public class TheClassINeverHad: APracticalClass, IPractical, IRidiculous
ala VB: Public Class TheClassINeverHad
             Inherits APracticalClass
             Implements IPractical
             Implements IRidiculous
A comment...
ala C#: //This is a 1 line comment
          /* This starts a multiline comment
          This ends a multiline comment */
ala VB: 'This is a one line comment
There is no such thing as a multline comment in VB, but who comments code anyway?

You really should though.

a field...
ala C#: private int SomeNumberIWillUse;
ala VB: Private SomeNumberIWillUse as Integer
VB.NET surrounds the name of the variable with its access modifier and type.  C# gets all that out of the way then tells you the name.

a constant...
ala C#: private const string LAZY_GIT = "Lazy Git";
ala VB: Private Const LAZY_GIT as String = "Lazy Git"
a constructor...
ala C#: public TheClassINeverHad()
            {
                //Do Something Useful
             }
ala VB: public Sub New()
             'Do Something Useful
          End Sub

C# uses the name of the class to indicate the constructor. The Sub New in VB is a little clearer at first blush.

A structure can be a handy little doo-dad when a class is overkill...
ala C#: public struct Soda
           {
                 public string Name;
                 public int Calories;
            }
ala VB: Public Structure Soda
             Public Name as String
             Public Calories as Integer
          End Structure
More brackets in C#, another End statement in VB. C# shows it inclination for abbreviation. Patterns develop.

Let's not forget enumerations...
ala C#: public enum PlanetValues
           {
                    Mercury = 0,
                    Venus = 1,
                    Earth = 2,
                    Mars = 3,
                    Jupiter = 4,
                    Saturn = 5,
                    Uranus = 6,
                    Neptune = 7,
                    Pluto = 8
            }
            public enum PlanetValues
           {
                    Mercury,
                    Venus,
                    Earth,
                    Mars,
                    Jupiter,
                    Saturn,
                    Uranus,
                    Neptune,
                    Pluto
            }

ala VB: Public Enum PlanetValues
             Mercury = 0
             Venus = 1
             Earth = 2
             Mars = 3
             Jupiter = 4
             Saturn = 5
             Uranus = 6
             Neptune = 7
             Pluto = 8
          End Enum

        Public Enum PlanetValues
             Mercury
             Venus
             Earth
             Mars
             Jupiter
             Saturn
             Uranus
             Neptune
             Pluto
          End Enum

All these enumerations are identical.  If no value for the first element is specified it is set = 0, every other unspecified element is incremented one from the previous element. Curiously the C# syntax uses commas and not semi-colons.

a local variable...
ala C#: string DeveloperPersona;
ala VB: Dim DeveloperPersona as String
arrays...
ala C#: string[] CoolDevTools;
           string[] CoolDevTools = new string[5];
           //assignment
          CoolDevTools[0] = SomeString;
ala VB: Dim CoolDevTools as String()
          Dim CoolDevTools(5) as String
          'assignment
          CoolDevTools(0) = SomeString
             

C# uses square brackets [] for the elements.
VB uses parentheses ().

Ditto for collection elements...
ala C#: AnObjectType SomeObject = (AnObjectType)SomeHashtable[SomeKey];
           A
nObjectType SomeObject = (AnObjectType)SomeArrayList[SomeIndex];
ala VB:  Dim SomeObject as AnObjectType = SomeHashtable(SomeKey)
          
Dim SomeObject as AnObjectType = SomeArrayList(SomeIndex)
          'or if Option Strict is on
          D
im SomeObject as AnObjectType = CType(SomeHashtable(SomeKey), AnObjectType)
         
Dim SomeObject as AnObjectType = CType(SomeArrayList(SomeIndex), AnObjectType)
             
C# doesn't do narrowing implicit type casts,  so an element retrieved from an untyped collection must be explicitly cast.  This is done by wrapping the object type in parentheses and smooshing it against the collection name.
VB will implicitly cast unless Option Strict is On, in which case the CType method must be used to cast the element returned to the proper type.

a method that does NOT return a value...
ala C#: public void ThePerfectMethod(string DeveloperName)
             {
                // coding goodness
             }
ala VB: Public Sub ThePerfectMethod(DeveloperName as String)
                'Coding Goodness
          End Sub
a method that does return a value...
ala C#: public int ThePerfectMethod(string DeveloperName)
             {
                // coding goodness
                return 42;
             }
ala VB: Public Function ThePerfectMethod(DeveloperName as String) as Integer
                'Coding Goodness
                Return 42
          End Function
As with fields and constants, C# states the access modifier and the type being returned by the method before getting to the name.  When nothing is returned the type is void.
VB has separate keywords to differentiate between methods that return nada (Sub) and those that return something (Function).
Parameters are types just like variables are in each language:  type Name in C#, Name as Type in VB.

a read/write property...
ala C#: public int TheAnswer
             {
               get{   return mTheAnswer;}
               set{  mTheAnswer = value;}
             }
ala VB: Public Property TheAnswer() as Integer
                Get
                    Return mTheAnswer
                End Get
                Set (Value as Integer)
                   mTheAnswer = Value
                End Set
                     
          End Property

a read-only property...
ala C#: public int TheAnswer
             {
               get{   return mTheAnswer;}
             }
ala VB: Public ReadOnly Property TheAnswer() as Integer
                Get
                    Return mTheAnswer
                End Get
          End Property
a write-only property...
ala C#: public int TheAnswer
             {
               set{  mTheAnswer = value;}
             }
ala VB: Public WriteOnly Property TheAnswer() as Integer
                Set (Value as Integer)
                   mTheAnswer = Value
                End Set
                     
          End Property
VB.NET needs to be explicity told a property is read- or write-only, C# is happy as long as there is a get or set -- it figures it out.

static(Shared) members...
ala C#: private static int mANumberEveryoneNeeds;
           public static ANumberEveryoneNeeds
           {
                get{return
mANumberEveryoneNeeds;}
           }
           public static void ResetTheNumber()
           {
               
mANumberEveryoneNeeds = 0;
           }
ala VB: Private Shared mANumberEveryonNeeds as Integer
           Public Readonly Shared Property ANumberEveryoneNeeds() as Integer
                Get
                   Return mANumberEveryoneNeeds
                End Get
           End Property
           Public Shared Sub ResetTheNumber ()
                 mANumberEveryoneNeeds = 0
           End Sub

Shared = static.  static = Shared. Static members are shared by ALL instances of a class.  The meaning of static is not as immediately a clear as Shared. But it's not that hard to remember.

Branching...
ala C#: if(SomeVariable == 42)
             {
                Answer = "That's it!";
                HasWisdom = true;
             }
           else
             {
                Answer = "That's not it.";
                HasWisdon = false;
             }

          //one line syntax
           if(SomeVariable == 42)
                Answer = "That's it!";
           else
                Answer = "That's not it.";
               


ala VB: If SomeVariable = 42 Then
             Answer = "That's it!"
             HasWisdom = True
          Else
             Answer = "That's not it."
             HasWisdom = False
          End if
There's no Then in C#, the boolean expression is wrapped in parentheses and the code to execute is within {}. The brackets are not required if the condition only executes one line.  Like most other constructs in VB, the code block ends with a uniquely named End statement: End If.

Note in C# the == is an evaluation operator, as opposed to the assignment operator =.  In VB = performs both tasks.

What fun is an If statement without boolean logic...
ala C#: if(!Page.IsPostBack) //Not operator
          
if(Night != Day) //Inequality
          
if(Night == Day & Pigs.CurrentState == PigState.Flying) // And
           if(Night == Day && Pigs.CurrentState == PigState.Flying) //Conditional And
          
if(Night == Day | Pigs.CurrentState == PigState.Flying) // Or
          
if(Night == Day || Pigs.CurrentState == PigState.Flying) // Conditional Or
          
if(Night == Day ^ Pigs.CurrentState == PigState.Flying) // Xor


ala VB: If Not Page.IsPostBack Then
           If Night <> Day Then 'Inequality
           If Night = Day And Pigs.CurrentState = PigState.Flying Then
          
If Night = Day AndAlso Pigs.CurrentState = PigState.Flying Then 'Conditional And
           If Night = Day Or Pigs.CurrentState = PigState.Flying Then
          
If Night = Day OrElse Pigs.CurrentState = PigState.Flying Then 'Conditional Or
          
If Night = Day Xor Pigs.CurrentState = PigState.Flying Then
          
VB spells everything out, though <> is a unique feature of the language.  The conditional operators AndAlso (&&) and OrElse(||) are tres useful, they short circuit the code and stop evaluting as soon as the appropriate condition is met.

And when If Then is isn't enough...
ala C#: switch(SelectedPlanet)
           {
                 case PlanetValues.Earth:
                      message = "Live there";
                      break;
                 case PlanetValues.Venus:
                 case PlanetValues.Mars:
                      message = "Landed there";
                      break;
                
case PlanetValues.Mercury:
                 case PlanetValues.Jupiter:
                 case PlanetValues.Saturn:
                 case PlanetValues.Uranus:
                 case PlanetValues.Neptune:
                      message = "Flew by";
                      break;
                  case PlanetValues.Pluto:
                      message = "Is it a planet?"
                      break;
                   default:
                      message = "Never heard of it";
                      break;
           }

           

ala VB: Select Case SelectedPlanet
                Case PlanetValues.Earth
                   message = "Live there"
                Case PlanetValues.Venus, PlanetValues.Mars
                   message = "Landed there"
                Case PlanetValues.Mercury, PlanetValues.Jupiter, PlanetValues.Saturn, PlanetValues.Uranus, PlanetValues.Neptune
                   message = "Flew by"
                Case PlanetValues.Pluto
                   message = "Is it a planet?"
                Case Else
                   message = "Never heard of it"
          End Select

In C#, there's only one value per case, but once a supplied value matches a case, the code will "fall through" until it finds a case that executes code.  All cases that have code must end with a break;.
In VB, multiple values can be present on a line, it's also possible to do ranges. The code cannot fall through in VB, but the extra flexibility for defining case values makes it unecessary.

For Loops...
ala C#: for(int Index = 0; Index < SomeIntegerArray.Length; Index ++)
             {
                 Total += SomeIntegerArray[Index];
                 CallSomeOtherFunction(SomeIntegerArray[Index]);
             }
             //A single line For Loop can be done without the brackets
           
for(int Index = 0; Index < SomeIntegerArray.Length; Index ++)
               
Total += SomeIntegerArray[Index];

ala VB: For Index as Integer = 0 to SomeIntegerArray.Length -1
                Total += SomeIntegerArray(Index)
                CallSomeOtherFunction(SomeIntegerArray(Index))
          Next

In C#, {} brackets define what code gets looped, but a single line statement does not require brackets. Iteration step size is always specified
VB always requires the Next statement.  The iteration step size defaults to 1 for VB, to change the iteration step size...

ala C#: for(int Index = 0; Index < SomeIntegerArray.Length; Index += 2)
             {
                 Total += SomeIntegerArray[Index];
                 CallSomeOtherFunction(SomeIntegerArray[Index]);
             }
           


ala VB: For Index as Integer = 0 to SomeIntegerArray.Length -1 Step 2
                Total += SomeIntegerArray(Index)
               
CallSomeOtherFunction(SomeIntegerArray(Index))
          Next
To break out of the loop before it completes...
ala C#: for(int Index = 0; Index < SomeIntegerArray.Length; Index += 2)
             {
                 Total += SomeIntegerArray[Index];
                 if(CallSomeOtherFunction(SomeIntegerArray[Index]) == false)
                   break;
             }


ala VB: For Index as Integer = 0 to SomeIntegerArray.Length -1 Step 2
                Total += SomeIntegerArray(Index)
                If
CallSomeOtherFunction(SomeIntegerArray(Index)) = False Then
                   Exit For
                End if
          Next
break is used to get out of every kind of loop in C#.  The command for exiting a loop in VB.NET depends on the type of the loop. This can come in handy for nested loops of different types.

For each loops...

ala C#: foreach(Universe PossibleUniverse in PossibleUniverses)
             {
                 if(PossibleUniverse.HasStrongForce)
                 {
                     
                      AddToViableCandidates(PossibleUniverse);
                 }
             }
           


ala VB: For Each PossibleUniverse as Universe in PossibleUniverses
                If PossibleUniverse.HasStrongForce Then
                   AddToViableCandidates(PossibleUniverse)
                End if
          Next

Ignore the brackets and the for each loops look a lot alike.


Do While Loops...
ala C#: do
             {
                 Total += SomeIntegerArray[Index];
                 if(CallSomeOtherFunction(SomeIntegerArray[Index]) == false)
                   break;
                 Index++;
             }
             while(Index < SomeIntegerArray.Length);

ala VB: Do
                Total += SomeIntegerArray(Index)
                If
CallSomeOtherFunction(SomeIntegerArray(Index)) = False Then
                   Exit Do
                End if
                Index += 1
          Loop While Index < SomeIntegerArray.Length

          Do While Index < SomeIntegerArray.Length
                Total += SomeIntegerArray(Index)
                If
CallSomeOtherFunction(SomeIntegerArray(Index)) = False Then
                   Exit Do
                End if
                Index += 1
          Loop

The do loop in C# always executes at least once.  The top version of the VB loop does as well.  While the second version evaluates the condition before executing. This is the one of the few code structures in VB that doesn't denote it's end using an End statement (the others being the for and for each loops). If it did it would look something like this...

          'This is not legal syntax -- just what a Do loop would look like if VB were maddeningly consistent
          Do
                Total +=SomeIntegerArray(Index)
          End Do While Index < SomeIntegerArray.Length

Which is just goofy.

Do Until Loops...
ala C#: do
             {
                 Total += SomeIntegerArray[Index];
                 if(CallSomeOtherFunction(SomeIntegerArray[Index]) == false)
                   break;
                 Index++;
             }
             while(Index < SomeIntegerArray.Length);

ala VB: Do
                Total += SomeIntegerArray(Index)
                If
CallSomeOtherFunction(SomeIntegerArray(Index)) = False Then
                   Exit Do
                End if
                Index += 1
          Loop Until Index = SomeIntegerArray.Length

          Do Until Index = SomeIntegerArray.Length
                Total += SomeIntegerArray(Index)
                If
CallSomeOtherFunction(SomeIntegerArray(Index)) = False Then
                   Exit Do
                End if
                Index += 1
          Loop

Wait a second -- there's no do until in C#. Until is just the other side of while.  Instead of executing while a condition is true, it executes until it is true. When moving from VB.NET to C# just use the while and flip the condition to its opposite. Again the C# loop and the first VB loop execute at least once. 

And the last loop is the plain old while loop...
ala C#: while(Index < SomeIntegerArray.Length)
             {
                 Total += SomeIntegerArray[Index];
                 if(CallSomeOtherFunction(SomeIntegerArray[Index]) == false)
                   break;
                 Index++;
             }
           

ala VB: While Index < SomeIntegerArray.Length

                Total += SomeIntegerArray(Index)
                If
CallSomeOtherFunction(SomeIntegerArray(Index)) = False Then
                   Exit While
                End if
                Index += 1
          End  While
        
While loops in both languages evaluate the condition before executing.  Note the while uses the familiar Exit While to break and the End While to terminate the loop.

Finally, a tricky difference -- hooking up event handlers...
ala C#: SomeButton.Click += new ButtonEventHandler(SomeButton_Click);
           
ala VB: AddHandler SomeButton.Click, AddressOf SomeButton_Click

          'or directly declare it
          Sub SomeButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SomeButton.Click
VB lets you hook up the Handler on the event declaration or add the handler dynamically.  C# only allows the dynamic hook. 

I think this post has sufficiently covered 93.7% of commonly encountered code.  I'd cover Generics (VB usage)  but I think anyone working with Generics probably doesn't have any problems reading either language.

Here are some reference links...
And for the truly lazy or people who have to translate more than 20 lines of code, there are converters (though you might get some interesting results) ...
So learn 'em both -- double your code examples, double your employment opportunities -- double your fun.
.NET | 2.0 | Annoyances
Friday, 30 March 2007 17:12:15 (Eastern Standard Time, UTC-05:00)   #     Comments [2]  | 
Wednesday, 07 February 2007

In the previous GridView post, we figured out how to create a simple updating GridView without a lick of code.  But it only updated a value from a TextBox, nothing too difficult about that.  What would happen if one of the columns needed a DropDownList for editing purposes?  This is something that required code in ASP.NET 1.1. The DropDownList needed to be bound in the ItemDataBound event, and that was only for display purposes.  Updating required even more code.  Can the declarative code model handle this twist without resulting to actual -- gasp -- coding?

I'll save the suspense and admit that, in fact, it is possible to create an Editable, Updating GridView with a DropDownList  without writing any code.  Here it is.   We'll talk about the interesting bits afterwards.

    <div>
       <asp:GridView ID="GridViewDropDown" runat="server" DataSourceID="TestSqlSource" AutoGenerateEditButton="True" DataKeyNames="NameID" AutoGenerateColumns="False" >
       <Columns>
        <asp:BoundField HeaderText="Name" DataField="Name"  />

           <asp:TemplateField HeaderText="Popularity Trend">
               <EditItemTemplate>
                   <asp:DropDownList ID="PopularityTrendDropDown" runat="server"   SelectedValue='<%# Bind("PopularityID") %>' DataSourceID="PopularitySqlSource" DataTextField="Description"  DataValueField="PopularityID" ></asp:DropDownList>
                                    
               </EditItemTemplate>
               <ItemTemplate>
                   <asp:Label ID="PopularityTrendLabel" runat="server" Text='<%# Eval("Description") %>'></asp:Label>
               </ItemTemplate>
           </asp:TemplateField>
   
       </Columns>
        </asp:GridView>
        <asp:SqlDataSource ID="TestSqlSource" runat="server" ConnectionString="<%$ ConnectionStrings:TestConnectionString %>" SelectCommand="SELECT Name, NameID, PopularityID, Description FROM [BabyName] bn Left join Popularity p on bn.PopularityID = p.PopularityID" UpdateCommand="UPDATE BabyName SET Name = @Name, PopularityID = @PopularityID WHERE NameID = @NameID"  >
                   
        </asp:SqlDataSource>
         <asp:SqlDataSource ID="PopularitySqlSource" runat="Server" ConnectionString="<%$ ConnectionStrings:TestConnectionString %>" SelectCommand="SELECT PopularityID, [Description] FROM [Popularity]" >

         </asp:SqlDataSource>
 
    </div>

There are now 2 data sources, one for the GridView, and the PopularitySqlSource for the PopularityTrendDropDown. The PopularitySqlSource just provides a simple list of the possible values to display in the dropdown. TestSqlSource's SelectCommand has a new join and and an extra column, Description.  This is so that the Item template can display the user friendly text value in the label.  I was searching for a sexier way of doing this, so I didn't have to include the join and column in the statement, but heck, as long as we're polluting the aspx with SQL statements might as well use all the SQL we can.

In order to use a DropDown in the GridView, we need to stop autogenerating the columns and create a TemplateField for the column that has the DropDown.   The TemplateField has two parts: the ItemTemplate and the EditItemTemplate.  The ItemTemplate simply shows the user friendly description of the PopularityTrend.  The EditItemTemplate holds the DropDownList for selecting the proper PopularityID. Whatever is in the EditItemTemplate is what shows up when the user clicks on the Edit button.

There is a little bit of data binding script syntax needed to properly bind the underlying values into the controls.  For the DropDownList we bind the SelectedValue to the PopularityID...

SelectedValue='<%# Bind("PopularityID") %>'

The bit bewteen <%# and %> is actually a call to the Bind method which sets up the control to do two-way binding so that it can keep track of updates.  This is used behind the scenes for the BoundField too.  Technically this is coding, but since we are not creating a separate code file or breaking out the <script> tags, we'll ignore it.

Similarly the Text property of the label is bound using the Eval method. 

Text='<%# Eval("Description") %>'

The difference between Eval and Bind, is that Eval is a read-only binding, it can't be used to update the underlying datasource.

So all that is needed to create a GridView that uses a DropDownList to edit a column value is:

  1. A TemplateField to hold the DropDown when a row is being edited, and a label when it is not
  2. A DataSource for the list portion of the DropDown control
  3. A little extra SQL to get the friendly description for the label
  4. A wee bit of binding code syntax

So, still no code, but our GridView and DataSource declarations are getting heftier.  Probably still slimmer than the analogous code, but not nearly as compact as the simple GridView from the previous example.

Actually, if there were a DropDownField available the declarative syntax could be almost as slim as it was for the simple GridView.  I'm surprised that there wasn't a DropDownField class created for ASP.NET 2.0 given their frequent use for editing grid columns.  I'm sure someone has created one (or is is creating one) that could be added in. Could be a fun little project.

Next time, we'll see if we can add in multi-row editing without code.  I have my doubts.

 

 

Wednesday, 07 February 2007 23:20:59 (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 
Tuesday, 30 January 2007

Starting to get more questions about GridViews and SqlDataSources on the forums I haunt.  On the surface, these two components seem to offer a quick path to application development with no coding. 

And sure enough, once you figure them out, you don't have to do much to get an updatable GridView on the page.

Here's an example of a fully updating GridView...

<asp:GridView ID="NoCodeGridView" runat="server" DataSourceID="TestSqlSource" AutoGenerateEditButton="True"   DataKeyNames="NameID">
</asp:GridView>

<asp:SqlDataSource ID="TestSqlSource" runat="server" ConnectionString="<%$ ConnectionStrings:TestConnectionString %>" SelectCommand="SELECT * FROM [BabyName]" UpdateCommand="UPDATE BabyName SET Name = @Name WHERE NameID = @NameID">
            <UpdateParameters>
                <asp:Parameter Name="Name" Size="50" Type="String" />
                <asp:Parameter Name="NameID" Type="Int32" />
            </UpdateParameters>
 </asp:SqlDataSource>

The code behind file is strangely empty, yet clicking on a row's edit button brings up an editable row with an update and cancel button.  And clicking on the update button saves the altered baby name.  This scares and frightens me, because I know it won't be this easy once I need to do something real. While I appreciate that the details of implementation have been hidden from me, the fact that I can't see them also worries me. I'll leave that aside for the moment. I will also ignore the fact that I have embedded SQL statements in an ASPX page, and we'll move on and examine what's needed so the snippet above works.

The key in the GridView is this attribute:

AutoGenerateEditButton="True" 

This tells the GridView to generate the Edit button and Update/Cancel button. There are other ways to do this, but we're looking for the quickest, dirtiest way at the moment.

The real keys are in the SqlDataSource.  Without a select command nothing would be bound to the grid. And it obviously needs an update command, otherwise you get this exception...

Updating is not supported by data source 'TestSqlSource' unless UpdateCommand is specified.

Reading the stack trace for the exception shows you what ASP.NET is doing behind the scenes. 

   System.Web.UI.WebControls.SqlDataSourceView.ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues) +1828259
   System.Web.UI.DataSourceView.Update(IDictionary keys, IDictionary values, IDictionary oldValues,    DataSourceViewOperationCallback callback) +78
   System.Web.UI.WebControls.GridView.HandleUpdate(GridViewRow row, Int32 rowIndex, Boolean causesValidation) +1215
  
System.Web.UI.WebControls.GridView.HandleEvent(EventArgs e, Boolean causesValidation, String validationGroup) +858
   System.Web.UI.WebControls.GridView.OnBubbleEvent(Object source, EventArgs e) +95
   System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +35
   System.Web.UI.WebControls.GridViewRow.OnBubbleEvent(Object source, EventArgs e) +117
   System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +35
   System.Web.UI.WebControls.LinkButton.OnCommand(CommandEventArgs e) +115
   System.Web.UI.WebControls.LinkButton.RaisePostBackEvent(String eventArgument) +163
   System.Web.UI.WebControls.LinkButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +7
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +11
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +174
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5102

The last three are the interesting ones (the stack reads down from the last method called to the first).  The GridView's HandleEvent figures out an Update is going on and calls HandleUpdate, which in turn calls the Update method on the DataSourceView, which in turn calls the ExecuteUpdate on the SqlDataSourceView which does the real work. 

Let's take a little side trip and see what we can find out about these methods.

GridView.HandleUpdate is not a public method and hence does not appear in the documentation.

DataSourceView.Update is public.  DataSourceView is an abstract base class that alll the DataSourceView implementations are derived from.  This method calls the protected ExecuteUpdate method on that has been implemented by the inheriting class, in this case SqlDataSourceView.ExecuteUpdate. All pretty straightforward, and the SqlDataSourceView has some event handlers so it looks like there are places to hook in when actual programming is required.

Let's end our little side trip and get back into seeing what's needed for the little snippet to work.

One thing I noted was the documentation frequently mentions parameters, so they must be needed to make this work.  Let's pull out the <UpdateParameters> element and see what happens.

Begorra! The GridView does not throw an error and still updates.  It seems everything will be peachy if the update command parameter names correspond to columns in the select command. Let's run a wee test and change a parameter name in the update command. @Name will become @Name1

Didn't like that all

Must declare the variable '@Name1'.

So this is all you actually need...

     <asp:GridView ID="NoCodeGridView" runat="server" DataSourceID="TestSqlSource" AutoGenerateEditButton="True" DataKeyNames="NameID">
     </asp:GridView>
     <asp:SqlDataSource ID="TestSqlSource" runat="server" ConnectionString="<%$ ConnectionStrings:TestConnectionString %>" SelectCommand="SELECT * FROM [BabyName]" UpdateCommand="UPDATE BabyName SET Name = @Name WHERE NameID = @NameID">
        
     </asp:SqlDataSource>

As long as the SqlDataSource's SelectCommand returns column names that correspond to the parameter names used in the UpdateCommand it all works.

Next time we'll see what happens when you need to do something a little fancier.

Tuesday, 30 January 2007 22:18:17 (Eastern Standard Time, UTC-05:00)   #     Comments [1]  | 
Wednesday, 17 January 2007
Under ASP.NET 1.1, the ASP.NET engine is not (by default) responsible for the application's image, style sheet, and javascript files. These are served up directly by IIS. ASP.NET can be made responsible for these file types by playing with the ISAPI file mappings and maybe creating an HttpHandler or two.

This changes under ASP.NET 2.0.  The ASP.NET engine has responsibility for all these file types and is called when a request for one is made.

So what?  The files get served, the application works, who cares if IIS or ASP.NET does the work?

In many applications it wouldn't matter, but what happens if the application has been secured in web.config like so...

<authorization>
   <deny users="?" />
</authorization>

... and an anonymous user tries to access the site and gets redirected to the login page?

Under 1.1, since IIS was responsible for the css, javascript and image files, it wouldn't matter -- the page would be served as expected, showing all the images and properly referencing any stylesheets or script files.

Under 2.0, the anonymous user would see an unstyled page with blank image boxes. Any javascript calls to referenced files won't work either. Why? Because ASP.NET isn't going to serve up anything but the login page to an anonymous user -- because that is what it was told to do.

This is great for security, but can be a little frustrating when you KNOW you put the right path in for that image, and KNOW that the all h1 elements should be hot pink  and all you see is an unformatted mess.

Fortunately it is very easy to work around this so the public pages on a secured site show up properly.  All that needs to be done is to tell the application that anonymous users are allowed to access the content in certain folders. This can be done using a location element or two in the web.config file.  The following one allows anonymous users to access content in the unsecured_images folder...

<location path="unsecured_images">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
  </location>

That's all there is to it.


Wednesday, 17 January 2007 22:29:44 (Eastern Standard Time, UTC-05:00)   #     Comments [1]  | 
Wednesday, 20 December 2006

Finally! .NET 2.0 has been out for a year.  Finally found the time to move our main application to 2.0. It's been a bit of an adventure.  There are 12 class libraries, 2 server control assemblies, a service, a web app and various utilities.  Two of the class libraries are in C++, one managed, one native. The truly insane can read about the little odyssey through those assemblies.  Everything else is written in VB.NET. 

The VB.NET class libraries converted easily.  The only issue was in the few classes that performed XSL Transformations where I had to change a couple of deprecated method calls.  These were no surprise.  Other than that there were only warnings for untyped functions or parameters (very naughty, and one of the dangers of working in VB with OPTION STRICT OFF) and a surprising number of unused local variables. 

The web application was a lot trickier than anticipated.  There are some fundamental differences between 1.1 and 2.0 web applications. One of the significant changes is in the coding model.  2.0 makes use of partial classes, so that a single class can be created from separate files, this cleans some things up.  There are no longer control declarations in the code-behind file, but it is a change. 

Here is a very handy resource that discusses most of the issues you will run into when converting from 1.1 to 2.0. 

In the standard out-of-the-box VS2005, the project file for web applications has also gone the way of the dodo, you create Web Site Projects.  Everything in the project tree gets put into the application. Fortunately, there is a feature to exclude files, which you will use. Since the Web Site Project includes ALL the files in the directory tree, files that you excluded in your 1.1 project will suddenly reappear like uncompilable ghosts in the 2.0 version. The other annoying "feature" is that these projects spew forth an assembly for every folder in your application, and couple of others for good measure, and the files are randomly named.  Hello deployment fun -- I'm sure there's good reason for this, but it is not intuitively obvious, it seems friggin' nutty.

This application model had been fine for the smaller projects I had converted, and I figured I would discover a way to deal with the assembly vomit, so I pushed on assuming that I was moments away from having a our application working in 2.0.

But it was not to be, this web application pushed the Web Site Project model over the cliff of despair.

The application has around 60 pages, 15 classes and 15 user controls spread amongst 10 directories. Most of the heavy lifting is done in the underlying libraries. I didn't think it was that large until I tried to compile it.  In VS 2003, it was up and running in under a minute, in VS2005 it was 5+ minutes, and the sucker was crashing every time I changed the base web page class that the pages inherited from.  I lived with this for about a day, googling while it compiled or restarted, toggling various settings, swearing and pruning previously exlcuded and unused pages ruthlessly. 

After one seemingly eternal cycle of rebooting, I seriously considered asking for a quad-core super box or retreating back to 1.1.  I decided to take one more look around the web for a solution and I stumbled across this article, which in turn led me to discover an alternate model to this lunancy, the Web Application Project! It was the old 1.1 compilation model, complete with a single assembly output -- hooray.  It required some VS update installations and yet another conversion from my original 1.1 application, but in a few hours I had a quickly compiling application.  Some testing and a small victory dance later, and it was time to start ripping out the facacta hand-rolled page templates and putting in the master pages!



Just a reminder kids, always use source code control, especially when undertaking a conversion.  It makes mistakes almost painless and recovery simple!


UPDATE:  MS has shipped the first service pack for VS 2005. This includes the Web Application Projects. If you have previously installed the Web Application update, you will have to uninstall it before installing the service pack.

Wednesday, 20 December 2006 23:04:59 (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 

Theme design by Dean Fiala

Pick a theme: