Welcome

You have reached the blog of Keith Elder. Thank you for visiting! Feel free to click the twitter icon to the right and follow me on twitter.

Witty Twitter 1.9.0.20 Published

Posted by Keith Elder | Posted in .Net, PC Software | Posted on 20-12-2008

4

Get Latest Version Here:

http://keithelder.net/software/witty/witty.application (requires .Net 3.0 framework)

It has been awhile since I published a version of Witty Twitter.  I was going to push one a month or so ago but new features were not ready for prime time.  This version has a few neat twists in it.  Here is a list of things that were added. 

image

Witty now supports multiple URL services.  TinyUrl is the default, but it also supports Bitly and ISGD.

Another feature added is the ability to filter tweets.  This would have been handy during election time but there are other times you just want to tune out some noise.

image

Another feature is the ability to temporarily ignore a user.  Sure everyone needs More Wally in their life, but there are times when there can be too much Wally.  Right click a user and click “Temporarily Ignore User”.  This will ignore that user for 30 minutes.  Very handy when someone you are following starts to get a little out of hand.

image

Thanks to Jon Galloway for putting most of these features in.  Enjoy.

Workaround For WCF NetMsmqBinding Bug: The service ‘~/queue’ does not exist.

Posted by Keith Elder | Posted in .Net, WCF | Posted on 24-11-2008

10

There is an extremely nasty bug in WCF (Windows Communication Foundation) that I have discovered as of late.  I know it is a bug because after several weeks with an open support call into Microsoft it was confirmed as a bug.  It was so perplexing because it was hard to replicate.  It even took the .Net Framework developers a week or more to track it down.  Here’s a full blown error message:

An unhandled exception occurred and the process was terminated.

Application ID: /LM/W3SVC/2/ROOT

Process ID: 4428

Exception: System.ServiceModel.EndpointNotFoundException

Message: The service ‘~/unittestqueue’ does not exist.

