dotNoted

Icon

Observations of .Net development in the wild

Paths in Asp.Net 2

It’s not immediately evident how to find where you are currently, in terms of the web site and server, in an Asp.Net app. MSDN comes to the rescue here, mostly, with a decoder ring page, but it’s not easy to find itself.
 
 
Basically, the points are:
 
  • Use the tilde character – "~" – in server controls and code, since it parses this out to mean "this application’s root URL". Don’t try to use this in JS or other client-side stuff, though.
  • HttpRequest.ApplicationPath provides this same info, but is less declarative and more clutter
  • HttpRequest.CurrentExecutionFilePath gives you the app root, any folders and the executing page. This is true even after a Server.Transfer or a Server.Execute.
  • HttpRequest.FilePath is similar, but gives the original (calling) page after Server.Transfer or a Server.Execute.
  • HttpRequest.Path returns the current URL path, exluding the host (and related kit). This also includes any "trailers" after the page, like …/default.aspx/blah/blah/blah
  • HttpRequest.PhysicalApplicationPath is the root path on the disk of the server where the application lives – corresponding to ApplicationPath. Don’t send this to the client.
  • HttpRequest.PhysicalPath is the physical path of the currently executing page.

 

Filed under: .Net Basics

Don’t ever do this bad thing

This is bad:
 

protected override void OnLoad( EventArgs e )

{

base.OnLoad(e);

PubsDataSet.Instance.UpdateFailed += new UpdateFailedDelegate(Instance_UpdateFailed);

}

 

As you can see, this is an override from an ASP.Net code behind class. Yep, the .Instance property is a Singleton. I knew it was a no-no to hook up an event listener to a static instance in an Asp.Net solution, because the resulting class which has the listener never gets GC’d, and you get memory leakage in a nasty way.

 

What’s more, if you execute the code above, what happens is that all references to controls on the page return "null" since, due to the way that events are implemented as linked lists, the reference that you are looking at in the event handler is an old instance of the page, which should have been disposed, but isn’t because you have a reference outstanding and the GC won’t collect it.

 

However, knowing this didn’t stop me from doing it in an example I’m cooking up for a course. This is why experience is valuable – you know when something is wrong because you’ve felt the pain of doing it wrong, which lends to a much more acute sense of what is right than just studying it. Knowing the symptoms from studying the above analysis earlier helped me kill this bug in under 30 minutes, but having the experience will prevent me from creating the bug.

 

Here is a good solution which makes use of an Anonymous method to handle the event callback. Notice how the handler is removed when the page is unloaded – this is key:

private UpdateFailedDelegate updateFailed = delegate( object sender, UpdateFailedEventArgs e )

{

EditErrorLabel.Visible =

true;

EditErrorLabel.Text = e.FailureReason.ToString();

};

protected override void OnLoad( EventArgs e )

{

base.OnLoad(e);

PubsDataSet.Instance.UpdateFailed += updateFailed;

}

protected override void OnUnload( EventArgs e )

{

base.OnUnload(e);

PubsDataSet.Instance.UpdateFailed -= updateFailed;

}

 

Filed under: .Net Basics

Why C++ needs .H files

I never questioned why C++ needs .h files – I just accepted it. Definitions go into .h files, and code goes in .cpp or .c files. Strange, I know – me just accepting without questioning. Huh. I suppose it was the nice side effect of having the .h file be your API definition. But that’s not really why it _has_ to have one. You need it because the C++ compiler is a clunky beast which only does a single pass through the code. Sure, there is some history for this, but there really isn’t a tenable argument to be found why it should stay this way.

I found all this out by trying to resolve a circular reference among objects which I am creating to wrap the Shapefile library by Frank Warmerdam. This post helped me unravel that issue, and deduct the real reason behind .h files.

So basically, you can do this:

In ShapeObject.h:

                // a "stub" definition for the related class which contains ShapeObject
                ref class ShapeFile;

	public ref class ShapeObject
	{
	private:
		Boolean		_isDisposed;
		SHPObject*	_internalHandle;
		Int32		_index;
		ShapeType	_type;

                                // Now we don't get a compilation error here
		ShapeFile^	_parentFile;
                                .
                                .
                                .
                };

And in ShapeFile.h:

                #include "ShapeObject.h"
	public ref class ShapeObjectsCollection : public System::Collections::Generic::List
	{
	public:
		ShapeObjectsCollection() { }
	};

	public ref class ShapeFile
	{
	
	private:
		ShapeObjectsCollection ^ _shapes;
                                .
                                .
                                .

                 };

The important thing is the stub declaration… since the C++ compiler only does one pass, it needs to be declared before hand… implementation can be done later, which is where the .h/.c[pp] split comes in.

Filed under: .Net Basics

Generic fun

Generics are really cool…
 
 
bummer – i thought i might have one of those "You’re our lucky 1,000,000th person who said that winner!" banner descend from Javascript heaven.
 
Anyway I had a hard time using them vs. code-generation of collection classes since code gen had the advantage of non-generic _names_. But I just found out we can do this:
 
 

public sealed class Role

{

    private string _roleName;

    public string RoleName

    {

        get { return _roleName; }

    }

}

 

public sealed class RolesCollection : List<Role>

{

   public Role this[string roleName]

   {

      get

      {

          foreach( Role r in this )

              if( r.RoleName == roleName ) return r;

          return null;

       }

   }

}

 

Now I can have my cake and eat it too. Yum.

 

-rory

Filed under: .Net Basics