The mysteries of software development and networking... RSS 2.0



 Tuesday, June 02, 2009

I’m playing around with code generation using Visual Studio 2008 T4 and I needed to pull in some data. Easiest way to create the data is using Excel and then pull it into a dataset. Using the right connection string this becomes very easy.

The code below shows how to select the data from a worksheet.

public class Excel2007Reader

{

    private static string BuildExcelConnection( string filename )

    {

        return @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filename + @";Extended Properties=""Excel 12.0;HDR=YES;""";

    }

 

    public static DataSet Read( string filename, string worksheet, string range, string tableName )

    {

        DataSet result = new DataSet();

        string connectionString = BuildExcelConnection( filename );

        string select = @"SELECT * FROM [" + worksheet + "$" + range + "]";

        using ( OleDbConnection conn = new OleDbConnection( connectionString ) )

        {

            conn.Open();

            using ( OleDbCommand cmd = new OleDbCommand( select, conn ) )

            {

                OleDbDataAdapter da = new OleDbDataAdapter( cmd );

                da.Fill( result, tableName );

            }

            conn.Close();

        }

        return result;

    }

}

Tuesday, June 02, 2009 12:52:32 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | C# | Team System
 Monday, June 01, 2009

In our Maine Microsoft Certification Study Group we recently had a discussion about using regular expression. Today I found myself writing a RegEx to check for illegal characters in a formula (string). I thought I’d share the solution:

private bool FormulaContainsIllegalCharacters( string formula )

{

    bool result = false;

    try

    {

        Regex r = new Regex( @"(!)|(@)|(#)|(\$)|(%)|(&)" );

        result = r.Match( formula ).Success;

    }

    catch { } // ignore any regular expressions errors -> return false

    return result;

}

In my case I’m not interested in handling exceptions. If a technical error occurs I will accept the input. Notice that I needed to put a “\” before the $ sign, since the $ is a reserved character marking the end of a line.
I don’t need to put each character in “( )” brackets, but for personal preference I just find it easer to read.

Monday, June 01, 2009 9:18:40 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | C#
 Wednesday, May 27, 2009

Another little extension method. This one allows easy rounding to a specific number of decimals:

double d = 0.66782423;
string s = d.ToString(3);  // s = “0.668”

This is done by the following method:

 

public static class DoubleExtension

{

    public static string ToString( this double value, int decimals )

    {

        StringBuilder format = new StringBuilder( "0" );

        if ( decimals > 0 )

        {

            format.Append( "." );

        }

        for ( int i = 0; i < decimals; i++ )

        {

            format.Append( "0" );

        }

        return value.ToString( format.ToString() );

    }

}

Wednesday, May 27, 2009 1:47:25 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | C#

Back when .NET 1.1 was cool people would often use DateTime.MinValue to indicate that a date was actually empty. With .NET 2.0 can the Nullable<T> which allows you to create a nullable datetime. Ofcourse there is still plenty of old code out there, so when adding new code you may need to convert DateTime.MinValue to null. With extensions methods (.NET 3.5) you can implement an elegant solution.

The code below will allow you to write this:

DateTime old = DateTime.MinValue;

DateTime? current = old.ToNullable();

This is achieved with the following extension method:

public static class DateTimeExtension
{
    /// <summary>
    /// Examine the value of the DateTime, if the value is equal to DateTime.MinValue
    /// then the result is null, otherwise the supplied value is returned.
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static DateTime? ToNullableDateTime( this DateTime value )
    {
        if ( value == DateTime.MinValue )
        {
            return null;
        }
        else
        {
            return value;
        }
    }
}

Wednesday, May 27, 2009 9:55:29 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
 Friday, April 24, 2009

Today I had to fix a bug in some code involving a program creating multiple files where each file needed to have a unique machine generated filename. I was building my own unique name using the DateTime.Now.Ticks().ToString() as part of the name. Apparently on some machines the Ticks are not going to be unique. So I looked at the Path.GetTempFile() method, but I needed to control the location of the temporary files. Next stop: Path.GetRandomFileName().

Documentation:
The GetRandomFileName method returns a cryptographically strong, random string that can be used as either a folder name or a file name. Unlike GetTempFileName, GetRandomFileName does not create a file. When the security of your file system is paramount, this method should be used instead of GetTempFileName.

Works great!

Friday, April 24, 2009 10:09:51 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | C#
 Monday, April 06, 2009

Yeah, my last Training Kit is shipping!

Get a copy now at Amazon: http://tinyurl.com/dxwdz5

Monday, April 06, 2009 2:21:19 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | C# | General | LINQ
 Monday, March 23, 2009

The documentation doesn't specifiy it but in the Entity Framework when you call ObjectContext.SaveChanges the update is 'wrapped' in a transaction.

NorthwindIBModel model = new NorthwindIBModel();

Guid id = Guid.NewGuid();

model.AddToCustomer(new Customer() { CustomerID = id, ContactName = "Andrew", CompanyName = "Northwind Traders" });
model.AddToCustomer(new Customer() { CustomerID = id, ContactName = "Aikido", CompanyName = "Northwind Traders " });

model.SaveChanges(); // exception duplicate key - transactional -> no changes to the database

Monday, March 23, 2009 9:45:21 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | C# | LINQ

Today I ran into a problem where apparently the registry settings for Visual Studio got messed up since I was no longer able to add a data connection in my Server Explorer, nor create an Entity Framework model from a database. Time to reset Visual Studio command(o) style.

To reset Visual Studio you open the Visual Studio Command Prompt and type:

devenv /resetsettings

And life is good...

Monday, March 23, 2009 9:17:29 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Saturday, January 17, 2009
 Thursday, November 27, 2008

I wanted to add a context menu to a DataGridView, allowing the user to perform an action on a specific row. However, right clicking in a DataViewGrid does not change the selected row. This can be achieved by adding the following code to the CellMouseDown event (the name of my grid is dgvWorkflows):

private void dgvWorkflows_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
    if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
    {
        dgvWorkflows.CurrentCell = dgvWorkflows.Rows[e.RowIndex].Cells[e.ColumnIndex];
    }
}

Thursday, November 27, 2008 2:20:46 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
 Wednesday, November 12, 2008

We had an interesting workflow issue the other day. For some inexplicable reason our state machine workflow was terminated. After digging around in the database trying to reconstruct what might have happened we finally figured it out:

We have a transaction scope activity which sends an update to the database. The update failed and the exception cause the fault handler on the activity to kick in. The fault handler changed the state of the state machine to custom state called 'TechnicalError'. We explicitly modeled this state because it allows our administrators to recover a workflow from a technical error and essentially restart the workflow. In the InitializeState of the 'TechnicalError' state we wanted to update some data in the database. This also failed, since the cause of the original error was that we had lost connectivity to our database.

Next?

Since we had no fault handler on this database action the workflow crashed. Since connectivity to our workflow persistence database was also lost we now have a situation where the workflow in memory is inconsistent with the data in our line of business application database and is also inconsistent with the last persisted state in the workflow persistence database.

Next?

The workflow runtime never crashed several minutes later the workflow persistence database came back online and the in memory state of the workflow (which was terminated) was sync-ed with the workflow persistence database. However, our line of business database was never updated. The timestamp on the updates in the workflow persistence database where minutes apart from the last updates in the line of business database, which made it hard to reconstruct what had happened.

Solution?

We now have a fault handler on the initialize state of the 'TechnicalError' state. If the workflow persistence database OR the line of business application database is unavailable then a delay is introduced. And the workflow retries to transition to the TechnicalError state. This way the workflow will never ever terminate. The only scenario left is where the machine running the workflow is turned off. If this happens then the workflow will recover from it's last save point and life should be good.

Wednesday, November 12, 2008 1:51:34 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | WF
 Sunday, October 26, 2008

After discovering that the LINQ to SQL Designer will only support tables from a single data source I set out to manually implement a cross database query using two data contexts.

The result is the following query which joins orders in the OrderDB to products in the VideoGameStoreDB.

public List<Order> FindOrders( string typename )

{

    try

    {

        var productdb = new VideoGameStoreDBDataContext();

        var orderdb = new OrderDBDataContext();

 

        var query  = from o in orderdb.Orders

                     join p in productdb.Products on o.ProductID equals p.ProductID

                     where p.ProductType.ProductTypeName.Contains( typename )

                     select o;

 

 

        return query.ToList();

    }

    catch ( Exception exception )

    {

        Trace.WriteLine( exception );

        throw;

    }

}

 

LINQ to SQL is unable to resolve this query, even though both databases sit on the same server. The compiler will however not warn you not to do this, instead a runtime exception with message 'The query contains references to items defined on a different data context.' occurs.

In a scenario like this the only solution appears to be to write a stored procedure which can perform the cross database query and use that stored procedure from a data context.

Sunday, October 26, 2008 5:16:21 AM (Eastern Standard Time, UTC-05:00)  #    Comments [1] -
C# | LINQ

The LINQ to SQL Designer supports just one connection, which makes sense since a LINQ DataContext is scoped to one connection. The designer does offer to change the connection string for you, but I guess making cross database queries is not possible using the designer.

The following message is what you get when dragging a table from a second data source onto the design surface.

image

Sunday, October 26, 2008 4:25:01 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | LINQ

I just discovered that the LINQ to SQL Designer does not support User Defined Types.

The following message appears when I try and add a table from my database to my design surface. The Customer table in question has a UDT named 'Point' to specify the GPS location of the business.

image

Sunday, October 26, 2008 4:17:42 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | LINQ
 Saturday, October 25, 2008

With LINQ to SQL you can choose to use an external mapping file, allowing you to map SQL statements to CLR objects (also referred to as POCO, Plain Old CLR Objects). Doing so means you do not need to adorn your classes with attributes.
Here's a little sample of how to do this.

public class Supplier
{
    public int ID { get; set; }
    public string Name { get; set; }
}
 
public List<Supplier> GetSupplier( string name )
{
    SqlConnection conn = new SqlConnection( cConnectionString );
 
    XmlMappingSource xms = XmlMappingSource.FromUrl( @"mapping.xml" );
 
    var db = new DataContext( conn, xms );
 
    Table<Supplier> Suppliers = db.GetTable<Supplier>();
 
    var query = from s in Suppliers
                where s.Name == name
                select s;
 
    return query.ToList();
}
 
 

The XML can be as simple as:

<?xml version="1.0" encoding="utf-8"?>
<Database Name="VideoGameStoreDB"
          xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
  <Table Name="dbo.Supplier" Member="Supplier">
    <Type Name="Supplier">
      <Column Name="SupplierID" Member="ID" />
      <Column Name="SupplierName" Member="Name"  />
    </Type>
  </Table>
</Database>
 

You can use SQLMetal (a command line tool included with Visual Studio) to generate a mapping file.

Saturday, October 25, 2008 8:27:35 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | LINQ
 Friday, August 22, 2008

The article wrote for Code Magazine, named 'From Delegate to Lambda', about understanding the transition from delegates to lambdas has been published in the September issue and can also be found online at: http://www.code-magazine.com/Article.aspx?quickid=0809081.

Friday, August 22, 2008 12:26:32 AM (Eastern Standard Time, UTC-05:00)  #    Comments [4] -
C#
 Friday, August 01, 2008

If you're using the xsd.exe tool to generate C# code from an XML Schema you'll find that an attribute defined as an integer is generated into a string field.

The reason is listed on MSDN:

The xs:integer type is specified as a number with no upper or lower bound on its size. For this reason, neither XML serialization nor validation map it to the System.Int32 type. Instead, XML serialization maps the xs:integer to a string while validation maps it to the Decimal type that is much larger than any of the integer types in the .NET Framework.

Friday, August 01, 2008 6:52:45 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
 Wednesday, June 11, 2008

My article on combining AIM Call Out with geocoding a phone number to display the location of the person you're trying to call has gone live on the AOL Developer Network.

I think it turned into a very cool sample application.

Dial a number and see the location of the person you're calling!

Wednesday, June 11, 2008 10:56:10 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | AOL | C#
 Wednesday, May 21, 2008

Anyone familiar with building applications using .NET Remoting (in .NET 2.0) knows that the DataSet and DataTable classes have a property called RemotingFormat. This could be set to either XML or Binary where Binary would give you a performance boost since it is more compact.

Windows Communication Foundation does not use this property at all. The service binding dictates the serialization format, no matter what you set the RemotingFormat property to be, even if your using a NetHttpBinding.

The following configuration will setup a service to use .NET Binary formatting over Http:

<system.serviceModel>
  <bindings>
    <customBinding>
      <binding name="NetHttpBinding">
        <reliableSession />
        <compositeDuplex />
        <oneWay  />
        <binaryMessageEncoding  />
        <httpTransport />
      </binding>
    </customBinding>
  </bindings>
  <services>
    <service behaviorConfiguration="ServiceBehavior" name="MyService">
      <endpoint address="" binding="customBinding"
        bindingConfiguration="NetHttpBinding" name="HttpBinding" contract="IService" />
      <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="ServiceBehavior">
        <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
        <serviceMetadata httpGetEnabled="true"/>
        <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
        <serviceDebug includeExceptionDetailInFaults="false"/>
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

So even if your service looks something like this:

public DataSet GetData()
{
    DataSet ds = BuildDataSet();   // retrieve some data here
    ds.RemotingFormat = SerializationFormat.Xml;
    return ds;
}

The DataSet will still get serialized as a .NET binary as defined in the binding ('binaryMessageEncoding').

Wednesday, May 21, 2008 4:04:18 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | WCF
 Tuesday, May 13, 2008

The article I wrote about building a Voice over IP .NET application using AIM Call Out and the AOL Open Voice API has just gone live on the AOL Developer Network. Read it here.

Tuesday, May 13, 2008 2:11:26 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | AOL | C#
 Saturday, May 10, 2008

I just wasted some of my time figuring out how to do collection initialization in VB9.

C#3.0 has a new feature called collection initializer and according to a (somewhat older) post by Scott Guthrie, VB9 was slated to have it too. I guess it got cut somewhere.

Anyway this is what collection initializers look like in C#3.0:

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

The closest thing in VB9 would be to use array initializers:

Dim numbers As New List(Of Integer)

Dim temp() As Integer = {1, 2, 3, 4, 5}

numbers.AddRange(temp)

Saturday, May 10, 2008 9:22:46 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | VB.NET
 Friday, May 09, 2008

Okay, so you read the title of this post. Perhaps you're expecting huge amounts of code, but guess what. As it turns out, this is so ridiculously easy. This will be a very short post.

Step one is to have a method that loads an RSS feed. WCF offers a new class called SyndicationFeed.

private SyndicationFeed Load( string url )

{

  XmlReader reader = XmlReader.Create( url );

  SyndicationFeed feed = SyndicationFeed.Load( reader );

  return feed;

}

 

The above method will take a url and use to load a feed. Now suppose I have a list of urls and I want to take all the items in all the feeds, sort them and use them to generate a new, aggregated feed. Sounds like a fair amount of work, right.

Here is the code:

 

private SyndicationFeed Aggregate( List<string> urls )

{

  var items = from url in urls

              from item in Load( url ).Items

              orderby item.PublishDate descending

              select item;

 

  SyndicationFeed feed = new SyndicationFeed( items );

  return feed;

}

 

Cool!

Friday, May 09, 2008 11:10:19 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | LINQ | WCF
 Friday, May 02, 2008

An important part of LINQ and C# 3.0 is the concept of deferred execution. What does this mean?

Let's have a look at the following code:

static void Main( string[] args )
{
   List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
   var evenNumbers = numbers.Select( x => ( x % 2 == 0 ) );
 

   foreach ( int i in evenNumbers )
   {
     if ( i == 6 )
         numbers.Add( 12 ); // add a number to the list of numbers
     Console.WriteLine( i );
   }
   Console.ReadLine();
}

public static List<int> Select( this List<int> numbers, Filter filter )
{
   List<int> result = new List<int>();
   foreach ( int i in numbers )
   {
      // call the filter method/delegate to see if this
      // number needs to be in the result
      if ( filter( i ) == true )
      {
         // if i matches the filter then add it to the result
         result.Add( i );
      }
   }
   return result;
}

In the code above the extension method 'Select' will apply a filter and return a subset of the original collection of numbers. When the numbers are printed we add the number '12' to the original collection. Since the Select method created a new collection with the subset we will not see the number 12 being printed to the console. If we want a more dynamic interaction we can rewrite the Select method to return an enumerator rather than a List.

public static IEnumerable<int> Select( this List<int> numbers, Filter filter )
{
    for ( int n = 0; n < numbers.Count; n++ )
    {
        if ( filter( numbers[n] ) == true )
        {
            // if numbers[n] matches the filter then yield the value
            yield return numbers[n];
        }
    }
}

The code above shows that instead of returning a List of numbers we now yield the value of each number as it passes through the filter. Now when we run the same Main we will see that the value '12' is included in our output.  If we put a breakpoint inside the application we can inspect the type of 'evenNumbers'.

As you can see it point to the Select methods and the Lambda has been compiled into an anonymous delegate. Rather than having a fixed result the Select method keeps being called until there are no more numbers being 'yielded'. You can preview the results by opening the 'Results View', but that will only provide a view of the iterator at that specific point in time.

Friday, May 02, 2008 1:33:43 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#

There are three key things that you need to understand in order to understand Lambda expressions in C#3.0.

1. Delegates,
2. Delegates,
3. ... delegates.

Since Lambda has come to town (or C#) I've discovered that a lot of people use delegates, but quite a few developers don't really know what a delegate is.
Understanding delegates is key to understanding what Lambdas are.

Wikipedia has the following definition:
A delegate is a form of type-safe function pointer used by the .NET Framework.  Delegates specify a method to call and optionally an object to call the method on. They are used, among other things, to implement callbacks and event listeners.

Here is my rule of thumb definition:
A delegate definition is a signature description for a method. 

It helps me to think of it as an interface definition for methods. An interface defines a number of methods, properties and/or events that need to be implemented by a class. You can use an interface definition as a type for a parameter in a method. Similarly a delegate definition defines the return type and parameters that a method needs to 'implement' (match is a better word). And a delegate can also be used as a type for a parameter in a method.

Still a lot of mumbo jumbo?
Okay, let’s take the journey from ‘traditional’ programming to C#3.0 syntax.

Consider the following program. Traditionally if you wanted to select a subset from a collection you would iterate over the collection and copy the items you're interested in into a new collection.

static void Main(string[] args)
{
    List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    List<int> evenNumbers = GetEvenNumbers( numbers );
    foreach ( int i in evenNumbers )
    {
        Console.WriteLine( i );
    }
    Console.ReadLine();
}

static List<int> GetEvenNumbers( List<int> numbers )
{
    List<int> result = new List<int>();
    foreach ( int i in numbers )
    {
        if ( i % 2 == 0 )
        {
            // if i matches the filter then add it to the result
            result.Add( i );
        }
    }
    return result;
}

The above code will select all the even numbers and print them to the console. Just a foreach and no delegates yet.

Instead of implementing a 'GetEvenNumbers' method, lets create a generic Select method. The method will be generic and will loop over the numbers and select only those which are selected by a filter. But how to define the filter? Lets first look at what we want our Select method to look like:

static List<int> Select( List<int> numbers, Filter filter )
{
    List<int> result = new List<int>();

    foreach ( int i in numbers )
    {
        // call the filter method/delegate to see if this
        // number needs to be in the result
        if ( filter( i ) == true )
        {
            // if i matches the filter then add it to the result
            result.Add( i );
        }
    }
    return result;
}

We want to create a method which takes a reference to another method as a parameter. This is what is known as a delegate. In our case the delegate needs to be a method which takes an Int32 as a parameter and returns a Boolean. In C# the delegate is defined using the 'delegate' keyword:

delegate bool Filter( int x );

Now, any method that takes an Integer as a parameter and returns a Boolean matches this delegate. So both methods shown below match the delegate:

static public bool IsEvenNumber( int number )
{
    return ( number % 2 == 0 );
}

 private bool IsOddNumber( int z )
{
    return ( z % 2 == 0 );
}

Notice that the name of the method does not matter, nor does the name of the parameter, nor does the accessibility of the method. Types of the parameter(s) and the return type is all that matters when it comes to matching with the delegate.

We can now rewrite Main to use the Select method:

static void Main( string[] args )
{
    List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
     List<int> evenNumbers = Select( numbers, IsEvenNumber ); 

    foreach ( int i in evenNumbers )
    {
        Console.WriteLine( i );
    }
    Console.ReadLine();
}

In C# 3.0 it has become easier to create a delegate, all you need to do is provide the name of the method, the compiler infers that you wish to create a delegate.

The old syntax was:

static void Main( string[] args )
{
    List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    List<int> evenNumbers = Select( numbers, new Filter( IsEvenNumber ) );

    foreach ( int i in evenNumbers )
    {
        Console.WriteLine( i );
    }
    Console.ReadLine();
}

The syntax is shorter, and arguably more readable, but hides the fact that a delegate is in fact an object and not just a reference as the new syntax seems to suggest.

Ok, now our IsEvenNumber method is quite simple, right? So to create a whole method for that method, which will likely never be reused is a little much. This is where anonymous delegates come in. Rather than specify a method which matches the delegate we can create an anonymous delegate which also matches with the Filter delegate.

Consider the following code:

static void Main( string[] args )
{
    List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    List<int> evenNumbers = Select( numbers, delegate( int x ) { return ( x % 2 == 0 ); } );

    foreach ( int i in evenNumbers )
    {
        Console.WriteLine( i );
    }
    Console.ReadLine();
}

The reference to IsEvenNumber has now been replaced by the creation of an anonymous delegate. The creation and implementation of the delegate is all done in a single line.

You'll probably agree that this does not do much for readability.

Remember how I started this blog post? Lambdas are delegates. So let’s replace the delegate with a lambda.

static void Main( string[] args )
{
    List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    List<int> evenNumbers = Select( numbers, ( x => ( x % 2 == 0 ) ) );

    foreach ( int i in evenNumbers )
    {
        Console.WriteLine( i );
    }
    Console.ReadLine();
}

So what is happening here? Let’s look at the Lambda:

x => ( x % 2 == 0 )

We are expressing that there is an input 'x' which we want to mod by two. Since this Lambda expression is only a single line the return statement is implied and automatically applied to the last statement, most Lambda expressions contain only one line of code, but any number is possible. If you want more that one line you need to use the { } to denote the scope of the block and use the return statement (if your delegate return anything other than void).
If we were to change the expression to:

x => ( x % 2 )

Then the result of the Lambda would be a integer and the code would not compile since the return type Int32 does not match with the Filter delegate.
There is quite a bit of 'magic' going on for the compiler to decide which delegate the Lambda maps onto, the intellisense will help you, because (in this sample) it will know that 'x' is of type Int32.

So to summarize:
Lambdas are a concise notation for defining delegates.

 

 

 

 

Friday, May 02, 2008 9:55:30 AM (Eastern Standard Time, UTC-05:00)  #    Comments [1] -
C#
 Thursday, April 24, 2008

I'm currently doing some work with MapQuest and ran into the situation that I need to define styles for point of interest. From a code point of view I would like an enumeration, but the MapQuest API defines a series of strings to specify the style you wish to use. With C#3.0 I can now add a method to an enumeration using an extension method.

The sample below shows an enumeration for stars and an extension method for getting the value of that enumeration as a string:

public enum Stars : int
{
    Red = 31,
    Green = 32,
    Blue = 33,
    Yellow = 34,
    Orange = 35,
    Purple = 36,
    White = 37,
    Black = 38,
    Gray = 39,
    Gold = 40
}

public static class StarsExtension
{
    public static string Value( this Stars enumerator )
    {
        int v = (int) enumerator;
        return "MQ000" + v.ToString();
    }
}

I can now use this as follows:

string s = Stars.Gold.Value();

Thursday, April 24, 2008 11:11:49 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
AOL | C#
 Wednesday, April 23, 2008

Array conversion, or reshaping of objects, seems like a cool thing to do with LINQ and C# 3.0.
I've played around a little with the following:

sbyte[] imageBytes = GetImage();

// convert using extension method / Lambda syntax 
byte[] y = imageBytes.Select( s => (byte) s ).ToArray();

// convert using LINQ syntax
byte[] x = ( from b in imageBytes select (byte) b).ToArray() ;

// convert using the Cast extension method
byte[] z = imageBytes.Cast<byte>().ToArray();

So what is the difference? Actually approach 1 and 2 lead to the same IL.
The Cast method works quite different and in my case I got an exception from approach 3 saying the sbyte would not fit in the byte.

But of course LINQ is not needed for this simple conversion:

// convert by casting to array to byte[]
byte[] bytes = (byte[])(Array)imageBytes;

I did a quick perf check and the last option is 500 to 800 times faster.

 

Wednesday, April 23, 2008 11:10:52 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
 Monday, April 21, 2008

The Maine Developer Network is hosting a Geek Lunch tomorrow at the State of Maine, Harlow Building at 18 Elkins Ave in Augusta.
Chris Bowen will be presenting on LINQ & Language Improvements in C# 3.0/VB 9.
Sign up here.

LINQ (Language Integrated Query) is a unified approach for querying data using coding syntax that remains consistent regardless of the data source. It WILL change the way you work as a developer and architect and this session will help you on your way to using it effectively. To understand how LINQ works, we'll first navigate the new features of C# 3.0 and VB 9.0 that enable LINQ functionality. Then, we'll dive into .NET 3.5 and Visual Studio 2008 to explore the various realms of LINQ: Datasets, XML, Database/SQL, in-memory objects, and more. By the end of this session, you'll have a solid understanding of how LINQ works and what it can do for your applications.

Monday, April 21, 2008 8:50:10 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General | LINQ
 Monday, April 07, 2008

The Boston Code Camp 9 is over and done with. It was a great two day event and kudos to Chris, Chris and all the presenters that put their time and effort into making this an excellent happening!

Here are the two presentations from the session that I did:

04-06-2008 CC9 - Building a State Machine Workflow.zip (231.61 KB)
04-06-2008 CC9 - Building applications with logic.zip (1.78 MB)
Monday, April 07, 2008 10:20:18 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
Architecture | C# | General | WF
 Thursday, March 27, 2008

Since I was looking at books today anyway I thought I'd research what is available C# 3.0, I haven't read any of these yet, but check them out:

Thursday, March 27, 2008 12:34:28 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | LINQ
 Monday, March 24, 2008

The 22nd of April the Maine Developer Network is organizing a Geek Lunch. We'll be meeting at the State of Maine offices in Augusta to listen to Chris Bowen present on LINQ & Language Improvements in C# 3.0/VB 9.

Pizza will be provided and attendance is free and open for everyone!

More info and RSVP here.

Monday, March 24, 2008 11:52:01 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General | LINQ
 Thursday, January 17, 2008

I was writing some code today to map online drive and files to a local objecttree. So I created a custom file and directory object and a directory holds subdirectories and files.

Something like this:

public class File
{
    public string Name { get; set; }
}

public class Directory
{
    public string Name { get; set; }
    public List<Directory> SubDirectories { get; set; }
    public List<File> Files { get; set; }
}

Now I wanted to have a method which tells me how many files are in a folder, including all the subfolders. This is essentially a recursive select of the number of files per directory and then the sum of the files.

So I implemented a LINQ statement:

public int GetNumberOfFiles()
{
    int total = ( from dir in SubDirectories
                  select dir.Files.Count ).Sum();
    return total;
}

Now this will only get the sum of the number of files in the directories immediately below the current. Let's add a little recursion:

public int GetNumberOfFiles()
{
    int total = ( from dir in SubDirectories
                  select dir.Files.Count + dir.GetNumberOfFiles() ).Sum();
    return total;
}

Pretty nifty!

Thursday, January 17, 2008 3:08:35 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
 Friday, January 11, 2008

Okay, so I'm having a carstarter installed in my car and obviously have nothing better to do than keep tinkering with this DSL stuff.

So I'm thinking... If we create a DSL for the person writing the code, then the debug experience should also be DSL-like. Now I'm not about to write my own debugger, but instead of showing a plain DateTime (what kind of datatype is that anyway?!?!?) we're talking animals, persons and real 'talk' date of birth stuff here.

So I create a special DateOfBirth class which overrides the ToString() method and this creates a 'pretty' experience in my debug window. Notice the values for DateOfBirth. This could ofcourse be extended to person, which is still displayed as the same old school type information: 'DSL.Person'.

The complete code comes at the end of this post, but lets have a look at te code complexity when going from

Person p = new Person();
p.DateOfBirth = new DateTime(1972,9,25);

to our DSL :-)

I guess the code is not too bad. Visual Studio still scores it green on the maintainability scale, but it is clear that quite a large amount of code is needed to create a DSL. And DSL's like this get more context sensitive. Imagine if I would also like to support birds with my DSL? Birds get hatched not born. I'd have to expand my extensions class, or maybe create a whole new set of classes and methods, having a class 'HatchedOn'.

Anyway, they just called, my car is done.

Here is the code for the final sample:

namespace DSL
{
    class Program
    {
        static void Main(string[] args)
        {
            Person mark = Person.Named("Mark").BornOn(Day.the25th).Of(Month.September).InTheYear(1972);
            Animal watson = Animal.Named("Watson").BornOn(Day.the2nd).Of(Month.January).InTheYear(2001).AndItIsA(Animal.KindOf.Dog);
        }
    }


    public class DateOfBirth
    {
        public int Year;
        public Month Month;
        public Day Day;

        public static implicit operator DateTime(DateOfBirth dob)
        {
            return new DateTime(dob.Year, (int)dob.Month, (int)dob.Year);
        }

        public override string ToString()
        {
            return "Born on " + Day.ToString() + " of " + Month.ToString() + " in the year " + Year.ToString() + ".";
        }
    }

    public enum Day : int
    {
        the1st = 1,
        the2nd = 2,
        the25th = 25
    }

    public enum Month : int
    {
        January = 1,
        February = 2,
        September = 9
    }

    public interface IDateOfBirth
    {
        DateOfBirth DateOfBirth { get; set; }
    }

    public class Person : IDateOfBirth
    {
        public DateOfBirth DateOfBirth { get; set; }
        public string Name { get; set; }

        public static Person Named(string name)
        {
            Person p = new Person(name);
            p.DateOfBirth = new DateOfBirth();
            return p;
        }

        protected Person(string name)
        {
            Name = name;
        }
    }

    public class Animal : IDateOfBirth
    {
        public enum KindOf
        {
            Dog,
            Cat
        }

        public DateOfBirth DateOfBirth { get; set; }
        public string Name { get; set; }
        public KindOf KindOfAnimal { get; set; }

        public static Animal Named(string name)
        {
            Animal animal = new Animal();
            animal.Name = name;
            animal.DateOfBirth = new DateOfBirth();
            return animal;
        }
        public Animal AndItIsA(KindOf kind)
        {
            KindOfAnimal = kind;
            return this;
        }
    }


    public static class DateOfBirthExtensions
    {
        public static T BornOn<T>(this T p, Day day) where T : IDateOfBirth
        {
            p.DateOfBirth.Day = day;
            return p;
        }

        public static T Of<T>(this T p, Month month)  where T : IDateOfBirth
        {
            p.DateOfBirth.Month = month;
            return p;
        }

        public static T InTheYear<T>(this T p, int year)  where T : IDateOfBirth
        {
            p.DateOfBirth.Year = year;
            return p;
        }
    }

}

 

Friday, January 11, 2008 8:48:37 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#

I've decided working with enumerations beats working with generics. So now I've taken my little DSL experiment back to enumerations and started implementing the DateOfBirth DSL as a generic extension method.

Since the compiler infers the type based on the actual parameters used you don't need to supply the type when using the extensions methods. Very cool!

Now my DateOfBirthExtensions can work on anything that implements the IDateOfBirth interface, be it a person or an animal :-)

 

namespace DSL
{
    class Program
    {
        static void Main(string[] args)
        {
            Person mark = Person.Named("Mark").BornOn(Day.theTwentyFifth).Of(Month.September).InTheYear(1972);
            Animal watson = Animal.Named("Watson").BornOn(Day.theSecond).Of(Month.January).InTheYear(2001).AndItIsA(Animal.KindOf.Dog);
        }
    }

    public enum Day : int
    {
        theFirst = 1,
        theSecond = 2,
        theTwentyFifth = 25
    }

    public enum Month : int
    {
        January = 1,
        February = 2,
        September = 9
    }

    public interface IDateOfBirth
    {
        DateTime DateOfBirth { get; set; }
    }

    public class Person : IDateOfBirth
    {
        public DateTime DateOfBirth { get; set; }
        public string Name { get; set; }

        public static Person Named(string name)
        {
            Person p = new Person(name);
            return p;
        }

        protected Person(string name)
        {
            Name = name;
        }
    }

    public class Animal : IDateOfBirth
    {
        public enum KindOf
        {
            Dog,
            Cat
        }

        public DateTime DateOfBirth { get; set; }
        public string Name { get; set; }
        public KindOf KindOfAnimal { get; set; }

        public static Animal Named(string name)
        {
            Animal animal = new Animal();
            animal.Name = name;
            return animal;
        }
        public Animal AndItIsA(KindOf kind)
        {
            KindOfAnimal = kind;
            return this;
        }
    }


    public static class DateOfBirthExtensions
    {
        public static T BornOn<T>(this T p, Day day) where T : IDateOfBirth
        {
            p.DateOfBirth = new DateTime(p.DateOfBirth.Year, p.DateOfBirth.Month, (int)day);
            return p;
        }

        public static T Of<T>(this T p, Month month)  where T : IDateOfBirth
        {
            p.DateOfBirth = new DateTime(p.DateOfBirth.Year, (int)month, p.DateOfBirth.Day);
            return p;
        }

        public static T InTheYear<T>(this T p, int year)  where T : IDateOfBirth
        {
            p.DateOfBirth = new DateTime(year, p.DateOfBirth.Month, p.DateOfBirth.Day);
            return p;
        }
    }

}

Friday, January 11, 2008 7:55:53 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#

Inspired by Pinku Surana's blog about DSL's and after reading the presentation from Neal Ford I felt compelled to experiment with a little DSL style programming.

My goal was to get as close as possible to something like:

Person mark = Person.Named("Mark").BornOn(theTwentyFifth).Of(September).InTheYear(1972);

As it turns out the linking of methods is pretty easy. Where you might be inclined to create a property, just create a method which returns the base object, in this case Person.
The hardest part I found was trying to come up with something decent for 'theTwentyFifth' and 'September'. My first try was to create enumerations, but then you have to name the enum and you get something like:

Person mark = Person.Named("Mark").BornOn(Day.theTwentyFifth).Of(Month.September).InTheYear(1972);

Which is good because the intellisense in C# is great, but having to prefix it messes it up just a little. An Alternative implementation is to 'abuse' generics and do it like this:

Person mark = Person.Named("Mark").BornOn<theTwentyFifth>().Of<September>().InTheYear(1972);

The draw back to this is that intellisense is less useful and it is messy to be using generics for BornOn and Of, but not for InTheYear.
The implementation is below. I'm still thinking about which solution is more useful.


namespace DSL
{
    class Program
    {
        static void Main(string[] args)
        {
            Person mark = Person.Named("Mark").BornOn<theTwentyFifth>().Of<September>().InTheYear(1972);
        }
    }

    public abstract class CalenderMonth
    {
        public int Month { get; private set; }