StackTrace:    at System.ServiceModel.ServiceHostingEnvironment.NormalizeVirtualPath(String virtualPath)
   at System.ServiceModel.Channels.MsmqHostedTransportManager.HostedBindingFilter.MatchFound(String host, String name, Boolean isPrivate)
   at System.ServiceModel.Channels.MsmqBindingMonitor.MatchQueue(MatchState state)
   at System.ServiceModel.Channels.MsmqBindingMonitor.ProcessFoundQueues(MessageQueue[] queues, Dictionary`2 knownQueues, Boolean isPrivate)
   at System.ServiceModel.Channels.MsmqBindingMonitor.OnTimer(Object state)
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke2()
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.OnSecurityContextCallback(Object o)
   at System.Security.SecurityContext.Run(SecurityContext securityContext, ContextCallback callback, Object state)
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke()
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ProcessCallbacks()
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.CompletionCallback(Object state)
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
   at System.ServiceModel.Diagnostics.Utility.IOCompletionThunk.UnhandledExceptionFrame(UInt32 error, UInt32 bytesRead, NativeOverlapped* nativeOverlapped)
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

 

Ok, you see the error message above where it says the service ‘~unittestqueue` does not exist?  Well that queue DOES exist on the server but there isn’t a service mapped to that queue. 

The kicker to this is that I’m not even using the unittestqueue at all within my code.  This begs the question, why is a queue that I’m not even using showing up in my error list?  The netMsmqBinding I had configured used another queue called logEntries.  Here is the WCF configuration so you can see how this is configured.

   1: <system.serviceModel>
   2:         <serviceHostingEnvironment>
   3:             <baseAddressPrefixFilters>
   4:                 <add prefix="http://keithelder.net/"/>
   5:             </baseAddressPrefixFilters>
   6:         </serviceHostingEnvironment>
   7:         <client/>
   8:         <bindings>
   9:             <netMsmqBinding>
  10:                 <binding name="msmqBinding">
  11:                     <security mode="None">
  12:                         <transport msmqAuthenticationMode="None" msmqProtectionLevel="None"/>
  13:                         <message clientCredentialType="None"/>
  14:                     </security>
  15:                 </binding>
  16:             </netMsmqBinding>
  17:         </bindings>
  18:         <services>
  19:    <service behaviorConfiguration="LogEntriesBehavior"
  20:     name="KeithElder.MsmqService">
  21:     <endpoint address="net.msmq://keithelder.net/private/LogEntries"
  22:      binding="netMsmqBinding" bindingConfiguration="msmqBinding" name="msmq"
  23:      contract="KeithElder.ILogMsmqService" />
  24:     <endpoint binding="mexHttpBinding" bindingConfiguration="" name="wsdl"
  25:      contract="IMetadataExchange" />
  26:    </service>
  27:   </services>
  28:         <behaviors>
  29:             <serviceBehaviors>
  30:                 <behavior name="LogEntriesBehavior">
  31:                     <serviceMetadata httpGetEnabled="true"/>
  32:                     <serviceDebug includeExceptionDetailInFaults="false"/>
  33:                     <serviceThrottling/>
  34:                 </behavior>
  35:             </serviceBehaviors>
  36:         </behaviors>
  37:     </system.serviceModel>

The endpint is set to net.msmq://keithelder.net/private/LogEntries.  This means that messages received on this endpoint will be stored in the private queue logEntries.  Once stored, the messages call the method written in WCF to take the message from the queue and process it.  Really, this is all slick when it works and opens the door for a lot of scenarios. 

Obviously we aren’t supposed to be getting this error, especially about a queue WE AREN”T EVEN USING!

By the way, when this error occurs, it kicks off the jitdebugger and will slow your machine to a crawl.  It isn’t something fun to debug, trust me.

The Fix

If you have run into this error, and find this entry on my blog somehow, here is the workaround for this.  Again, this is a workaround, not optimal by any means.  There are two things you have to do (at least as far as I can tell with my testing).

Fix #1

Do not have any additional private queues other than the queue required for your service.  Obviously this has problems because other applications may be writing to private queues as well. 

Fix #2

Deploy the application to a virtual directory in IIS.  This is where I first started noticing the problem because I couldn’t get our test server to work when I deployed the code even though it worked on my machine. 

Fix #3 (added 12/3/2008)

Support from Microsoft said you can do one or the other, but I am still getting errors in the event log even though the application is deployed in a virtual directory with two private queues.  If I delete all queues and have it deployed in a virtual directory things are happy.  Changing the endpoint to the name of the path of the service does fix the problem and allows multiple queues to be on the machine.  I’ve tested this extensively.  Here’s an example:

image

So instead of having the queue named “LogEntries”, changing it to “myvirtualapp/service.svc” fixed the problem and things work normally.

Official Fix

I was told by Microsoft Support this bug would be fixed in the next service pack and also the .Net Framework 4.0. 

Creating a REST WCF Service From an Existing XSD Schema

Posted by Keith Elder | Posted in .Net, Asp.Net, WCF, Web Services | Posted on 02-11-2008

5

A reader of this blog sent me an email asking the following question:

“I have an XSD that I am required to use to export my company’s data. How can I use that XSD and return data to them in a web method? I should be able to return a data set with the information formatted the way the XSD defines but I have no idea how to do that. Any ideas would save me a ton of time and grief!”

Turns out this is a really good question, and I think one a lot of developers struggle with primarily because the majority of developers are scared of XSD schemas.  Hopefully I can change that.  An XML Schema is really simple and it is your friend. 

What is an XSD or Xml Schema Definition?

An XML Schema describes the structure of an XML document.

That’s it, see, it isn’t that hard after all!

As a developer think of an XSD the same way you would when creating business rules to validate objects before storing them into a database.  Some items in objects cannot be null, some can.  Some need to have their data formatted (email address for example) and others need to not exceed certain lengths, etc. 

When dealing with an XML document, we need to apply the same type of rules and this is where the XSD comes in.  Once we have an XSD to describe an XML document we can guarantee any XML data we receive conforms to these rules.

Ok, enough intro, let’s get coding.

The Schema

In the case of the reader’s question, an XSD schema already existed.  To save time, I’ve taken then general idea of the schema I was sent and slimmed it down for simplicity sakes.  The schema represents an XML document that will contain job listings. Here is a view of the schema from the schema explorer in Visual Studio as well as the schema itself (again slimmed down).

   1: <xsd:schema
   2:   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   3:   targetNamespace="http://keithelder.net/Jobs"
   4:   xmlns:xs="http://keithelder.net/Jobs">
   5:  
   6:   <xsd:complexType name="JobListing">
   7:     <xsd:sequence>
   8:       <xsd:element maxOccurs="unbounded" minOccurs="1" name="job" type="xs:Job" />
   9:     </xsd:sequence>
  10:   </xsd:complexType>
  11:  
  12:   <xsd:complexType name="Job">
  13:     <xsd:sequence>
  14:       <xsd:element maxOccurs="1" minOccurs="1" name="Title"  type="xsd:string"></xsd:element>
  15:       <xsd:element maxOccurs="1" minOccurs="1" name="Description" type="xsd:string"></xsd:element>
  16:       <xsd:element maxOccurs="1" minOccurs="1" name="Location" type="xs:Address"></xsd:element>
  17:       <xsd:element minOccurs="0" maxOccurs="1" name="PostingDate" type="xsd:date"></xsd:element>
  18:       <xsd:element minOccurs="0" maxOccurs="1" name="CloseDate" type="xsd:date"></xsd:element>
  19:       <xsd:element minOccurs="0" maxOccurs="1" name="Benefits" type="xsd:string"></xsd:element>
  20:       <xsd:element maxOccurs="1" minOccurs="1" name="Salary"  type="xsd:string"></xsd:element>
  21:       <xsd:element maxOccurs="1" minOccurs="0" name="JobType" type="xs:JobType"></xsd:element>
  22:       <xsd:element minOccurs="0" maxOccurs="1" name="Function" type="xs:JobFunction"></xsd:element>
  23:       <xsd:element minOccurs="0" maxOccurs="1" name="Category" type="xs:JobCategory"></xsd:element>
  24:     </xsd:sequence>
  25:   </xsd:complexType>
  26:  
  27:   <xsd:simpleType name="JobType">
  28:     <xsd:restriction base="xsd:string">
  29:       <xsd:enumeration value="full-time"></xsd:enumeration>
  30:       <xsd:enumeration value="part-time"></xsd:enumeration>
  31:       <xsd:enumeration value="contractor"></xsd:enumeration>
  32:     </xsd:restriction>
  33:   </xsd:simpleType>
  34:  
  35:   <xsd:complexType name="Address">
  36:     <xsd:sequence>
  37:       <xsd:element minOccurs="0" maxOccurs="1" name="Street" type="xsd:string"></xsd:element>
  38:       <xsd:element minOccurs="0" maxOccurs="1" name="City" type="xsd:string">   </xsd:element>
  39:       <xsd:element minOccurs="0" maxOccurs="1" name="Country" type="xsd:string"></xsd:element>
  40:     </xsd:sequence>
  41:   </xsd:complexType>
  42:  
  43:   <xsd:simpleType name="JobCategory">
  44:     <xsd:restriction base="xsd:string">
  45:       <xsd:enumeration value="Automotive"/>
  46:       <xsd:enumeration value="Banking"/>
  47:       <xsd:enumeration value="Construction"/>
  48:       <xsd:enumeration value="Internet"/>
  49:       <xsd:enumeration value="Retail"/>
  50:       <xsd:enumeration value="Services"/>
  51:     </xsd:restriction>
  52:   </xsd:simpleType>
  53:  
  54:   <xsd:simpleType name="JobFunction">
  55:     <xsd:restriction base="xsd:string">
  56:       <xsd:enumeration value="Chief Peanut Butter Spreader"/>
  57:       <xsd:enumeration value="I ran the whole ship"/>
  58:       <xsd:enumeration value="Other"/>
  59:     </xsd:restriction>
  60:   </xsd:simpleType>
  61: </xsd:schema>

image

Once we have a schema defined like this we can generate code to be used for a service.  We have a tool at our disposal that is available within the Visual Studio Command Prompt called XSD.exe.  This executable does a lot of things but one thing it can do is generate code from an XML Schema Definition. 

When generating from the XSD file I was sent there was a problem with it.  Here is the walk through of that story so you can follow along. 

image

When I first tried this on the reader’s original XSD I got an error:

Warning: cannot generate classes because no top-level elements with complex type were found.

What does this mean?  Well, look at the screen shot of the XML Schema Explorer above.  Do you see the <> green icons?  Well those represent an XML Element.  An element is a fancy name for an XML tag like:  <Cows>Bramar</Cows> 

Let me roll this up and take another screen shot so you can start to see the problem (i have to hit my magic number of 12 screen shots anyway 🙂 ).

image

See the problem?  There isn’t an element in this schema (no green <> thingy).  What this means is we have a schema which just lists complex types of elements and enumerations.  There isn’t any “xml” in this schema.  The fix is simple though.  Add an element to the schema. 

   1: <xsd:element name="JobListing" type="xs:Job" />

Now we have a green thingy icon which means this XSD contains at least one element.  Basically think of the JobListing element as the root element.

image

Now that we have an element we can generate a C# class file from this XSD:

image

The code generated is about 350 lines so I’m not going to include it in the article.  There are some nice things happening for us when the C# classes are generated using xsd.exe. For starters the enumerations in the XSD are turned into C# enumerations.  The classes are marked serializable and they have the appropriate XML attributes on the properties to serialize these objects into XML.  This is a good thing since it means we didn’t have to create it.  Code generation is your friend.  Now that we have C# objects we can serialize these to XML easily. 

The Service

The first thing we need to do is create the WCF service.  For this example I chose to create a WCF Service Application in Visual Studio 2008.  After the project is initialized, the first thing we need to do is define the contract for the service.  In other words, what is coming in and going back out.  Since we have generated our code using the XSD utility we are going to use the XmlSerializer with our service.  The reason is this will make sure our XML formatted the way we intended.  While we are at it, I’ve made the service a RESTful type of service.  Here is the contract.

   1: [ServiceContract]
   2: public interface IJobService
   3: {
   4:  
   5:     [OperationContract]
   6:     [XmlSerializerFormat]
   7:     [System.ServiceModel.Web.WebGet(UriTemplate="/jobs/{type}", RequestFormat=WebMessageFormat.Xml)]
   8:     List<Job> GetJobListings(string type);
   9: }

The contract above has one method GetJobListings().  This method has two additional attributes.  One, the attribute to mark the method to serialize using the XmlSerializer and two the attribute to turn the method into a RESTful service.  In other words our service can be accessed like this:

http://localhost/service.svc/jobs/full-time

Now that the contract is setup, we just need a class to implement this contract on.  Here’s a quick and dirty implementation.

   1: public class Service1 : IJobService
   2: {
   3:  
   4:     #region IJobService Members
   5:  
   6:     public List<Job> GetJobListings(string type)
   7:     {
   8:         return GetJobs();
   9:     }
  10:  
  11:     private static List<Job> GetJobs()
  12:     {
  13:         var jobs = new List<Job>();
  14:         jobs.Add(new Job { JobType= JobType.parttime, Category = JobCategory.Banking, Benefits= "You are on your own.", Description="I did something" });
  15:         jobs.Add(new Job { JobType= JobType.fulltime, Category = JobCategory.Banking, Benefits= "You get something." });
  16:         jobs.Add(new Job { JobType= JobType.contractor, Category = JobCategory.Banking, Benefits= "Times are tuff, deal with it." });
  17:         jobs.Add(new Job { JobType= JobType.fulltime, Category = JobCategory.Banking, Benefits= "How does $700 billion sound?" });
  18:         return jobs;
  19:     }
  20:     #endregion
  21: }

Now all we have left is to get this working is to configure WCF to support our RESTful implementation.  In order to do this we are going to use the webHttpBinding.  Here is the WCF configuration to implement our RESTful service.

   1: <system.serviceModel>
   2:   <bindings>
   3:     <webHttpBinding>
   4:       <binding name="rest" />
   5:     </webHttpBinding>
   6:   </bindings>
   7:   <services>
   8:     <service behaviorConfiguration="WcfService1.Service1Behavior"
   9:      name="WcfService1.Service1">
  10:       <endpoint address="mex" binding="mexHttpBinding" name="wsdl"
  11:        contract="IMetadataExchange" />
  12:       <endpoint address="" behaviorConfiguration="NewBehavior" binding="webHttpBinding"
  13:        bindingConfiguration="" name="web" contract="WcfService1.IJobService" />
  14:     </service>
  15:   </services>
  16:   <behaviors>
  17:     <endpointBehaviors>
  18:       <behavior name="NewBehavior">
  19:         <webHttp />
  20:       </behavior>
  21:     </endpointBehaviors>
  22:     <serviceBehaviors>
  23:       <behavior name="WcfService1.Service1Behavior">
  24:         <serviceMetadata httpGetEnabled="true" />
  25:         <serviceDebug includeExceptionDetailInFaults="false" />
  26:       </behavior>
  27:     </serviceBehaviors>
  28:   </behaviors>
  29: </system.serviceModel>

That’s it, we are all setup.  Now all we have to do is launch the service and browse to the URL we outlined earlier to get our results.

image

This may seem like a lot of steps but it really isn’t.  I encourage you to take this example and play with it.  You can download the solution below.

Download Solution WcfService.zip

WCF vs ASMX WebServices

Posted by | Posted in .Net, WCF | Posted on 17-10-2008

77

This question comes up a lot in conversations I have with developers. 

“Why would I want to switch to ASMX services?”

One analogy I have come up with to explain the difference between the two is an airplane analogy. 

I associate ASMX services with a Cessna 150 cockpit and I associate WCF services with a 747 Jumbo Jet cockpit. 

image

I’ll be honest, I’ve never flown a plane but I think I’m smart enough to crank a Cessna 150 if I had to figure it out.  The above screen shot is a real Cessna 150 cockpit.  There are a few gauges, some knobs, etc.  Really not that bad.  And I think this explains ASMX really well.  ASMX services are easy to crank and jump start.  Think about it.  We take an existing Asp.Net website and add a file called “asmx”.  Any method we attribute with [WebMethod] magically turns into a service.  Objects we pass in and pass out that have public getters and setters will be serialized into XML.

   1: [WebMethod]
   2: public string FlyToDestination(Location loc)
   3: {
   4:     // up up and away
   5: }

The barrier to cranking and getting going with an ASMX service is really simple.  And because it is simple, we’ve adopted them on a massive scale.  Let’s turn our attention to WCF.

image

WCF is a jack of all trades.  Think of it like a large plane that can repurposed for hauling passengers, hauling cargo, military use or whatever.  We are dealing with a plane but it is all about how that plane is configured.  Because things can be configured a lot of ways with the WCF 747 plane there are a lot more buttons in the airplane cockpit as compared to the Cessna 150.  The flip side of this is that once you understand how to configure WCF you’ve got one of the most versatile plane in the world!

From a developers stand point, the same logic or code written in an ASMX service works in WCF.  The code between the curly braces is the same.  The bottom line in either case is a method gets called and an object gets passed in (we call this a message when talking about services).  The difference in WCF is we program to a specific contract.  Here’s the same example above done in WCF.

   1: [ServiceContract]
   2: public interface IAirportService
   3: {
   4:     [OperationContract]
   5:     string FlyToDestination(Location loc);
   6: }
   7:  
   8: public class AirportService : IAirportService
   9: {
  10:     
  11:     public string FlyToDestination(Location loc)
  12:     {
  13:         // up up and away
  14:     }
  15: }

Instead of attributing the specific method like we do in ASMX, in WCF we attribute the Interface.  Programming to an Interface is a good thing and the reason this is done is to loosely couple the host of the service from the implementation.  Doing this opens the door for hosting WCF services not only in IIS but console apps, Winforms, WPF, etc.  Since we’ve programmed to a contract (which is just an Interface), any class that implements the Interface can be a service.  This is powerful.  This is powerful because how we expose this service is up to us (again it is all about configuration).  Because we can expose our AirportService a number of ways we can see that WCF provides developers the ability to write code once and repurpose their code as needed. 

image

Exposing a WCF service requires a little more training from this point forward ( just like flying a 747) because we have to understand how to configure the service.  It is this little bit of extra effort required to understand WCF configuration that stops a lot of developers from using WCF.  This is a shame because when the developer using ASMX wants to guarantee message delivery, participate in transactions, or use binary serialization instead of XML, they’ve got a lot of work ahead of them as compared to WCF.   

The moral of the story is ASMX is simple and because it is simple, it isn’t very powerful.  Take the time to learn about WCF because this is the future of the .Net platform, thus it will be time wisely spent.  If you’ve been holding back I encourage you to step out of your old ASMX habits and learn the ways of WCF. 

If you would like to dig a little deeper with WCF I encourage you to check out my “Demystifying Windows Communication Foundation” power point.  In there you’ll find a lot more details about how WCF works.

http://keithelder.net/Presentations/DemystyfyingWCF/DemystifyingWindowsCommunicationFoundation.ppt

Happy messaging.

Balancing Readability and New Syntax Sugar in C# 3.0

Posted by Keith Elder | Posted in .Net | Posted on 08-10-2008

9

I’ve been struggling with something the past several weeks since I’ve been heads down programming some new features at work.  It is the first time in awhile I’ve really had a chance to dig in and use the latest and greatest features in .Net 3.5 and C# 3.0 in a production environment.  Like most developers, I find myself struggling to remember to use the new features in the language since I’ve been doing things the same way for years.    I have to constantly remind myself that I could do things differently than I’ve done them before.  Anonymous methods, automatic properties, lambda expressions, LINQ and other new features just to mention a few.

Here’s what I’m struggling with.  Where do you draw the line in the sand?  At which point do you say “Just because you can doesn’t mean you should?”.  In other words, how do you balance readability versus using new language features.  The absolute simplest example I’ve run across recently is as follows. 

I needed to get the first IP4 Address of the current machine.  A computer can have multiple addresses (not only IP4 but IP6 addresses too).  To start with I already had a method that would validate an IP4 address.  Here’s the method. 

   1: public static bool ValidateIP4Address(string ipAddress)
   2: {
   3:     string ipRegex = @"^(2[0-5]{2}|2[0-4]\d|1\d{2}|[1-9]\d|\d)\." +
   4:                     @"(2[0-5]{2}|2[0-4]\d|1\d{2}|[1-9]\d|\d)\." +
   5:                     @"(2[0-5]{2}|2[0-4]\d|1\d{2}|[1-9]\d|\d)\." +
   6:                     @"(2[0-5]{2}|2[0-4]\d|1\d{2}|[1-9]\d|\d)(?:/(3[012]|[12]\d|\d))?$";
   7:     Regex regex = new Regex(ipRegex);
   8:     return regex.IsMatch(ipAddress);
   9: }

As I solved this problem I knew what I wanted to do. I wanted to loop through all IP Addresses on the machine and take the first IP4 Address.  The solution is simple but it can be done numerous ways, especially when you start using new C# 3.0 features.  I started writing the code and here’s what I came up with using a Lambda expression (a new C# feature).

   1: private static void GetIpUsingLambda()
   2: {
   3:     string ipAddy = Dns.GetHostAddresses(Dns.GetHostName()).First(i => ValidateIP4Address(i.ToString())).ToString();
   4:     Console.WriteLine(ipAddy);
   5: }

After writing it I checked my unit test and it passed.  I then switched gears in my brain and starting looking at it as if I had seen it for the first time.  Sure it looks cool and complicated but what the heck is it doing?  There is a plethora of parentheses, nested methods and dots.  Honestly, it isn’t easy to read.  But it is in one line!

Then I rewrote it like this to hopefully make it more “readable”.

   1: private static void GetIpUsingLambda()
   2: {
   3:     string ipAddy = Dns.GetHostAddresses(
   4:                         Dns.GetHostName()
   5:                         ).First(
   6:                             i => ValidateIP4Address(i.ToString())
   7:                         ).ToString();
   8:     Console.WriteLine(ipAddy);
   9: }

Is it more readable?  I don’t know to be honest.  I’m struggling with it myself.  It is only marginally easier to read since it is somewhat broken up by the parentheses.

I decided to then write it “old school” just for comparison. 

   1: private static void GetIpOldWay()
   2:   {
   3:       IPAddress[] addresses = Dns.GetHostAddresses(Dns.GetHostName());
   4:       foreach (IPAddress addy in addresses)
   5:       {
   6:           if (ValidateIP4Address(addy.ToString()))
   7:           {
   8:               Console.WriteLine(addy.ToString());
   9:               return;
  10:           }
  11:       }
  12:   }

Line #3 gets all IP addresses on the machine.  Then we loop through each one calling ValidateIP4Address().  If we find a match we stop on the first one.

Here’s the question, which one is more readable and understandable at first glance, the lamba or the old way?  I’ll let you decide.

Of course we could take the GetIpOldWay() and throw in some new C# features using the keyword “var”. 

   1: private static void GetIpUsingVar()
   2:    {
   3:        var addresses = Dns.GetHostAddresses(Dns.GetHostName());
   4:        foreach (var addy in addresses)
   5:        {
   6:            if (ValidateIP4Address(addy.ToString()))
   7:            {
   8:                Console.WriteLine(addy.ToString());
   9:                return;
  10:            }
  11:        }
  12:    }

Really there isn’t much difference.  It is less typing for me the developer but that’s about it.  Not much difference.

One more way we could write this is using LINQ.

   1: private static void GetIpUsingLinq()
   2:  {
   3:      var ipAddy = Dns.GetHostAddresses(Dns.GetHostName());
   4:      var foo = (from i in ipAddy
   5:                 where ValidateIP4Address(i.ToString())
   6:                 select i).First();
   7:      
   8:      Console.WriteLine(foo);
   9:  }

Interesting.

For me the LINQ version above is the most interesting and I think the simplest to understand for someone looking at the problem for the first time.  I think it expresses more of the “intent” of what I was doing.  It is more typing compared to the Lamba expression in the GetIpUsingLambda() but it is easier on the eyes. 

After writing all four variations on this simple real world problem I think I like the LINQ example the best.  I am positive I’m not the only person out there struggling with this and I think it is a discussion that is happening in developers minds.  Of course this whole discussion is just personal preference but I think maintaining readable code is something we should strive for in our systems.  I also think if another developer had to change or modify the Lambda expression they’d spend a lot more time figuring out what it is doing compared to other samples, especially the LINQ example even though we are using new language features.

For developers throwing around Lambda expressions like they are candy I would question if it is truly the best and most maintainable code.  Just because you can doesn’t mean you should in all cases.  Definitely something to think about.  Feel free to weigh in, I’m curious as to which example you find the easiest to understand.

UPDATE:

Several of us on IRC continued this conversation there yesterday and I wanted to capture some of that conversation.

Jay Wren brought up using AddressFamily which in this example would be faster.  Here is a rewritten example using the Lambda expression using the AddressFamily enumeration.

   1: private static void GetIpUsingLambda()
   2: {
   3:     string ipAddy = Dns.GetHostAddresses(Dns.GetHostName()).Where(i => i.AddressFamily == AddressFamily.InterNetwork).First().ToString();
   4:     Console.WriteLine(ipAddy);
   5: }

Nate Kohari added onto Jay’s work and took on the challenge of readability by suggesting an extension method of IsIP4() for the IPAddress. 

   1: public static class Extensions
   2: {
   3:     public static bool IsIP4(this IPAddress i)
   4:     {
   5:         return i.AddressFamily == AddressFamily.InterNetwork;
   6:     }
   7: }

Adding the extension method would then allow the Lambda and the LINQ example to really flow.  They would now look like this.

   1: private static void GetIpUsingLambdaWithExtension()
   2: {
   3:     string ipAddy = Dns.GetHostAddresses(Dns.GetHostName()).Where(i => i.IsIP4()).First().ToString();
   4:     Console.WriteLine(ipAddy);
   5: }

   1: private static void GetIpUsingLinqExtension()
   2: {
   3:     var foo = (from i in Dns.GetHostAddresses(Dns.GetHostName())
   4:                where i.IsIP4()
   5:                select i).First();
   6:     
   7:     Console.WriteLine(foo);
   8: }

Now we are truly getting somewhere balancing the new features in C# 3.0 and readability.   This final LINQ version is the winner in my book although the Lambda example makes my geek senses start to tingle.

Like this article? kick it on DotNetKicks.com

Technorati Tags: