Friday, August 08, 2008

Exceptions

If only the System.Exception class were abstract or only contained protected constructors... This would force people to define their own custom exceptions (a good thing), but still wouldn't solve humankind's insatiable appetite for the catch-all exception handler.

Wednesday, August 06, 2008

System.OutOfMemoryException Part 2

We've been seeing loads of these recently, not as a result of memory leaks (the usual suspects) but the result of trying to do too much at one time. Now that 64-bit operating systems are here, couldn't we take advantage of the extra virtual address space? Microsoft have a comparison of 32-bit and 64-bit memory architecture for 64-bit editions of Windows XP and Windows Server 2003
outlining the changes between the two memory architectures. Next step is to see whether the 64-bit operating systems are approved.

UnhandledException

From .NET 2.0 onwards, unhandled exceptions on any thread cause the process to terminate. This is - according to a number of experts - the "correct" behaviour, and is different to how they were handled back in .NET 1.1.

The AppDomain.UnhandledException event allows you to perform some kind of diagnostics (such as logging the exception and stack trace, or performing a mini-dump) after such an exception is thrown, but the CLR is going to exit - whether you like it or not - just as soon as all event handlers have run.

So... if you are a responsible application developer who is spawning new threads (or queueing user work items to the thread pool) please please please ensure that _if_ you can handle the exception, that it is caught and not rethrown. Even if it means storing the exception and letting another thread handle it, as in the case of the asynchronous programming model (APM).

Wednesday, June 25, 2008

Goodbye to Awkward Dictionaries in .NET

I take enjoyment in analytic work, and often find myself writing code to empirically test a bunch of XML files to see if I've got the "implied schema" right. For example, I might have 500 files of similar structure, and I'd want to see the possible values (and count) of the "/Reports/Globals/@Client" node's value (using XPath). Usually this would entail using a Dictionary and every access would have to test if the dictionary already contains the key ... until now. After seeing that Ruby's designers allow you to specify a default value for a Hash, I took another step forward, allowing a user of the class to provide a default function, allowing more complex defaults such as empty lists.

using System;
using System.Collections.Generic;

namespace ConsoleApplication6
{
class Program
{
public delegate T DefaultFunction<T>();

public class RubyDictionary<TKey, TValue>
{
private IDictionary<TKey, TValue> inner = new Dictionary<TKey, TValue>();
private DefaultFunction<TValue> defaultFunction;

private static TValue Default()
{
return default(TValue);
}

public RubyDictionary()
{
defaultFunction = Default;
}

public RubyDictionary(TValue defaultValue)
{
defaultFunction = delegate()
{
return defaultValue;
};
}

public RubyDictionary(DefaultFunction<TValue> defaultFunction)
{
this.defaultFunction = defaultFunction;
}

public TValue this[TKey key]
{
get
{
if (!inner.ContainsKey(key))
{
inner.Add(key, defaultFunction());
}
return inner[key];
}
set
{
inner[key] = value;
}
}
}

static void Main(string[] args)
{
try
{
RubyDictionary<string, int> dict = new RubyDictionary<string, int>();
Console.WriteLine(dict["9"]);
dict["8"] += 1;
Console.WriteLine(dict["8"]);
dict["7"] = 5;
Console.WriteLine(dict["7"]);
dict["6"]++;
Console.WriteLine(dict["6"]);

dict["5"]--; dict["5"]--;
Console.WriteLine(dict["5"]);


RubyDictionary<string, IList<string>> lists = new RubyDictionary<string, IList<string>>(delegate() { return new List<string>(); });
lists["shopping"].Add("bread");
lists["shopping"].Add("milk");
lists["todo"].Remove("write this dictionary class");

foreach (string item in lists["shopping"])
{
Console.WriteLine(item);
}

RubyDictionary<int, int> foo = new RubyDictionary<int, int>(777);
Console.WriteLine(foo[8] - 111);
}
catch (Exception exception)
{
Console.Error.WriteLine(exception);
}
finally
{
if (System.Diagnostics.Debugger.IsAttached)
{
Console.WriteLine("Press enter to continue...");
Console.ReadLine();
}
}
}
}
}

Saturday, May 31, 2008

IEnumerable vs IEnumerator

IEnumerator<T> generic interface defines "cursor" methods for iterating over a collection:
T Current { get; }
bool MoveNext();
void Reset();
void Dispose();

IEnumerable<T> generic interface defines just one method:
IEnumerator<T> GetEnumerator();

C# supports iterator blocks. These are blocks of code (i.e. method or property getter blocks) in which you "yield" a return value at various points in the code. The compiler uses hidden magic to create a nested type that implements both IEnumerable<T> and IEnumerator<T>; the body of your original method is stubbed out to call into this new object, and all your original logic is implemented in the IEnumerator<T>'s MoveNext method.

The C# foreach keyword is quite flexible and operates on any object that exposes a public GetEnumerator() method (the 'collection' pattern) - the object doesn't have to implement IEnumerable or IEnumerable<T>.

Thursday, May 29, 2008

Experiment in the Fidelity of UTC DateTime

// make sure your local clock is not displaying GMT

DateTime a = new DateTime(2008, 7, 6, 4, 3, 2, DateTimeKind.Utc);
DateTime b = new DateTime(2008, 7, 6, 4, 3, 2, DateTimeKind.Local);
DateTime c = new DateTime(2008, 7, 6, 4, 3, 2, DateTimeKind.Unspecified);

// no surprises here...
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);

// and again, no surprises. this makes it that much more explicit.
Console.WriteLine("-");
Console.WriteLine(a.ToUniversalTime());
Console.WriteLine(b.ToUniversalTime());
Console.WriteLine(c.ToUniversalTime());

// notice the Z(ulu) for UTC, the time zone for local, and the (nothing) for unspecified
Console.WriteLine("-");
XmlSerialize(a);
XmlSerialize(b);
XmlSerialize(c);

// ooh! our first loss of fidelity
Console.WriteLine("-");
DataSet dataSet = new DataSet();
DataTable dataTable = dataSet.Tables.Add();
DataColumn dataColumn = dataTable.Columns.Add("DateTime", typeof(DateTime));
dataTable.Rows.Add(a);
dataTable.Rows.Add(b);
dataTable.Rows.Add(c);
Console.WriteLine(dataSet.GetXml());

// those .net framework guys fight back with the DateTimeMode property (new in 2.0)
// understandably, weird stuff starts happening when not all input dates are of the same kind
Console.WriteLine("-");
DataSet dataSet2 = new DataSet();
DataTable dataTable2 = dataSet2.Tables.Add();
DataColumn dataColumn2 = dataTable2.Columns.Add("DateTime", typeof(DateTime));
dataColumn2.DateTimeMode = DataSetDateTime.Utc;
dataTable2.Rows.Add(a);
dataTable2.Rows.Add(b);
dataTable2.Rows.Add(c);
Console.WriteLine(dataSet2.GetXml());

//you can't just get the bytes for a DateTime, it's a struct.
//Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(a)));
//Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(b)));
//Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(c)));

Console.ReadKey();

Tuesday, May 27, 2008

Flex interaction with JavaScript (and ASP.NET)

It just doesn't quite work out of the box.

First, a flash object within an HTML form element fails when the flash runtime tries to register the callbacks you defined in your Flex app (e.g. a callback added in ActionScript using ExternalInterface.addCallback("someFunction", someFunctionPointer) is evaluated in the browser as __flash__addCallback(objectId, "someFunction"). A hack to get around this would be to assign your Flash object to window.objectId as soon as you've created it: hey presto! you've worked around one limitation.

Second. There appears to be a race condition if you need to initialize your Flex app with JavaScript data as soon as both are ready. At first, I thought I had a choice... push from JavaScript or pull from Flex. To push, we need to know that the callback has been added in the browser: either by polling or by registering an event. I refuse to poll, and I can't find a way to register for the event. The remaining option is to pull. The question is, will the source data (JavaScript) have been assigned by the time my Flex Application's applicationComplete event has fired? No idea, really.

Friday, April 25, 2008

Notes On the :: Operator in C#

Have you seen this construct before in auto-generated partial classes (e.g. code-behind .designer.cs for a web control)?

protected global::System.Web.UI.WebControls.TextBox MyTextBox;

Basically it's there to ensure that the System namespace is the same System namespace that's declared in the global namespace. So, why would they need this? Consider that you might define your new UserControl -derived class in a namespace like this:

namespace MyNamespace.System { ... }

Visual Studio's code-generator would create a partial class in the MyNamespace.System namespace, in which it would define a field MyTextBox of type System.Web.UI.WebControls.TextBox. However, when the time came for the compiler to put the puzzle together, the namespace resolution rules would match the "System" part of the member's type to the [unintended] "MyNamespace.System" namespace. Not cool.

Enter the global namespace alias, and the namespace alias qualifier operator. (Wow, that sentence is a mouthful).

To force the compiler to use the intended "System" namespace (which resides in the global namespace, not the MyNamespace namespace), the MyTextBox member is declared with the global:: namespace alias qualifier.

Obviously, things NOT to do include:
1) using global = System.Diagnostics;
Generates the compiler warning: Defining an alias named 'global' is ill-advised since 'global::' always references the global namespace and not an alias.
2) namespace System { class MyClass { } }
No warning from the compiler (Java doesn't let you do the equivalent).

Further usage patterns:

using sys = global::System; //<-- nice and recursive :-)
using diag = System.Diagnostics;
using dbg = System.Diagnostics.Debug;

sys::Object o = new System.Object();
diag::Debug.Assert(true); // <-- OK
dbg.Assert(true); // <-- OK, but important to make the distinction that it's a "type" alias and not a "namespace" alias.

Wednesday, March 19, 2008

More HTTP Compression in IIS 6.0

Further to my previous post, I've come across more issues with HTTP compression and IIS 6.0. IIS allows the compression of dynamic files (e.g. files generated on the fly by ASP.NET handlers), but Internet Explorer doesn't appear to like it when the dynamic file is a zip itself. Unfortunately, compression is controlled at the "Service" level (right-click on Web Sites, rather than right clicking on an individual web site) in IIS manager snap-in, and using shared infrastructure can mean that your web site breaks immediately for no apparent reason. Lucky for you though, the metabase can be tweaked to enable/disable compression at the "Site" level... you just have to be able to figure out the site number.

adsutil.vbs SET W3SVC/687245286/root/DoDynamicCompression False
adsutil.vbs SET W3SVC/687245286/root/DoStaticCompression True

IIS from the dark ages

Back in IIS 5.1 you can easily run multiple sites, just not all at once. Run the following scripts to enumerate the sites already installed, and copy an existing site to a new site!
[code]
C:\inetpub\AdminScripts>CScript.exe .\adsutil.vbs COPY W3SVC/3 W3SVC/4
C:\inetpub\AdminScripts>CScript.exe .\adsutil.vbs ENUM W3SVC /P
[code]

Wednesday, March 12, 2008

(De)bugger

A neat trick to assist debugging in C# or JavaScript, when you have no (or little) control over how or when the process is started: use the System.Diagnostics.Debugger.Attach() method or the debugger statement.

Monday, February 25, 2008

Visual Studio Dependencies

You're building a project named A.exe and you've included a file reference to the assembly B.dll (the value of the "CopyLocal" option is set to "true"). Assembly B references C.dll and D.dll, one of which is installed to the GAC. When you hit the build button, a copy of B is made in the project's output directory. Now comes the tricky part: without the ability to specify (or query) the "CopyLocal" option for the dependent assemblies, does msbuild.exe copy C.dll and D.dll? The answer: if the dependent assembly cannot be found in the GAC, then it's copied; otherwise it won't.

One more trick here: don't use Windows Explorer to try and view the GAC on another machine; you can't. Something about a shell extension? You can see the GAC with a command prompt and a mapped network drive.

To disable the shell extension, you can set the following registry value:
HKLM\Software\Microsoft\Fusion\DisableCacheViewer [DWORD] to 1. This will enable you to view the GAC of a remote machine.

Friday, December 14, 2007

Sharing the Strong Name Key File

Pedantry in motion: even though you shouldn't ever change your public key (see log4net versions 1.2.9 - 1.2.10 for an excellent reason) I still like to share a single strong name key file (.SNK) between all projects in a solution. Using Visual Studio 2005, this can be accomplished thusly:
1) Store the key in a parent folder of the project, so it can be accessed by all projects in the solution.
2) Add it as a link (use the add existing file menu)
3) In the signing tab of the project properties window, check the "sign the assembly" check box and choose the path from the drop down list. You will notice this is the path to the actual .snk file - not a local copy of that file.

Wednesday, December 12, 2007

Anonymous Methods

It looks like I've fallen off the bleeding edge again; this time I'm talking about anonymous methods: C#'s answer to the Java concept of anonymous inner classes. They've been available since C# 2.0 came out nearly two years ago. See this guy's blog for some cool stuff you can do with them. I've especially taken to sorting lists this way. :)

Saturday, December 08, 2007

SQL Server 2005 Connections

So, you can see your local database server using SSMSEE, but when you fire up Visual Studio you can't find it anymore. First, you need to set up the surface area configuration to allow remote TCP/IP connections, then you need to configuration manager to choose a TCP port. If you choose 1433 then Hey, Presto! and everything should start working magically. If you intend to connect to the database server from another machine, don't forget to allow traffic over port 1433 using Windows Firewall.

Monday, July 16, 2007