        protected CalenderMonth(int month)
        {
            Month = month;
        }
    }

    public class September : CalenderMonth
    {
        public September()
            : base(9)
        {
        }
    }


    public abstract class DayOfMonth
    {
        public int Day { get; private set; }

        protected DayOfMonth(int day)
        {
            Day = day;
        }
    }

    public class theTwentyFifth : DayOfMonth
    {
        public theTwentyFifth()
            : base(25)
        {
        }
    }

    public class Person
    {
        DateTime _dob = new DateTime();
        string _name;


        public const int theFirst = 1;
        public const int theTwentyFifth = 25;

        public static Person Named(string name)
        {
            Person p = new Person(name);
            return p;
        }

        protected Person(string name)
        {
            _name = name;
        }

        public Person BornOn<T>() where T : DayOfMonth, new()
        {
            T d = new T();
            _dob = new DateTime(_dob.Year, _dob.Month, d.Day);
            return this;
        }

        public Person Of<T>() where T : CalenderMonth, new()
        {
            T m = new T();
            _dob = new DateTime(_dob.Year, m.Month, _dob.Day);
            return this;
        }

        public Person InTheYear(int year)
        {
            _dob = new DateTime(year, _dob.Month, _dob.Day);
            return this;
        }
    }

}

 

Friday, January 11, 2008 7:24:33 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#

If you want to dynamically want to load a form and you only know the classname then the following snippet may be of use:

Type t = Type.GetType("ConsoleApplication1.Form1");
if (t != null)
{
    System.Windows.Forms.Form f = (System.Windows.Forms.Form) Activator.CreateInstance(t);
    f.ShowDialog();
}

Now, if you'd want to load the form from a different assembly, let's say, some library assembly with forms, then you need to specifiy an AssemblyQualifiedName.

Like:

