ToDebugString() – give me some debug info about my object, e.g. Request.Url

by Oliver Fri, September 16 2011 20:06

Lately, I was having trouble debugging certain parts of my code in Visual Studio, and all I wanted to know was the value of some variable at some point in time. Well, I’d use some logging if I could just get at that value easily. But for some objects I don’t really know what I’m looking for or where I should be looking for it. So just give me the values of all the members of that object, will ya? And could you recurse that? But no deeper than 3 levels, alright? Or let’s say… 5?

public static string ToDebugString(this object obj, int maxdepth, int depth=0)
{
    if (obj == null)
        return "null";
 
    if (obj is IConvertible)
        return obj.ToString();
 
    if (depth >= maxdepth)
        return "...";
 
    var sb = new StringBuilder();
 
    if (depth > 0)
        sb.AppendLine();
 
    foreach (var propertyInfo in obj.GetType().GetProperties(BindingFlags.Public|BindingFlags.Instance))
    {
        sb.Append(new string(' ', 2*depth)).Append(propertyInfo.Name).Append(": ");
        try
        {
            var value = propertyInfo.GetValue(obj, new object[0]);
            sb.AppendLine(ToDebugString(value, maxdepth, depth + 1));
        }
        catch (Exception ex)
        {
            sb.AppendLine(string.Format("[{0}]", ex.Message));
        }
    }
 
    // remove newline from end of string
    var newLine = Environment.NewLine;
    if (sb.Length >= newLine.Length)
        sb.Replace(newLine, "", sb.Length - newLine.Length, newLine.Length);
 
    return sb.ToString();
}
With this little helper I can now simply call anyobject.ToDebugString(4 /* maxdepth */) and I get a nicely formatted debug view of that object; e.g. Request.Url.ToDebugString(3) gives me:
AbsolutePath: /logg.aspx
AbsoluteUri: http://localhost:55235/logg.aspx
Authority: localhost:55235
Host: localhost
HostNameType: Dns
IsDefaultPort: False
IsFile: False
IsLoopback: True
IsUnc: False
LocalPath: /logg.aspx
PathAndQuery: /logg.aspx
Port: 55235
Query:
Fragment:
Scheme: http
OriginalString: http://localhost:55235/logg.aspx
DnsSafeHost: localhost
IsAbsoluteUri: True
Segments:
Length: 2
LongLength: 2
Rank: 1
SyncRoot:
Length: 2
LongLength: 2
Rank: 1
SyncRoot: ...
IsReadOnly: False
IsFixedSize: True
IsSynchronized: False
IsReadOnly: False
IsFixedSize: True
IsSynchronized: False
UserEscaped: False
UserInfo:

Nice Smile

Right now this method chokes on indexed properties but once I’ll need it I’ll go and look for a way to include them. It also chokes any exceptions on the way to just get the job done.

Happy coding!

Tags:

.NET | C# | Debugging | Software development | Tips & Tricks | Visual Studio | developer

Unexpected EOF encountered in BCP data-file

by Oliver Thu, September 15 2011 17:05

Today, I tried importing a CSV file like the following into one of our MS SQL Server databases:

Id;Latitude;Longitude
4610;43.7119;-1.0737
5502;49.4297;-1.806
11360;46.9343;-1.8875

I tried it using the following command line:

   1: bcp GeoDataImport in geodata.csv -w -t; -T

but that threw the mentioned error:

“Unexpected EOF encountered in BCP data-file”

cmd> bcp GeoDataImport in geodata.csv -w -t; -T
Starting copy...
SQLState = S1000, NativeError = 0
Error = [Microsoft][SQL Server Native Client 10.0]Unexpected EOF encountered in BCP data-file
0 rows copied.
Network packet size (bytes): 4096
Clock Time (ms.) Total     : 1

I’ve had this problem before and somehow managed to remember that it might have something to do with the encoding of the file. So I opened it with Notepad++ where you can easily check and change the file encoding and found it was ANSI encoded:

image

