GridView doing double postback when using ImageButton for Delete

I just spent a bit of time trying to figure out why my GridView was randomly doing a double postback when deleting rows.  When I hooked up the debugger and put a break point on in the Page_Load, I would see that it was being called twice.  It turns out that there is a bug with the GridView that causes this behavior.  If you use either a LinkButton or regular Button, the GridView works as expected.  There is also a workaround @ http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=105123


Book Review: Microsoft AJAX Library Essentials: Client-side ASP.NET AJAX 1.0 Explained

This is a book that should be in your library if you are going to be doing development with ASP.NET AJAX.

Typically when you start learning ASP.NET Ajax all of the material centers around UpdatePanels and leaves out anything to do with the client-side scripts.  This book will make you realize how much functionality you are missing by only using UpdatePanels.

Also, this book not only covers learning the ASP.NET AJAX client scripts but how to do object oriented javascript development. 


Visual Studio Tips and Tricks

I am big fan of using keystrokes over using the mouse.  The two blogs below have some great post on visual studio shortcuts.

 

Sara Ford's Weblog : Daily post of a Visual Studio Tip.

Chris Craft's Blog : Currently running a 31 days of Visual Studio Tips and Tricks


C# Convert Collection to Delimited String using Linq

Several times I have had the need to take a collection and convert it to a delimited string for displaying in the UI.  I have been using the code below that I found on a blog that I have since lost the link to. However, while at the SEVDNUG meeting tonight Rob showed me an easier way to get the same output using LINQ.

Original Code:

public class CollectionUtilities 
{ 
    public string Join<T>(string delimiter, IEnumerable<T> items, Converter<T, string> converter) 
    { 
        StringBuilder builder = new StringBuilder(); 
        foreach (T item in items) 
        { 
            string converted = converter(item); 
            if (string.IsNullOrEmpty(converted) == false) 
            { 
                builder.Append(converted); 
                builder.Append(delimiter); 
            } 
        } 
        if (builder.Length > 0) 
        {
            builder.Length = builder.Length - delimiter.Length; 
        }

        return builder.ToString(); 
    } 
}
 

New Code:

public class CollectionUtilities 
{ 
    public string Join<T>(string delimiter, IEnumerable<T> items, Converter<T, string> converter) 
    { 
          return string.Join(delimiter, (items.Where(i => string.IsNullOrEmpty(converter(i)) == false).Select(i => converter(i))).ToArray()); 
    } 
}

NUnit Test:

[Test] 
public void JoinTest() 
{ 

    string[] joins = new string[]{"1", "2", "3", "4"}; 
    string joinTest = new.Join(",", joins, item => item); 
    Assert.AreEqual("1,2,3,4", joinTest); 

    joins = new string[] { "1", "", "3", "4" }; 
    joinTest = new CollectionUtilities().Join(",", joins, item => item); 
    Assert.AreEqual("1,3,4", joinTest);

    joins = new string[] { "1"}; 
    joinTest = new CollectionUtilities().Join(",", joins, item => item); 
    Assert.AreEqual("1", joinTest);  
}

How to run a CMD command as a CCNet Prebuild Task without additional bat files

I have had a problem for ages with when a build fails in CCNET is runs the file merge tasks that are part of my publishers to include the nunit test results. I finally got around to implementing something to delete those results xml files before the build runs. Originally I was just going to add it to nant but I found in the CCNET docs that there is now a prebuild section. One of the tasks included with the CCNET is an exec but it is not very clear on how to use CMD instead of creating a separate batch file. Luckily someone else figured this out at posted it to the mailing list @ http://groups.google.com.ag/group/ccnet-user/browse_thread/thread/d3f19074845bacf7/f58fa4bf7e221b3d?lnk=gst&q=prebuild+&rnum=9#f58fa4bf7e221b3d

Just in case the link goes away, below is how to do it.

<prebuild>
    <exec>
        <baseDirectory>C:\Temp</baseDirectory>
        <executable>CMD</executable>
        <buildArgs>/C RD "%ccnetworkingdirectory%" /S /Q</buildArgs>
    </exec>
</prebuild>


WEB farm - Load Balancing in Asp.net

Pretty good article on different concepts for implementing load balancing in asp.net.

http://www.c-sharpcorner.com/UploadFile/gopenath/Page107182007032219AM/Page1.aspx