Type t = Type.GetType("ClassLibrary1.Form1, ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
if (t != null)
{
    System.Windows.Forms.Form f = (System.Windows.Forms.Form)Activator.CreateInstance(t);
    f.ShowDialog();
}

This will dynamically load the form and show it. So no compiletime binding needs to be done.

 

Friday, January 11, 2008 10:33:31 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
 Thursday, January 10, 2008

I'm beginning to appreciate the power of extension methods. At first I thought: "Who wants this?". Doesn't this 'break' the encapsulation of object oriented programming?

Well yes it does, but it makes for some darn pretty code when building utility methods. Right now I'm working on some stuff with the DataContractJsonSerializer and this class has a ReadObject method which takes a stream as a parameter. When writing unit test (and regular code) I'm quite frequently going from a string to a stream. So I figured I'd create an extension method called ToMemoryStream(). This is what is looks like:

using System;
using System.IO;

namespace DevelopOne.Framework.Serialization
{
    /// <summary>
    /// Class with extension methods which are helpful when working
    /// with serialization.
    /// </summary>
    public static class Extensions
    {
        /// <summary>
        /// Converts a string to a memory stream and sets the position of the stream to
        /// the beginning of the stream.
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static MemoryStream ToMemoryStream(this string s)
        {
            MemoryStream ms = new MemoryStream();
            byte[] bytes = System.Text.ASCIIEncoding.ASCII.GetBytes(s);
            ms.Write(bytes, 0, bytes.Length);
            ms.Position = 0;
            return ms;
        }
    }
}

Now calling this method can be done by simply including the namespace DevelopOne.Framework.Serialization and calling ToMemoryStream() on a string.

Like this:

string json = "{\"exceptions\":[{\"type\":\"ExceptionObject\",\"errorMessage\":\"Calls to member.login must be secure.\",\"errorInfo\":null,\"errorCode\":513}]}";
MemoryStream ms = json.ToMemoryStream();

 

 



The best web hosting service is the one that not only provides cheap web hosting, but comes with perks like email hosting as well. This and the added benefits of hosting more than one domain names of course adds to the entire package. Thanks to the extensive promotion of online marketing, now anyone with access to computers knows of this. This has contributed effectively to the popularity of home business setups as well.

Thursday, January 10, 2008 8:09:58 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
 Monday, November 19, 2007

The last couple of weeks I've been working on migrating an ASP.NET application from using a Visual FoxPro database to using SQL Server 2005. My application has it's logic in library DLL and with some layering uses Typed DataSets to connect to the database.

Typical code within the data access layer looks like this:

internal ViewDataSet.RequestViewDataTable GetViewByPrimaryUser( string user )
{
    using ( ViewDataSetTableAdapters.RequestViewTableAdapter _adapter 
            
= new ViewDataSetTableAdapters.RequestViewTableAdapter() )
    {
        ViewDataSet.RequestViewDataTable table;
        table = _adapter.GetByPrimaryUser( user.Trim() );
        return table;
    }
}

The method 'GetByPrimaryUser' is defined on the TableAdapter and using the GUI designer in Visual Studio I manage my typed datasets. All SQL is stored within the Typed DataSets. There is very limited use of stored procedures.

Migrating the .NET code from using a Visual FoxPro database to using SQL Server 2005 has involved the following:

  • Change the connection string property on every datatable to use the SQL Server connection string instead of the FoxPro connection string.
  • Opening every single query and changing the SQL parameters from question marks '?' to named parameters like '@user'.
  • Rechecking the mapping of the columns in the datatable, sometimes these would get messed up. Especially in cases where non-database columns where added to the datatable.
  • Rechecking column expressions.
  • Some areas of the code accessed the OleDbDataAdapter and OleDbConnection within the typed dataset, this had to be replaced with SqlDataAdapter and SqlConnection.
  • FoxPro does not support the .NET light weight transactions, so code to custom manage the transaction could be deleted and a simple 'using( TransactionScope tx = new TransactionScope() )' could be implemented.
  • There where several areas where 'adapter.Update(row)' did not work with FoxPro, so the Insert/Update/Delete had to be called manually in the data access layer. With SQL Server there are no problems and this 'fix-it' code could be removed.

After following these steps some of the datatables would generate unexplicable validation errors. Not wanting to waste too much time I just re-created those typed tables and re-added the queries on those tables.

 



Since the advent of cheap web hosting, we have had more development in the field of SEM. Thanks to features like internet phone, managing internet network marketing is a lot more feasible now. Marketing strategies like cpc, ppi and pay per click can be managed with much more comfort now. Usually regular advertising agencies miss out on this since they concentrate more on building links through email marketing.

Monday, November 19, 2007 7:23:49 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | C#

Visual Studio 2008 Team Suite has just become available on MSDN Subscriber Downloads.

Monday, November 19, 2007 6:41:32 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | C# | General | Team System
 Monday, November 12, 2007

Another gem in .NET 2.0. Parsing a string to get a datetime used to be pretty complex. But now with the DateTime.ParseExact(...) method you can specify the exact format of your string.

string s = "20071231T214559";
DateTime d = DateTime.ParseExact( s, "yyyyMMddTHHmmss", null );
this.textBox2.Text = d.ToString();  // this will print: 31-12-2007 21:45:59

Steve Tibbet has a post describing all the options for specifying the format.

Monday, November 12, 2007 8:54:54 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | C#

The .NET Framework is huge and I still frequently find new things in .NET 2.0 which I had not seen before. Last week I stumbled across the update in Math.Round(...).
In .NET 1.x the .NET Framework would only support the American way of rounding numbers. This means that:

decimal y = 2.5M;
decimal x = Math.Round(y, 0);     // x = 2

For Dutch people this wrong. We would expect x to be '3'.
In .NET 2.0 there is a new overload, allowing you to specify how the Round method should work.

decimal y = 2.5M;
decimal x = Math.Round(y, 0, MidpointRounding.AwayFromZero);     // x = 3!

Monday, November 12, 2007 8:24:02 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
.NET | C#
 Sunday, November 11, 2007

Earlier this year the C# team implemented a change in the design of anonymous types. It used to be possibly to create an anonymous type and then change a property on the anonymous type. The code would look like this:

var x = new { Name = "Mark", Age = 0 };
x.Age = 35;

In Visual Studio 2008 beta 2 this is however no longer possible since anonymous types are now immutable. There are apparently good reasons for doing this and Sree explains it in this post and there is an issue on MSConnect where Mads from the C# team explains the reasoning. Must say I don't completely get the reasoning, especially since VB.NET does not have this restriction.

Sunday, November 11, 2007 11:23:02 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | LINQ

Yesterday I spoke at the iSDC and Ronua Community Workshop. We had a great day and it was a pleasure meeting the people at iSDC, meeting the developers in Cluj and surroundings (some drove over 200km to make it to the meeting) and Petru Jucovschi (the DPE for Microsoft Romania).

Here are the two presentations that I did:

11-09-2007 - Developing Windows Vista gadgets.pptx (431.43 KB)

11-10-2007 - 2008.NET.pptx (252.91 KB)

In the Visual Studio 2008 presentation I also talked about the work I've done for AOL. The AOL developer site can be found at http://dev.aol.com and for more reference material on Vista gadgets you can visit my AOL blog.

Sunday, November 11, 2007 3:32:20 AM (Eastern Standard Time, UTC-05:00)  #    Comments [2] -
C# | General | LINQ | Vista | WCF
 Wednesday, October 31, 2007

I just finished my sample of the week for my AOL blog. This week I created code to upload a file to XDrive using the HttpWebRequest object. The sample is also useful if you're trying to find out more about uploading a file using C# (or the .NET Framework).

Wednesday, October 31, 2007 11:17:39 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
AOL | C#
 Thursday, October 25, 2007

.NET 2.0 has no special support for REST and JSON. That doesn't mean you can't call a REST resource and pass it a JSON object. In my weekly AOL post I demonstrate how to use WebRequest, WebResponse and basic string manipulation to call a REST resource and pass a JSON object.

Thursday, October 25, 2007 9:15:35 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
AOL | C#
 Wednesday, August 22, 2007

I've just posted a new blog entry on my AOL blog. I think it turned out really cool!

I use Windows Communication Foundation 3.5 (beta 2) to create a service contract, data contract and client channel and then connect to a non WCF, REST based service.

More on: http://dev.aol.com/node/595.

Wednesday, August 22, 2007 1:21:48 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
AOL | C# | WCF
 Wednesday, August 15, 2007

Read my AOL post on using XmlDocument to invoke the REST based AOL Video Search here.

Wednesday, August 15, 2007 2:46:50 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
AOL | C#
 Saturday, June 30, 2007
Saturday, June 30, 2007 5:45:15 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
Amazon | C#
 Tuesday, June 12, 2007

While playing around with SOS a little today I took two looks at the output of the command:

!dumpheap -stat

First I ran.

static void Main(string[] args)
{
}  //breakpoint here

Next I added a Console.Writeline.

static void Main(string[] args)
{
Console.WriteLine("Hello!");
}  //breakpoint here

Output of the dumpheap of the first bit of code:

!dumpheap -stat
PDB symbol for mscorwks.dll not loaded
total 2074 objects
Statistics:
      MT    Count    TotalSize Class Name
790fdd5c        1           12 System.Security.Permissions.SecurityPermission
790fd5b4        1           24 System.OperatingSystem
790fc79c        1           24 System.Reflection.Assembly
790fb668        1           28 System.SharedStatics
790fce28        1           32 Microsoft.Win32.Win32Native+OSVERSIONINFO
79124544        1           36 System.Int64[]
790fd444        1           40 Microsoft.Win32.Win32Native+OSVERSIONINFOEX
790fbcfc        1           40 System.AppDomainSetup
790fdc3c        1           44 System.Security.FrameSecurityDescriptor
790fd4ec        2           48 System.Version
790f9c18        4           48 System.Object
790fc308        3           60 System.RuntimeType
790fa800        3           60 System.Text.StringBuilder
790fca24        1           64 System.IO.UnmanagedMemoryStream
790fd824        2           72 System.Security.PermissionSet
790fac70        1           72 System.ExecutionEngineException
790fabcc        1           72 System.StackOverflowException
790fab28        1           72 System.OutOfMemoryException
00153d48        6           84      Free
790fb8c8        1          100 System.AppDomain
790fad14        2          144 System.Threading.ThreadAbortException
79124670        6          356 System.Char[]
79124228        4         8288 System.Object[]
790fa3e0     2028       130364 System.String
Total 2074 objects

The output for the second bit of code:

!dumpheap -stat
PDB symbol for mscorwks.dll not loaded
total 4451 objects
Statistics:
      MT    Count    TotalSize Class Name
79110e94        1           12 System.Resources.FastResourceComparer
79107f40        1           12 System.RuntimeTypeHandle
79102f48        1           12 System.__Filters
79102ef8        1           12 System.Reflection.Missing
79101ca8        1           12 System.RuntimeType+TypeCacheQueue
790fdd5c        1           12 System.Security.Permissions.SecurityPermission
79178564        1           16 System.IO.MdaHelper
79126bd8        1           16 System.Collections.ObjectModel.ReadOnlyCollection`1[[System.Reflection.CustomAttributeData, mscorlib]]
79126710        1           16 System.Collections.ObjectModel.ReadOnlyCollection`1[[System.Reflection.CustomAttributeTypedArgument, mscorlib]]
79111010        1           16 System.Resources.ResourceReader+TypeLimitingDeserializationBinder
7910fe28        1           16 System.Globalization.GlobalizationAssembly
7910646c        1           16 System.Reflection.Cache.InternalCache
79168874        1           20 System.Diagnostics.StackTrace
79126824        1           20 System.Reflection.CustomAttributeTypedArgument[]
7910fbdc        1           20 System.Environment+ResourceHelper
7910031c        1           20 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
791002c0        1           20 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
790ff26c        1           20 System.Text.InternalEncoderBestFitFallback
790fdf38        1           20 Microsoft.Win32.SafeHandles.SafeFileHandle
7910f690        1           24 System.Collections.Stack
791009f0        1           24 System.IO.TextWriter+SyncTextWriter
790ff2c4        1           24 System.Text.InternalDecoderBestFitFallback
790fd5b4        1           24 System.OperatingSystem
790fc79c        1           24 System.Reflection.Assembly
790f8648        1           24 System.Runtime.CompilerServices.RuntimeHelpers+ExecuteWithLockHelper
79125330        1           28 System.Reflection.Cache.InternalCacheItem[]
791008f0        1           28 System.Text.EncoderNLS
790fe4b0        1           28 System.IO.Stream+NullStream
790fde94        1           28 Microsoft.Win32.Win32Native+InputRecord
790fb668        1           28 System.SharedStatics
791064d8        1           32 System.Reflection.Cache.ClearCacheHandler
79100760        2           32 System.Text.DecoderReplacementFallback
79100700        2           32 System.Text.EncoderReplacementFallback
790fce28        1           32 Microsoft.Win32.Win32Native+OSVERSIONINFO
79124544        1           36 System.Int64[]
790fe280        1           36 System.IO.__ConsoleStream
790f992c        1           36 System.Resources.RuntimeResourceSet
79110f4c        1           40 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
790fd444        1           40 Microsoft.Win32.Win32Native+OSVERSIONINFOEX
790fbcfc        1           40 System.AppDomainSetup
790fdc3c        1           44 System.Security.FrameSecurityDescriptor
79193fa4        1           48 System.RuntimeMethodHandle[]
7910fc38        2           48 System.Environment+ResourceHelper+GetResourceStringUserData
79107714        1           48 System.Reflection.Module
790ffbe4        4           48 System.UInt16
791687fc        1           52 System.Diagnostics.StackFrameHelper
79126534        1           52 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Resources.ResourceLocator, mscorlib]]
790fb238        1           52 System.Threading.Thread
790f96e8        1           52 System.Resources.ResourceManager
7912545c        1           56 System.LogLevel[]
791005d4        2           56 System.Text.UTF8Encoding
791003f8        1           56 System.IO.StreamWriter
790ffb28        3           60 System.Globalization.CultureTableItem
79110c2c        2           64 System.Text.UTF8Encoding+UTF8Decoder
7910feec        2           64 System.Globalization.CompareInfo
79126398        1           72 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Resources.ResourceLocator, mscorlib]][]
790ffa34        1           72 System.Globalization.CultureTable
790fd824        2           72 System.Security.PermissionSet
790fac70        1           72 System.ExecutionEngineException
790fabcc        1           72 System.StackOverflowException
790fab28        1           72 System.OutOfMemoryException
790ff138        1           76 System.Text.SBCSCodePageEncoding
79110b54        2           80 System.IO.BinaryReader
7910fcec        1           80 System.Resources.ResourceReader
79102fac        3           96 System.Reflection.MemberFilter
79102e10        3           96 System.Runtime.CompilerServices.RuntimeHelpers+CleanupCode
791079cc        1          100 System.Reflection.MetadataArgs+SkipAddresses
790fb8c8        1          100 System.AppDomain
00153d48        7          100      Free
79125594        1          108 System.SwitchStructure[]
79102cec        4          128 System.Runtime.CompilerServices.RuntimeHelpers+TryCode
790ffe6c        1          128 System.Globalization.NumberFormatInfo
790f9c18       11          132 System.Object
790fad14        2          144 System.Threading.ThreadAbortException
79109a4c        4          240 System.Reflection.AssemblyName
790ff6dc        5          240 System.Globalization.CultureTableRecord
790fed1c       20          240 System.Int32
790fd4ec       10          240 System.Version
790fca24        4          256 System.IO.UnmanagedMemoryStream
791689a4        9          288 System.Diagnostics.StackFrame
791251f8        1          288 System.Reflection.CustomAttributeRecord[]
790fa800       20          400 System.Text.StringBuilder
7912747c       23          552 System.Collections.Generic.List`1[[System.Reflection.FieldInfo, mscorlib]]
79127200       23          552 System.Collections.Generic.List`1[[System.Reflection.RuntimeFieldInfo, mscorlib]]
791270bc       23          552 System.Collections.Generic.List`1[[System.Reflection.PropertyInfo, mscorlib]]
790ff4c4        8          576 System.Globalization.CultureInfo
79124958       25          600 System.Collections.Generic.List`1[[System.Reflection.RuntimeConstructorInfo, mscorlib]]
791240f0       12          608 System.Int32[]
79127404       23          644 System.RuntimeType+RuntimeTypeCache+MemberInfoCache`1[[System.Reflection.RuntimeFieldInfo, mscorlib]]
79127044       23          644 System.RuntimeType+RuntimeTypeCache+MemberInfoCache`1[[System.Reflection.RuntimePropertyInfo, mscorlib]]
79124b5c       24          672 System.RuntimeType+RuntimeTypeCache+MemberInfoCache`1[[System.Reflection.RuntimeConstructorInfo, mscorlib]]
791273a8       46          736 System.Reflection.CerArrayList`1[[System.Reflection.RuntimeFieldInfo, mscorlib]]
79126fe8       46          736 System.Reflection.CerArrayList`1[[System.Reflection.RuntimePropertyInfo, mscorlib]]
79124418       14          780 System.Byte[]
79125c30       28          784 System.RuntimeType+RuntimeTypeCache+MemberInfoCache`1[[System.Reflection.RuntimeMethodInfo, mscorlib]]
79124b00       49          784 System.Reflection.CerArrayList`1[[System.Reflection.RuntimeConstructorInfo, mscorlib]]
791100e4       23          828 System.Reflection.CustomAttributeData
7910b170       26         1144 System.Reflection.RtFieldInfo
7910aaf4       25         1200 System.Reflection.RuntimeConstructorInfo
790fc308       60         1200 System.RuntimeType
791036b0       51         1224 System.Collections.ArrayList
79125a94       90         1440 System.Reflection.CerArrayList`1[[System.Reflection.RuntimeMethodInfo, mscorlib]]
791256cc       62         1488 System.Collections.Generic.List`1[[System.Reflection.RuntimeMethodInfo, mscorlib]]
791275c8       23         1620 System.Reflection.CustomAttributeCtorParameter[]
79124670       20         1756 System.Char[]
79126e40       74         1776 System.Collections.Generic.List`1[[System.Reflection.RuntimePropertyInfo, mscorlib]]
790fea70       34         1904 System.Collections.Hashtable
79124d0c      156         2120 System.RuntimeTypeHandle[]
7910ae58       39         2340 System.Reflection.ParameterInfo
7910b778       51         2856 System.Reflection.RuntimePropertyInfo
79101be8       40         3200 System.RuntimeType+RuntimeTypeCache
79101e90       62         3472 System.Reflection.RuntimeMethodInfo
791242ec       34         4896 System.Collections.Hashtable+bucket[]
7910adcc      107         5136 System.Signature
79126d08       23         5512 System.Reflection.CustomAttributeNamedParameter[]
79124228      649        25308 System.Object[]
790fa3e0     2251       144908 System.String
Total 4451 objects