Well, the UCS-2 Little Endian encoding is what SQL Server expects as default encoding, so I changed the encoding, saved the file and imported it again – with success. UCS-2 might be something you rarely hear about – that’s because it’s been superseded by UTF-16 but in most situations they are pretty much identical (check out http://en.wikipedia.org/wiki/UTF-16/UCS-2 for more info).

That’s all for now – happy coding!

Tags:

MS-SQL Server | developer | Tips & Tricks

Creating a new module in ‘discoverize’ – using multi-file templates and good ol’ batch scripts

by Oliver Fri, July 15 2011 09:07

For our portal software discoverize I was looking for a way to create new modules faster and more reliably. The basic structure would always be the same, so a Visual Studio multi-file template seemed appropriate:

module

Well, unfortunately I didn’t find a way to create new folders with that approach. Multi-file templates really do what they say: they create multiple files from templates. Nothing else.

So I put together a short batch script that would create the directory structure needed for any new module:

image

I can quickly open a new command line window by using any one of several Visual Studio extensions (e.g. PowerCommands for Visual Studio 2010):

image

… and simply run:

image

Now going back to Visual Studio we have to include the new Feature folder in the project:

image

Then hit Ctrl + Shift + A to open the Add New Item dialog, select ‘Discoverize Module’ and type Feature in the Name textbox (unfortunately, there seems to be no easy way to automatically put the name of the folder inside that textbox):

image

This step will generate three code files, that are the backbone of every module: FeatureConfig.cs, FeatureModule.cs, and FeatureViews.cs. Finally, our multi-file item template comes into play!

Handling the multi-file template

The multi-file item template for a new module consists of four files: the template definition file Module.vstemplate and the template code files Config.cs, Module.cs, and Views.cs:

image

Those four files have to be packed into a zip file and copied to a folder underneath %UserProfile%\My Documents\Visual Studio 2010\Templates\ItemTemplates\ – I put this one into Visual C#\Code. That’s how it appeared under the Visual C# –> Code section in the Add New Item dialog.

Since it is somewhat cumbersome to zip and copy updated versions of the template (especially during early development where I keep adjusting and tuning the template code), I put together another batch file that does that for me. It basically does three things:

  1. Get the name of current folder to use as name for the zip file (found the solution here)
  2. Use 7-zip to zip the four files.
  3. Copy the zip file to the VS custom template directory.

image

The real script contains some safety nets and more output so that in case it won’t work across all developer machines I can get quick feedback as to what exactly didn’t work instead of just “it didn’t work”.

Happy Coding!

Tags: ,

Software development | developer | Tips & Tricks | Productivity

Code evolution + LINQ

by Oliver Tue, June 28 2011 01:27

Three year old code:

   1: protected string CpeBehaviorIds() 
   2: { 
   3:     var cpeIds = ""; 
   4:  
   5:     var helpItems = GetHelpItems(divGlobal); 
   6:  
   7:     foreach (var helpItem in helpItems) 
   8:         cpeIds += helpItem.CollapsiblePanelBehaviorID + ','; 
   9:  
  10:     // remove comma at end 
  11:     if (cpeIds.Length > 0) 
  12:         cpeIds = cpeIds.Remove(cpeIds.Length - 1); 
  13:  
  14:     return cpeIds; 
  15: } 
  16:  
  17: protected string CpeExpandIds() 
  18: { 
  19:     var cpeIds = ""; 
  20:  
  21:     var helpItems = GetHelpItems(divGlobal); 
  22:  
  23:     foreach (var helpItem in helpItems) 
  24:         cpeIds += helpItem.CollapsiblePanelExpandID + ','; 
  25:  
  26:     // remove comma at end 
  27:     if (cpeIds.Length > 0) 
  28:         cpeIds = cpeIds.Remove(cpeIds.Length - 1); 
  29:  
  30:     return cpeIds; 
  31: } 
  32:  
  33: protected static List<HelpItem> GetHelpItems(Control control) 
  34: { 
  35:     var idList = new List<HelpItem>(); 
  36:  
  37:     if (control is HelpItem) 
  38:         idList.Add(control as HelpItem); 
  39:     else 
  40:         foreach (Control child in control.Controls) 
  41:             idList.AddRange(GetHelpItems(child)); 
  42:  
  43:     return idList; 
  44: }
New code:
   1: protected string CpeBehaviorIds() 
   2: { 
   3:     return divGlobal.Controls<HelpItem>().Select(h => h.CollapsiblePanelBehaviorID).JoinNonEmpty(","); 
   4: } 
   5:  
   6: protected string CpeExpandIds() 
   7: { 
   8:     return divGlobal.Controls<HelpItem>().Select(h => h.CollapsiblePanelExpandID).JoinNonEmpty(","); 
   9: }
  10:  
  11: public static string JoinNonEmpty(this IEnumerable<string> values, string separator)
  12: {
  13:     return String.Join(separator, values.Where(s => !string.IsNullOrEmpty(s)).ToArray());
  14: }

LINQ – we love you!

Oliver

P.S. Controls<Type>() is another extension method defined like this:

   1: /// <summary>
   2: /// Returns all controls of the given Type that are found inside this control.
   3: /// Searches recursively.
   4: /// </summary>
   5: public static IEnumerable<T> Controls<T>(this Control control) where T : Control
   6: {
   7:     var controls = control.Controls;
   8:  
   9:     if (controls.Count == 0) return new List<T>(0);
  10:  
  11:     var newColl = new HashedSet<T>();
  12:     foreach (Control child in controls)
  13:     {
  14:         if (child is T)
  15:             newColl.Add((T) child);
  16:  
  17:         var childColl = child.Controls<T>();
  18:         foreach (T ctrl in childColl)
  19:             newColl.Add(ctrl);
  20:     }
  21:  
  22:     return newColl;
  23: }

Tags:

C# | Software development | developer

Gender: Web Developer vs. Web Developer

by andrej Thu, March 10 2011 14:54

Web Developers vs Web Developers from Cassie McDaniel on Vimeo.

I love the role the designer plays in this video :)

[via graphic.is]

Tags: ,

developer