A better tracing routine

In .NET 4.5 three new attributes were introduced. They can be used to pass into a method the details of the caller and this can be used to create better trace or logging messages. In the example below, it outputs tracing messages in a format that you can use in Visual Studio to automatically jump to the appropriate line of source code if you need it to.

The three new attributes are:

If you decorate the parameters of a method with the above attributes (respecting the types, in brackets afterwards) then the values will be injected in at compile time.

For example:

public class Tracer
{
    public static void WriteLine(string message,
                            [CallerMemberName] string memberName = "",
                            [CallerFilePath] string sourceFilePath = "",
                            [CallerLineNumber] int sourceLineNumber = 0)
    {
        string fullMessage = string.Format("{1}({2},0): {0}{4}>> {3}", 
            memberName,sourceFilePath,sourceLineNumber, 
            message, Environment.NewLine);

        Console.WriteLine("{0}", fullMessage);
        Trace.WriteLine(fullMessage);
    }
}

The above method can then be used to in preference to the built in Trace.WriteLine and it will output the details of where the message came from. The format that the full message is output in is also in a format where you can double click the line in the Visual Studio output window and it will take you to that line in the source.

Here is an example of the output:

c:\dev\spike\Caller\Program.cs(13,0): Main
>> I'm Starting up.
c:\dev\spike\Caller\SomeOtherClass.cs(7,0): DoStuff
>> I'm doing stuff.

The lines with the file path and line numbers on them can be double-clicked in the Visual Studio output window and you will be taken directly to the line of code it references.

What happens when you call Tracer.WriteLine is that the compiler injects literal values in place of the parameters.

So, if you write something like this:

Tracer.WriteLine("I'm doing stuff.");

Then the compiler will output this:

Tracer.WriteLine("I'm doing stuff.", "DoStuff", "c:\\dev\\spike\\Caller\\SomeOtherClass.cs", 7);

Parser Error Message: Ambiguous match found

Symptom

On deploying a newly precompiled web site, the error message as displayed by ASP.NET is as follows:

Server Error in ‘/’ Application.

Parser Error

Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.

Parser Error Message: Ambiguous match found.

Source Error:

Line 1:  <%@ control language="C#" autoeventwireup="true" enableviewstate="false" inherits="WebSiteControls_Offers_TypeFilter, App_Web_typefilter.ascx.bd9a439f" %>

Line 2:
Line 3: <%--

Source File: /WebSiteControls/Offers/TypeFilter.ascx    Line: 1


Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053

System Information

This may or may not be relevant, but it reflects my set up at the time I discovered this issue.

  • Web Site project
  • Visual Studio 2008
  • .NET 3.5
  • IIS 6.0

 

Reason

The reason for this is that a control, in this case a Repeater, in the User Control had a similar name as a field on the code behind. The only difference between the two the case. One was called “offerTypes” (in the code behind, an IEnumerable containing entities from the business layer), the other “OfferTypes” (a ASP.NET Repeater control).

Solution

Rename one or other so that the names differ by more that case alone. In my case, I renamed the field referring to the entities to offerTypeInformation.

Tip of the Day #17: Duplicate input fields

Don’t allow duplicate input fields into your form.

The other day I was trying to debug a bug in an application that I maintain. The code created a set of pagination buttons at the top of the page with previous and next buttons. At some point a request had come in that the buttons needed to be replicated at the bottom of the page. Since the HTML was being built up in a string and dumped in a literal control in the first place the developer that was tasked with making the change just dumped the string into two literal controls, the original at the top of the page, and the new one at the bottom of the page. The previous and next buttons use hidden input field to tell the application which actual page number the buttons correspond to. And these were now duplicated and as a result the previous and next buttons ceased to work.

Here is an example of something similar:

<input id="first-hidden-field" value="123" type="hidden" name="some-name" />
<input id="submit-button" value="Submit" type="submit" />
<input id="second-hidden-field" value="456" type="hidden" name="some-name" />

When the form fields are returned to the application and the field “some-name” is queried the result back is a combination of the two fields with the duplicate name. In this case:

string someName = Request.Form["some-name"];

will result in the value of “123,456” being stored in the string. Basically, it is the comma separated form of all the input fields with the given name.

Errors like these drive me insane

Today I was trying to fix up a website for one of our clients. I got the site out of source control but somehow or other it wouldn’t compile. I’m not going to talk about the fact it didn’t compile out of the box – We all know that is not a good situation and the person who allows source to get into a state like that needs to be slapped repeatedly with a wet fish.

What I’m going to talk about is what the eventual error turned out to be because it is not something I’ve ever seen before and it was such a bizarre thing that I can only hope it isn’t common. But if you are afflicted by it you will be pleased to know that the solution is easy, even if the discovery of what the problem actually was wasted several hours.

If you are reading this then I suspect you will probably be suffering from this problem in which case you are probably now yelling “STOP BABBLING MAN AND TELL ME WHAT TO DO”.