So 2000+ objects to do... "nothing" and then 2400 additional classes to output one string to the Console.

Seems a lot, but it illustrates how much management it takes to have a managed environment.

Tuesday, June 12, 2007 8:09:03 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
 Thursday, March 01, 2007

The very first Dutch Code Camp will be organised by a confederation of user groups. I love it when people come together to organize something great! Maurice de Beijer has taken the lead to get things started but with three user groups coming together it should be an excellent event!

Go to: http://www.code-camp.nl/

Thursday, March 01, 2007 10:56:33 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Tuesday, February 27, 2007

Here are the powerpoint and demo code from my session about developing for Windows Vista using .NET 3.0 at the Maine Developer Network user group meeting on the 27th of February 2007 in Augusta, ME.

WorkflowConsoleApplication1.zip (35.87 KB)

HelloWorldGadget.zip (14.31 KB)

02-27-2007_MDN_-_Developing_for_Vista_with_.NET_3.0.zip (417.06 KB)

[Updated: Fixed download link for powerpoint]

 

 



Individuals who have been in web development for quite some time, are now slowly converting to internet advertising. Working with tools for web design gives them an added benefit of course. They already have background knowledge on dedicated hosting. All they need is a cheap web hosting service and they can actually start an seo consultancy of their own. Usually pay per click and adsense does not agree with these people. More creative strategies like email marketing appeals to them.

Tuesday, February 27, 2007 9:05:46 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General | Vista | WPF

Here are the powerpoint and demo code from my session about implementing application logic in .NET 2.0 at the Maine Developer Network meeting on the 27th of February 2007 in Augusta, ME.

UserManagement.zip (2.1 MB)

02-27-2007_MDN_-_Implementing_application_logic_in_.NET_2.0.zip (1.14 MB)

[Updated: Fixed download link for powerpoint]

Tuesday, February 27, 2007 8:55:18 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
Architecture | C# | General
 Saturday, December 23, 2006

Microsoft® Visual Studio® 2005 Service Pack 1 is now available as a download from MSDN.

Go to: http://www.microsoft.com/downloads/details.aspx?familyid=BB4A75AB-E2D4-4C96-B39D-37BAF6B5B1DC&mg_id=10055&displaylang=en

Service Pack 1 also provides over 70 improvements for common development scenarios including:

  • New processor support (e.g., Core Duo) for code generation and profiling
  • Performance and scale improvements in Team Foundation Server
  • Team Foundation Server integration with Excel 2007 and Project 2007
  • Tool support for occasionally connected devices and SQL Server Compact Edition
  • Additional support for project file based Web applications
  • Windows Embedded 6.0 platform and tools support

The complete release notes can be found at http://support.microsoft.com/default.aspx/kb/928957/.

As it turns out, it's pretty unclear what has been fixed in this service pack. The 'What's New in Visual Studio 2005 SP1' page doesn't provide any information. Back in September Somasegar promised to provide a list of fixes, but in his post about the release of SP1 he makes no mention of what has been fixed.

Update: a list of fixes in Visual Studio 2005 SP1 can be found at: http://support.microsoft.com/kb/918526/en-us

 

Saturday, December 23, 2006 11:18:24 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Wednesday, October 18, 2006

I'm very pleased to announce that the first book with my name on the cover is now available through Amazon.com!

Just click the image :-)

Wednesday, October 18, 2006 9:52:24 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Monday, September 25, 2006

Matthew Cochran wrote an excellent article explaining how to implement the provider pattern: http://www.c-sharpcorner.com/UploadFile/rmcochran/providerPattern08102006110013AM/providerPattern.aspx

Monday, September 25, 2006 2:22:01 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
 Monday, September 11, 2006

At the end of the month I'll be doing another session for the Maine Developer Network.
Hope to see you there!

Topic       : Implementing application logic in .NET 2.0

Speaker     : Mark Blomsma

Date        : September 27th

Time        : 10:00 - 12:00

Location    : Harlow Building in the AMHI campus, Augusta, Maine, USA.

Description : This session will be about implementing business logic in .NET 2.0.
We'll look at and discuss various architectural issues and how to implement design
patterns to help create a blueprint of our application. We'll look at choosing and
implementing an exception handling strategy and we'll look at various ways data can
flow through our application.
Monday, September 11, 2006 8:25:06 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Sunday, September 10, 2006

They're out!

MSDN subscribers can download Windows Vista via http://msdn.microsoft.com/.

If you're running Windows XP and want to try out the .NET Framework 3.0 RC1, then get the bits at http://msdn.microsoft.com/windowsvista/downloads/products/getthebeta/default.aspx

The .NET Framework download is available for everyone. Not just MSDN subscribers.

Sunday, September 10, 2006 11:15:37 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General | Vista | WF | WPF
 Tuesday, September 05, 2006

When I need to have my code write files to a unique folder, I often use the following trick.

string folderName = someRoot + @"\" + username + @"\" + DateTime.Now.Ticks.ToString();

As long as I'm not writing code which runs multiple threads this will pretty much guarantee me of a unique folder name and it looks nicer than a Guid as a folder name. 

Tuesday, September 05, 2006 3:23:21 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General

I'm working on a ASP.NET 2.0 web application right now, which uses a Visual FoxPro database. I want the database to sit in the App_Data folder of my web application and I also want my connection string to use a relative path to access my database.

I found that SQL Express supports this, but the documentation suggests that it'll only work for the AttachDB value in a SQL Express connection string. Luckily this is not true. As shown in the sample below. The "|DataDirectory|" element can be used to point to the App_Data folder of your webapplication. I assume this will work for any database connection string.

<connectionStrings>

<add name="Develop-One.Framework.Properties.Settings.ConnectionString"

connectionString="Provider=VFPOLEDB.1;Data Source=|DataDirectory|UserData"

providerName="System.Data.OleDb"/>

</connectionStrings>

Tuesday, September 05, 2006 3:15:48 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Friday, August 18, 2006

Microsoft has released Visual Studio 2003 Service Pack 1.