LINQ Links

I have been looking into LINQ lately and have run across a ton of links that look useful. Unfortunately I have not had much time to actually play with LINQ but I thought I would pass along that links that I have been gathering for others.

Building an RSS Feed using LINQ to XML and LINQ to SQL

LINQ to Entities Web Cast

Nested Selects in LINQ to SQL

The C# ?? null coalescing operator (and using it with LINQ)

LinqDataSouce - DataItem in code behind

Dynamic String based Queries in LINQ - Dynamic Expression API

101 LINQ Samples

Lambda Expressions and Expression Trees

LINQPad (Query Manager using LINQ)

LINQ to SQL Web Cast and LINQ to SQL Web Cast Source Download

A Little LINQ

Hanselminutes Podcast 79 - LINQ to XML

Improving LINQ Code Smell with Explicit and Implicit Conversion Operators

Trying Out Persistence Ignorance with LINQ (Part I)

Trying Out Persistence Ignorance with LINQ (Part II)

DotNetRocks Shows: 270, 271, 274

LINQ To SQL Debugger Visualizer Revisited - Same Concerns Better UI

DataContext.Log - Logging LINQ To SQL Output to Console or Debugger Output Window

LINQ To SQL - Lazy Loading Properties and Specifying PreFetch When Needed - Sweet Query and Performance Control

Code Generation using CodeSmith - v4.1 - Visual Studio 2008 Support and LINQ to SQL Templates

DLinq (Linq to SQL) Performance: Part 1, Part 2, Part 3, Part 4, Part 5


WebForms and TDD

Interesting post on Webforms and testability. There is also a great comment by Scott Gunthrie (ScottGu) that has a lot of great information in it.

http://codebetter.com/blogs/jeremy.miller/archive/2007/03/07/Jay_2700_s-TDD-QuickStart_2C00_-and-the-underlying-problems-he-stumbled-into.aspx?CommentPosted=true#commentmessage


nAnt Versioning the Microsoft Way

Good post on how to use nant to update the version information in the assemblyinfo.cs the way that Microsoft does it.

Versioning the Microsoft way... with NAnt

I was inspired by a recent blog entry by Jeff Atwood here about how Microsoft versions their products and how the build number is significant. I thought it would be good to post a walkthrough of how to build your own versioning system ala Microsoft but using NAnt. I'm sure some budding geek out there could convert this to MSBuild, but you know my love of that tool so NAnt it is.

First off, NAnt has a great facility for generating that AssemblyInfo.cs file that every project has. It's the asminfo task and basically looks like this:

<?xml version="1.0"?>
<project name="Test" default="UpdateAssemblyInfo">
    <target name="UpdateAssemblyInfo">
        <asminfo output="AssemblyInfo.cs" language="CSharp">
            <imports>
                <import namespace="System.Reflection" />
                <import namespace="System.Runtime.InteropServices" />
            </imports>
            <attributes>
                <attribute type="AssemblyTitleAttribute" value="ClassLibrary1" />
                <attribute type="AssemblyDescriptionAttribute" value="" />
                <attribute type="AssemblyConfigurationAttribute" value="" />
                <attribute type="AssemblyCompanyAttribute" value="" />
                <attribute type="AssemblyProductAttribute" value="ClassLibrary1" />
                <attribute type="AssemblyCopyrightAttribute" value="Copyright (c) 2007" />
                <attribute type="AssemblyTrademarkAttribute" value="" />
                <attribute type="AssemblyCultureAttribute" value="" />
 
                <attribute type="ComVisibleAttribute" value="false" />
 
                <attribute type="GuidAttribute" value="f98c8021-fbf1-44ff-a484-946152cefdb8" />
 
                <attribute type="AssemblyVersionAttribute" value="1.0.0.0" />
                <attribute type="AssemblyFileVersionAttribute" value="1.0.0.0" />
            </attributes>
        </asminfo>
    </target>
</project>

This will product a default AssemblyInfo.cs file that looks like this:

using System.Reflection;
using System.Runtime.InteropServices;
 
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.42
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
 