Multi-stage deployments

I was recently foxed, I'll have to admit. Even when you don't think your own code's behaviour will impact another application, distributed shared environments seem to make it a likely event. For instance, you deploy a component upgrade onto one application server only... but you are unaware of the fact that references to your component are cached by clients, each of which can switch application servers at the drop of a hat. The result: thousands of errors an hour and irate support teams! :-)

Anyway, the lesson learned is that deployments - like code - should be thoroughly planned and all assumptions should be documented and passed over by someone who knows the target environment really well.

The other lesson learned is: don't change anything that you don't NEED to change. If you are required to alter the behaviour of one method, that's all you should do. Don't be clever and think that you can now refactor the code too; you'll get another opportunity to do that if it's really necessary. I guess it boils down to the fact that if your code was tightly coupled to start with - which, let's face it, a lot of code is - then you're more likely to break something. Something as silly as a client caching the method ID from an IDL definition instead of late binding using the method name can cause hours of anguish. Don't say I never warned you.

Tuesday, February 27, 2007

MSF Nostalgia

I'm determined not to make the same mistake again. A keen follower of process methodologies like RUP and MSF (and ACA.NET), I threw caution to the wind in developing a quote-unquote "prototype" recently. There wasn't much in the way of requirements, and it seemed like a cinch. Soon it became apparent that the business owners' visions weren't aligned and nobody could agree what the system should do. And I kept quiet because I had no idea what it should do; I'm the technology guy who would put it together from a requirements document. WRONG! What I should have done is forced them to agree on the vision ... then on the behaviour ... then on the look and feel. Lesson #1: to have their sign-off on these documents would have made my life a lot easier in the final stages where we quibbled over the system's behaviour (my interpretation of their ever-changing minds). Lesson #1.5: to get the sign-off of more senior people than those I dealt with every day would have more impact than the easily vetoed sign-off of not-so-high-up-management. Lesson #2: most importantly, have a signed-off requirements document. This you can use as a test plan, and you can use to check the boxes that everything you promised has been delivered. In summary, I think I delivered far too much functionality for free - but that's not necessarily good for the business because there was never a 100% clear and auditable understanding between myself and them. Lesson #3: never underestimate the importance of "I'd like that in writing".

Thursday, February 22, 2007

IExecutionStep

Why write a blog entry about the ASP.NET HTTP pipeline when someone else has already done it better? I'm talking about Rick Strahl's Low level look at ASP.NET architecture. Note to self: as soon as you have a box running IIS 7, see if you can't reverse-engineer everything down so far as to understand even the IExecutionStep interface.

Tuesday, February 13, 2007

Hidden Face of NTFS Permission Issues

How can everyone be so naïve about NTFS permissions? Just yesterday I had an Associate Director bring a web site to its knees by cut-and-pasting a configuration file from somewhere else on the system. Today's problem was far more obfuscated though, and we would have saved six hours of 3 devs' (and countless users') time if the same (recently promoted) Associate Director had looked in the event log as suggested to him. As it turns out, when the IUSR_MACHINENAME user account is locked out - and IIS is configured to only allow anonymous access - IIS will not serve any static content. If you allow Integrated Windows Authentication as well, then IIS will fall back to that mechanism (a corollary: if your service delivery guy is an administrator, everything will appear fine to him). In the first instance, a Filemon trace won't show failures of w3wp.exe trying to access the files, because it's the logon that's failing - and this can be very confusing! In the second instance, it will clearly display the NT username (of the token that w3wp.exe's associated with the current request) next to the file open failure.

So, next time you see the error: access denied, and you've ruled out the fact that a Muppet has messed up the permissions on a critical file... look in the Event Viewer and save yourself a bunch of time. It's there for a reason. Use it. Take a step further even, and write to it yourself!

Friday, February 09, 2007

HTML, JavaScript and Background-Color

Well this had me confused for an hour or so. Consider the HTML element below:

<div style="background-color:red">

First, I tried to set the color programmatically using JavaScript. I knew that layer.style.background-color wouldn't work so I typed in layer.style["background-color"] = "green"; No luck. Eventually, I noticed that layer.style["background"] worked, and I went on my merry way. For about 30 seconds. Now I needed to read the background-color value from a layer, and my previous two attempts were turning up empty strings.

With a bit of Googling, I discovered that background-color should be accessed as layer.style.backgroundColor (or layer.style["backgroundColor"]).

Google saves the day.

(A couple of weeks later, and programmatically setting the css class of an HTML element has tripped me up. It seems the property is called "className" in JavaScript.)