Link: http://www.microsoft.com/downloads/details.aspx?familyid=dc455c5d-2c99-43cc-ad71-4e0beb71bfa7&displaylang=en

For a list of bugs that were fixed in this service pack go to http://support.microsoft.com/default.aspx?scid=kb;en-us;918007

Friday, August 18, 2006 2:05:20 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Tuesday, June 13, 2006

I knew it was possible, but never took the time to have a closer look at how to do it.

With embedded resources you can embed whole files (binary and text) in your assembly. Today I created a Console application that provides help when you pass the '/?' switch. The helpfile is a plain textfile, embedded in the assembly.

Here's how it is done:

  1. Add the textfile to your project.
  2. Set the property 'Build Action' to 'Embedded Resource'.
  3. Use code below to retrieve file as string.

private static string GetFileFromResources(string filename)
{
Assembly assembly;
assembly = Assembly.GetExecutingAssembly();
Stream stream =
assembly.GetManifestResourceStream("Type assembly namespace here" + "." + filename);
StreamReader sr = new StreamReader(stream);
string file = sr.ReadToEnd();
return file;
}

Tuesday, June 13, 2006 10:05:33 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General

Soma announced today that WinFX is being renamed to .NET Framework 3.0. Jason has more detailed info though.

WinFX will become .NET 3.0 while still running on the CLR 2.0. C# 3.0 will not be part of this release, but rather remain part of the 'Orcas'-release (scheduled for sometime 2007). I guess they'll have to rename it to C# 4.0.

Updated 6/13/2006: There is also a .NET 3.0 website at http://www.netfx3.com/

Tuesday, June 13, 2006 6:52:15 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Monday, June 05, 2006

In May we had Gregg Dunn and Bryan Beatty speak at the Maine Developer Network. Sadly I was away on business, but their powerpoints have been posted and provide some great info on Smart Clients and Object Relational Mapping.

Go to: Maine Developer Network - Presentations

Monday, June 05, 2006 7:43:45 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Tuesday, May 09, 2006

Another example.

public partial class StoredProcedures
{
  [Microsoft.SqlServer.Server.SqlProcedure]
  public static void PerformDomainCount()
  {
    SqlConnection conn = new SqlConnection();
    SqlDataReader reader = null;
    try
    {

    // use "Context Connection=true" to specify that you're
    // tagging along on the current connection
    // if you wish you could connect to an external
    // database
    conn.ConnectionString = "Context Connection=true";

    // You have to open the connection, which feels a little strange
    conn.Open();

    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = "select count(*), dbo.ExtractDomain(email) from customers group by dbo.ExtractDomain(email)";
    cmd.Connection = conn;

    reader = cmd.ExecuteReader();
    SqlMetaData[] meta = DefineMetaData();
    SqlDataRecord record = new SqlDataRecord( meta );
    if ( reader.HasRows )
    {
      reader.Read();
      Copy( reader, record );
      SqlContext.Pipe.SendResultsStart( record );
      SqlContext.Pipe.SendResultsRow( record );
      while ( reader.Read() )
      {
        Copy( reader, record );
        SqlContext.Pipe.SendResultsRow( record );
      }
    }

    }
    catch ( Exception exception )
    {
      SqlContext.Pipe.Send( "ERROR: " + exception.Message );
    }
    finally
    { 
      // Close all
      reader.Close();
      conn.Close();
      if ( SqlContext.Pipe.IsSendingResults )
      {
        SqlContext.Pipe.SendResultsEnd();
      }
    }
  }

  private static SqlMetaData[] DefineMetaData()
  {
    SqlMetaData[] meta = new SqlMetaData[2];
    meta[0] = new SqlMetaData( "Count", SqlDbType.Int );
    meta[1] = new SqlMetaData( "Domain", SqlDbType.NVarChar, 50 );
    return meta;
  }

  private static void Copy(SqlDataReader reader, SqlDataRecord record)
  {
    record.SetSqlInt32( 0, reader.GetSqlInt32( 0 ) );
    record.SetSqlString( 1, reader.GetSqlString( 1 ) );
  }
}

Tuesday, May 09, 2006 1:37:03 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General

An example says it all.

[Microsoft.SqlServer.Server.SqlProcedure]
public static void PerformDomainCount()
{
SqlConnection conn = new SqlConnection();
// use "Context Connection=true" to specify that you're
// tagging along on the current connection
// if you wish you could connect to an external
// database
conn.ConnectionString = "Context Connection=true";

// You have to open the connection, which feels a little strange
conn.Open();


SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandText = "select * from customers";

SqlDataReader reader = cmd.ExecuteReader();

// Send result to caller
SqlContext.Pipe.Send( reader );

// Close the connection
conn.Close();
}

Tuesday, May 09, 2006 1:07:23 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Friday, March 10, 2006

Beth Massi has an interesting post about the performance of DataSets when using Binary Serialization.

Read more: http://bethmassi.blogspot.com/2006/01/binary-serialization-of-datasets-in.html

Friday, March 10, 2006 2:30:57 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#

I'm working on a WinForm 2.0 window on which I have a DataGridView.

The DataGridView is connected to an ObjectDataSource and the datasource of this ObjectDataSource is pointing to an array of items.

This works nicely, however, the user can use a popup to add an entry to the array. The DataGridView will not automatically detect that the underlying array has changed.

Solution: Call BindingSource.ResetBindings(..) after updating the array. This will raise an event which makes the DataGridView redraw itself.

Friday, March 10, 2006 10:01:38 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C# | General
 Friday, February 24, 2006

I was coding a little tool to send our SDN newsletters and discovered the new SmtpMail stuff in .NET2.0. Now you don't need to code any stuff for setting your mailserver or credential. Just configure it!

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.net>
    <mailSettings>
      <smtp deliveryMethod="Network">
        <network host="mail.myserver.net"
          port="25" 
          userName="Mark"
          password="secret"/>
      </smtp>
    </mailSettings>
  </system.net>
</configuration>

Now just send the message using the new classes in System.Net.Mail:

System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient();
client.Send( message );
Friday, February 24, 2006 2:30:45 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
 Tuesday, February 21, 2006

Today I had a discussion about coding guidelines and in particular about the size of a class, the number of methods in a class and the number of lines of code per class. What is right?

Ofcourse a little search on Google revealed millions of hits. Some of the more useful ones were:

Most standards don't say much about the size of a class, the number of methods in a class and the number of lines of code per class. The few that do say something come fairly close.

Here's the sum of guidelines that I think I'll stick by:

  1. A source file should only contain one class
  2. A method should be no more than 30 lines of code, excluding blank lines and comments
  3. A source file should contain no more than 1000 lines, including blanks and comments
  4. An interface should have no more than 10 methods, excluding overloads, ie. the combination of overloads counts as one methods
  5. C# 2.0 allows partial classes:
    • a source file should only contain one partial class
    • don't split the implementation of an interface across multiple files
    • for large classes split the implementation of interfaces and implement one interface per file
      • Filename:  <classname>.<interfacename>.cs
    • if you have a class which implements one interace, but has a lot of private methods, then create a partial class with just the private methods:
      • Filename: <classname>.private.cs

Ad 2.
This is the average I found and seems to make sense, since this means that with one look at the screen your brain can absorb the whole method.

Ad 3.
I'm not convinced this is a very important rule. Having 2000 lines of code in one file or spread across two classes in two files doesn't really make that big a difference to me. See also ad 5.

Ad 4.
This is mainly because of Intellisense. Ten methods will provide optimum use of Intellisense.

Ad 5.
Partial classes are great!

Tuesday, February 21, 2006 6:15:16 AM (Eastern Standard Time, UTC-05:00)  #    Comments [2] -
C# | General
 Saturday, January 14, 2006

Just a couple of links to stuff that's in beta right now:

WinFX, XAML and SDK
ASP.NET ATLAS
C# and LINQ
VB.NET and LINQ

Saturday, January 14, 2006 10:37:48 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
ASP.NET | C# | LINQ | WPF
 Thursday, January 12, 2006

With generic in C# 2.0 life just become so much easier. Today I was impressed by the ease with which you can now sort a list of T.

Code below shows how with one method you can now implement a sort. This used to be much more complex!

public class Person
{
    public Person(string name)
    {
        this.Name = name;
    }

    public string Name;
}

class Demo
{
    public List GetAllPersons()
    {
        List result = new List();
        result.Add(new Person("Mark"));
        result.Add(new Person("Dennis"));
        result.Add(new Person("Duncan"));
        result.Add(new Person("Jeremy"));
        result.Sort(SortByName);
        return result;
    }

    public static int SortByName( Person x, Person y )
    {
        return x.Name.CompareTo(y.Name);
    }
}
Thursday, January 12, 2006 1:14:32 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
C#
About
This blog is run by Mark Blomsma.
© Copyright 2009
Develop-One
Sign In
Statistics
Total Posts: 376
This Year: 34
This Month: 0
This Week: 1
Comments: 119
All Content © 2009, Develop-One
DasBlog theme 'Business' created by Christoph De Baene (delarou)