First, a description of the problem:

There is an ASP.NET web site project (probably does the same thing on a web application… And let’s not get in to why this is a web site project, it’s an old project and the standard now is web applications) with a number of web forms in it.

The ASPX for the default page currently looks something like this:

<%@ Page Language="C#" AutoEventWireup="true"
      CodeFile="Default.aspx.cs" Inherits="Default" %>
<html>
<head><title></title></head>
<body>
    <form id="form1" runat="server">
        Stuff that's on my page
        <asp:Label ID="MyLabel" runat="server"></asp:Label>
    </form>
</body>
</html>

Nothing too odd about that, you might say… And you’d be right. There is nothing at all wrong with this page. However, when you go to compile your website you get this error:

Infuriation 2
The name ‘MyLabel’ does not exist in the current context

But… but… but… You can see that MyLabel exists on the ASPX page and if you type in the C# or VB source file you’ll see that intellisense finds the object perfectly well. So what is going on?

Well, it is interesting to note that Page1 and Page2 are very similar to Default. In fact, so similar that when they were created the person that did this just copied Default.aspx and Default.aspx.cs (or Default.aspx.vb if that’s your poison). What they didn’t do when they made the copies was to change the page directive at the top that has the Inherits attribute that points to Default. So, Page1 and Page2 are inheriting the behaviour in Default.

When this first happened that wasn’t a problem. Page1 and Page2 had just minor cosmetic differences, the behaviour was the same and no one noticed.

At some point later someone came along and added MyLabel to Default.aspx… This still didn’t make a difference. Everything worked as normal.

Then someone came along and realised that MyLabel needed to change on some condition and added some code into the Default.aspx.cs file that modified MyLabel. At this point all hell broke loose!

Suddenly, MyLabel can’t be found and no one can figure out why. It is there on the ASPX page, intellisense picks it up, the stupid compiler can’t see it.

The Solution

Eventually, after spending a couple of hours on the problem and batting it around some collegues and doing bit of brainstorming someone (let’s call him Craig Muirhead because he figured it out in the end and deserves the credit) comes up with the idea that perhaps other pages are inheriting the wrong class. A quick find in files on the name of the class and we found it was referenced by 4 other pages. It takes a matter of moments to fix all those files to point to their respective code behind files/classes rather than the one on our hapless page. And all of a sudden everything compiles.

Technorati Tags: ,,,,

Tip of the Day #7 (SysInternals)

I’ve visited the SysInternals site a few times over the course of my career because of some strange problem that I just couldn’t track down. The amount of information about what is actually happening on your system that the SysInternals tools provide is phenomenal. The site was run by Mark Russinovich and Bryce Cogswell until they got hired by Microsoft. However, the tools are still available and being updated, only now they are hosted by Microsoft themselves.

So, today’s tip is to visit the SysInternals page on Microsoft‘s TechNet site and familiarise yourself with what is available. You might find that one day it will save you hours of frustration.

The Conditional attribute in .NET

One of the odd thoughts that shoot across my brain today was how does Debug.Assert() work? I mean there are not separate debug and release builds of the .NET Framework so how does it know what sort of build it is?

A quick look in reflector revealed that Debug.Assert is defined as:

[Conditional("DEBUG")]
public static void Assert(bool condition, string message)
{
    TraceInternal.Assert(condition, message);
}

Interesting… I don’t recall having ever come across the Conditional attribute before.

What this actually does is tell the compiler to only call the method when the supplied preprocessor symbol is defined. The method will still be compiled and will still exist in the assembly. So, in a debug build a program that looks like this:

static void Main(string[] args)
{
    Debug.Assert(true, "This condition must be true");
}

will still look like that, but when compiled in release mode, will look like this:

private static void Main(string[] args)
{
}

But what about more complex code. What happens if the method call includes calls to other methods. Like this:

static void Main(string[] args)
{
    Debug.Assert(GetTheCondition(), GetTheMessage());
}

So be careful – If the calls made as parameters into a method such as Assert modify the state of the object then that won’t happen in release mode. For example, if the whole program looks like this:

class Program
{
    static int someState = 0;
    static string someOtherState = "123";

    static void Main(string[] args)
    {
        Debug.Assert(GetTheCondition(), GetTheMessage());
        Console.WriteLine("SomeState = {0}", someState);
        Console.WriteLine("SomeOtherState = {0}", someOtherState);
        Console.ReadLine();
    }

    private static string GetTheMessage()
    {
        someOtherState += "abc";
        return someOtherState;
    }

    private static bool GetTheCondition()
    {
        someState++;
        return (someState!=0);
    }
}

Then the output from a release build will be different from a debug build.

This is the debug output:

SomeState = 1
SomeOtherState = 123abc

And this is the release output:

SomeState = 0
SomeOtherState = 123

Tags:

Follow

Get every new post delivered to your Inbox.

Join 25 other followers