[assembly: AssemblyTitleAttribute("ClassLibrary1")]
[assembly: AssemblyDescriptionAttribute("")]
[assembly: AssemblyConfigurationAttribute("")]
[assembly: AssemblyCompanyAttribute("")]
[assembly: AssemblyProductAttribute("ClassLibrary1")]
[assembly: AssemblyCopyrightAttribute("Copyright (c) 2007")]
[assembly: AssemblyTrademarkAttribute("")]
[assembly: AssemblyCultureAttribute("")]
[assembly: ComVisibleAttribute(false)]
[assembly: GuidAttribute("f98c8021-fbf1-44ff-a484-946152cefdb8")]
[assembly: AssemblyVersionAttribute("1.0.0.0")]
[assembly: AssemblyFileVersionAttribute("1.0.0.0")]

Notice however a few things. First is the Guid. We had to hard code that which might be okay, but lets dig into NAnt scripting by replacing it with a real Guid. NAnt also has the ability to let you write embedded code (C#, VB.NET, etc.) via the <script> task, so let's write a small task to do that. We'll just have it generate a new Guid and set a new custom property in the NAnt script that we'll use in our asminfo task. Create a property in the NAnt script to hold our Guid:

<property name="project.guid" value="f98c8021-fbf1-44ff-a484-946152cefdb8" />

Then use that property in our GuidAttribute:

<attribute type="GuidAttribute" value="${project.guid}" />

Finally here's the task to generate a Guid via NAnt (make the default UpdateAssemblyInfo task dependent on this one):

<target name="CreateUniqueGuid">
    <script language="C#">
        <code>
            <![CDATA[
                public static void ScriptMain(Project project) {
                    project.Properties["project.guid"] = Guid.NewGuid().ToString();
                }
            ]]>
        </code>
    </script>
</target>

Great. We now have a NAnt script that will generate a new version file with a unique Guid everytime. Next we want to tackle the versioning issue.

As described by Jensen Harris here, the Microsoft Office scheme is pretty simple:

  • Take the year in which a project started. For Office "12", that was 2003.
  • Call January of that year "Month 1."
  • The first two digits of the build number are the number of months since "Month 1."
  • The last two digits are the day of that month.

Using this we'll need to setup a couple of properties. One is to hold the year the project starts, the other is the build version we want to set:

<property name="project.year" value="2003" />
<property name="build.version" value="1.0.0.0" />

Now we could write a lot of NAnt code as there are functions to manipulate dates, but it's much easier using the <script> task and some C#. Here's the NAnt task to generate the build number using the Microsoft Office approach:

<target name="GenerateBuildNumber">
    <script language="C#">
        <imports>
            <import name="System.Globalization" />
            <import name="System.Threading" />
        </imports>
        <code>
            <![CDATA[
                public static void ScriptMain(Project project) {
                    Version version = new Version(project.Properties["build.version"]);
                    int major = version.Major;
                    int minor = version.Minor;
                    int build = version.Build;
                    int revision = version.Revision;
 
                    int startYear = Convert.ToInt32(project.Properties["project.year"]);
                    DateTime start = new DateTime(startYear, 1, 1);
                    Calendar calendar = Thread.CurrentThread.CurrentCulture.Calendar;
                    int months = ((calendar.GetYear(DateTime.Today)
                        - calendar.GetYear(start)) * 12)
                        + calendar.GetMonth(DateTime.Today)
                        - calendar.GetMonth(start);
                    int day = DateTime.Now.Day;
                    build = (months * 100) + day;
 
                    version = new Version(major, minor, build, revision);
                    project.Properties["build.version"] = version.ToString();
                }
            ]]>
        </code>
    </script>

We get the version in the NAnt script as a starter (since we're only replacing the build number) and then assign values to it (they're read-only in .NET). Then this is written back out to the property as a string.

If this is run today (February 17, 2007) it's been 49 months since the start of 2003 and today is the 17th day. So the build number is 4917. 

Here's the finaly output from this NAnt script:

using System.Reflection;
using System.Runtime.InteropServices;
 
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.42
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
 
[assembly: AssemblyTitleAttribute("ClassLibrary1")]
[assembly: AssemblyDescriptionAttribute("")]
[assembly: AssemblyConfigurationAttribute("")]
[assembly: AssemblyCompanyAttribute("")]
[assembly: AssemblyProductAttribute("ClassLibrary1")]
[assembly: AssemblyCopyrightAttribute("Copyright (c) 2007")]
[assembly: AssemblyTrademarkAttribute("")]
[assembly: AssemblyCultureAttribute("")]
[assembly: ComVisibleAttribute(false)]
[assembly: GuidAttribute("a6e7ff79-63ba-443f-8bc3-0c4b43f43ffe")]
[assembly: AssemblyVersionAttribute("1.0.4917.0")]
[assembly: AssemblyFileVersionAttribute("1.0.4917.0")]
 

And here's the full NAnt script:

    1 <?xml version="1.0"?>
    2 <project name="Test" default="UpdateAssemblyInfo">
    3 
    4     <property name="project.guid" value="f98c8021-fbf1-44ff-a484-946152cefdb8" />
    5     <property name="project.year" value="2003" />
    6     <property name="build.version" value="1.0.0.0" />
    7 
    8     <target name="UpdateAssemblyInfo" depends="CreateUniqueGuid, GenerateBuildNumber">
    9         <asminfo output="AssemblyInfo.cs" language="CSharp">
   10             <imports>
   11                 <import namespace="System.Reflection" />
   12                 <import namespace="System.Runtime.InteropServices" />
   13             </imports>
   14             <attributes>
   15                 <attribute type="AssemblyTitleAttribute" value="ClassLibrary1" />
   16                 <attribute type="AssemblyDescriptionAttribute" value="" />
   17                 <attribute type="AssemblyConfigurationAttribute" value="" />
   18                 <attribute type="AssemblyCompanyAttribute" value="" />
   19                 <attribute type="AssemblyProductAttribute" value="ClassLibrary1" />
   20                 <attribute type="AssemblyCopyrightAttribute" value="Copyright (c) 2007" />
   21                 <attribute type="AssemblyTrademarkAttribute" value="" />
   22                 <attribute type="AssemblyCultureAttribute" value="" />
   23 
   24                 <attribute type="ComVisibleAttribute" value="false" />
   25 
   26                 <attribute type="GuidAttribute" value="${project.guid}" />
   27 
   28                 <attribute type="AssemblyVersionAttribute" value="${build.version}" />
   29                 <attribute type="AssemblyFileVersionAttribute" value="${build.version}" />
   30             </attributes>
   31         </asminfo>
   32     </target>
   33 
   34     <target name="CreateUniqueGuid">
   35         <script language="C#">
   36             <code>
   37                 <![CDATA[
   38                     public static void ScriptMain(Project project) {
   39                         project.Properties["project.guid"] = Guid.NewGuid().ToString();
   40                     }
   41                 ]]>
   42             </code>
   43         </script>
   44     </target>
   45 
   46     <target name="GenerateBuildNumber">
   47         <script language="C#">
   48             <imports>
   49                 <import name="System.Globalization" />
   50                 <import name="System.Threading" />
   51             </imports>
   52             <code>
   53                 <![CDATA[
   54                     public static void ScriptMain(Project project) {
   55                         Version version = new Version(project.Properties["build.version"]);
   56                         int major = version.Major;
   57                         int minor = version.Minor;
   58                         int build = version.Build;
   59                         int revision = version.Revision;
   60 
   61                         int startYear = Convert.ToInt32(project.Properties["project.year"]);
   62                         DateTime start = new DateTime(startYear, 1, 1);
   63                         Calendar calendar = Thread.CurrentThread.CurrentCulture.Calendar;
   64                         int months = ((calendar.GetYear(DateTime.Today)
   65                             - calendar.GetYear(start)) * 12)
   66                             + calendar.GetMonth(DateTime.Today)
   67                             - calendar.GetMonth(start);
   68                         int day = DateTime.Now.Day;
   69                         build = (months * 100) + day;
   70 
   71                         version = new Version(major, minor, build, revision);
   72                         project.Properties["build.version"] = version.ToString();
   73                     }
   74                 ]]>
   75             </code>
   76         </script>
   77     </target>
   78 
   79 </project>

Enjoy!


Good ASP.NET Web.Config Tips

Ran across a two part series on web.config tips. All of the tips look really good and I am plan on using several on them on my current project.

 

Part 1: http://scottwater.com/blog/archive/quick-tips-for-asp-net-part-one/

Part 2:http://scottwater.com/blog/archive/asp-net-web-config-tips-part-two/