October 2003 - Posts

Codebehind vs. Codeinline: war is over

Note: this entry has moved.

Monday at the PDC03 has been an extremely busy day and today looks even busier. I managed to get some free time this morning (missed breakfast) so here goes my first PDC03-post:

 

What is your personal preference? Are you a codebehind fan or a code inline one?

 

On how many “codebehind vs. code-inline wars” have you ever been involved?

 

This would be the usual stuff coming from guy #1, a codebehind-lover:

 

“…I don’t like mixing UI with code, period; who in the world may want to mix presentation markup with code? This is such a bad idea that even VS.NET offers zero support for it. Ever tried to edit some code embedded into an .aspx? No intellisense, no coloring, no nothing. Moreover, it’s a nightmare, you’ve to deploy your sources along with your application…”

 

Now, some stuff coming from guy #2, a codeinline-fan:

 

“…Well, I laugh at poor codebehind-lovers. They have to recompile their 3000-pages app if they decide to change a single .aspx, everything they touch causes an application-restart. Also the dependencies that exist between the parser-generated class and the codebehind class are ugly, plus, VS.NET will usually decide to wipe out your event handling and initialization code. Finally, they usually like to stick to the IP-protection argument, that’s only because they’re afraid to show their ugly code!...”

 

So what would be the ideal model that could make both of these two guys happy? Let’s see:

 

VS.NET support

 

The major pain while working with code embedded into an .aspx is the lack of VS.NET support for this. If VS.NET could clearly present you, as WebMatrix does today, with an html-view, code-view, etc, it won’t matter much if UI + code is finally stored in a single file or its separated in two. So, making VS.NET smart enough to support this, plus giving you the option to still separate them into two files (if that makes you feel any better) should satisfy everyone.

 

Dynamic compilation

 

No matter if you’re putting your code into the .aspx or in a separate file, you should always get the benefit of dynamic compilation, that’s is: compilation of the UI and code for your pages on the fly, without having to rebuild the entire application (and without the obvious application restart too).

 

IP protection

 

You should be given the option to deploy your code in a compiled form (no sources) even if you decide to write your code into the .aspx

 

Making OO purists happier

 

While today’s codebehind model works, it has some big compromises. The main one is the implied assumption that exists between the codebehind and the parser-generated classes; from an OO perspective this is really ugly (i.e., a base class expecting some specific behaviour of the super class).

 

Well... everything described in the above paragraphs is already offered by the Whidbey bits; how they did accomplished this?

 

One of the most notorious changes was made possible by the introduction of support for partial classes. This allows us to declare our (previously named) codebehind class like this:

 

namespace ASP {

 

       public partial class test1_aspx

       {

               // your code goes here – parser class declaration looks the same

       }

}

 

The page parser will declare a class in exactly the same way as shown above. At compile time, both declarations will be merged and compiled as a single class thus eliminating the need for two separate classes (and the nasty assumptions made between them). Also, all the autogenerated  code (i.e. InitializedComponent method with all the event wireup code; yes, the method VS.NET likes to modify on its own from time to time) is now being found in the parser generated partial class (each generated __BuildControl* method now also contains the event wireup code for that particular control). 

 

But… wait a minute!! Now, if there is only a single class, that means that we could freely move our code around between code inline and codebehind (or Code Beside as it is being called by now) without any trouble. That’s possible. Don't be fooled by the fact that you can still choose to have two separate files. The war’s over.

Posted by vga with 4 comment(s)
Filed under:

Deep inside the SR type: curiosities, improvements and some generics code too

Note: this entry has moved.

Here I’m assuming you’re already familiar with the SR type; if you’re not, then reading this post will definitively help.

 

In this post I’m going to detail a few curiosities I found while dissecting the SR type plus some suggested improvements.

 

Getting the assembly where a type is implemented

 

I can hear you saying: “…This is really an easy one, just do”:

 

YourType.GetType ().Assembly

 

Sounds obvious; but now, if you peek at SR’s internal constructor you’ll find that they get to the assembly by using:

 

YourType.GetType ().Module.Assembly

 

So I asked myself: “Why in the world are they getting to the assembly by using the Module property?”

 

First thing I thought was the ResourceManager not being clever enough to resolve resources located in different modules of a multi-module assembly, although that is not the case in the .NET fx -where all assemblies are composed of a single module- I thought they may have coded it that way just for “forward-compatibility”.

 

I fired up a console and using csc.exe and al.exe hacked up a simple two-module assembly having types and resources in each one of the modules. Then I used TypeOne.GetType().Assembly, where TypeOne is defined in module A and tried to access resources stored in module B; I expected this to miserably fail so I could confirm my simple theory. The results shown that ResourceManager is actually clever enough to find any resources no matter where they’re stored; it will consult the assembly’s manifest where resources entries contains info about the module file where they reside and from there it will properly get to the resource.

 

Code bloating

 

You know SR includes about 22 utility methods (counting overloads) to provide a strongly-typed way of handling resources. Basically what every GetXXX method does is to use the resource manager to get an object reference and then cast that reference to the specific type they’re handling with, something like this:

 

static public double GetDouble (CultureInfo ci, string resid) {

     double num = 0;

     SR sr = SR.GetLoader ();
     if (sr != null)

          object o = sr.resources.GetObject (resid, ci);

     if (o != null)

          num = (double) o;

     return num;

}

 

Note the above lines in bold, they’re repeated in every GetXXX method (GetInt, GetFloat, GetChar, etc.)

There is a GetObject method that does exactly the same and could have been used by any of these methods, so why is this code repeated all along? The only reason I can think of is C# compiler’s inlining feature.

 

 

A generics-enabled SR

 

With the support for generics in Whidbey it will be possible to reduce the code-bloating nature of SR to this minimum expression:

 

 

static public T Get<T> (CultureInfo ci, string resid) {

     T res = T.default;

     object o = SR.GetLoader ()._resMgr.GetObject (resid, ci);

           

     if (o != null)

                res = (T)o;

           return res;

     }

 

static public T Get<T> (string resid) {

     return SR.Get<T> (null, resid);

}

 

Don’t you think generics just rocks?

 

Download a skeleton SR type using generics from here (you’ll need whidbey to compile).

Posted by vga with 7 comment(s)
Filed under:

The SR pattern, a simple approach to resource handling

Note: this entry has moved.

 

I’m currently performing a huge code & architecture review of a very big .NET project that includes several web applications and several frameworks. One of the first things I did was to estimate how costly would be to make all this stuff I18N ready. To my surprise (ok, not much of a surprise…) I found as many different ways to handle I18N as different teams the project has; moreover, most of them were really ugly ones… and some teams didn’t even thought about I18N.

 

Regarding resource handling, I decided to write a doc explaining the SR type that is used all along the .NET fx and also in other Microsoft products like Commerce Server, Exchange, etc, to present it to each team as “The SR pattern, a proven way to resource handling”. After that, I translated it to english and… this post was borned.

 

Hey look, it’s a double-check locking!

 

SR is an internal sealed type (I’m guessing named SR after “String Resources” although it can handle more than just strings). This type implements the double-check locking pattern, which is just a singleton pattern with thread safety in mind: it doesn’t expose any public constructors and it has a static method that always returns the very same instance of the type, plus it contains proper checks to make it thread-safe:

 

internal sealed class SR {

     private static SR loader;

          static SR () {

          SR.loader = null;

     }

     static SR GetLoader () {

          if (SR.loader == null) {

                lock (typeof(SR)) {

                     if (SR.loader == null)

                          SR.loader = new SR ();

                }

          }

          return SR.loader;

     }

}

 

By following the advices in CBrumme’s Memory Model post you could make this double checking safer by using a memory barrier after construction and before assignment of loader, i.e.:

 

SR sr = new SR ();
Thread.MemoryBarrier ();
SR.loader = sr;

 

Ok, enough singleton stuff, let’s get back on topic now.

 

Where to put the neutral culture resources?

 

The most common approach is to include the neutral culture resources into your main assembly. Following the approach taken by the .NET framework itself, a resource manager is instantiated and cached in the SR type’s internal constructor:

 

internal SR () {

     this.resMgr = new ResourceManager ("YourRootName", this.GetType().Assembly);

}

 

Note that the same assembly containing the SR type was specified as the one where the resource manager should look for resources. This is a good choice, as resources for a type are deployed along with it into the same assembly instead of going into a separate one, plus it enforces a bit the concept that a type’s resources are only meant to be used by that type and no other.

 

An alternative approach would be to ship the resources for the neutral culture in its own satellite assembly, i.e.: YourCompany.YourProduct.CommonStrings.dll, as some of the above mentioned Microsoft products actually do; but I prefer the .NET framework approach instead. Lastly, each additional supported culture should make it into its own satellite assembly.

 

No need to reinvent .resx

 

When doing the code review mentioned above, I stumped against some code of a guy that decided to create his very own resource format. You don’t need to do that, really; just add an Assembly Resource File (.resx) to your project and you’re done.

 

Sadly, VS.NET support for editing .resx is almost non-existent; it may be ok to use the XML view if you’re only dealing with strings but you’re on your own for anything else. Luckily you will find some free apps and add-ins to fill in this gap.

 

This is how a string resource looks like:

 

<data name="Attr_not_supported_in_directive">

          <value>The '{0}' attribute is not supported by the '{1}' directive.</value>

     </data>

 

The value for the name attribute of the data element represents the resource ID that we will need to provide when looking to access a resource’s value, which we provided as the content of the value element. Note that the {0} and {1} placeholders are there so we can easily format the string later using String.Format.

 

 

Naming resources

 

Regarding the naming of resources IDs, the framework tends to compose it using the name of the control or component to which the message belongs to, plus the description of the message itself, separating them with an underscore character, i.e.:

 

Calendar_TitleFormat

 

Actually, you will see that an underscore character is used also for separating words in the message detail, i.e.:

 

Object_tag_must_have_class_classid_or_progid

 

Seven underscores seems like just too much to me, so replacing them with some PascalCasing may be a good idea.

 

Get me that string, please

 

After you’re done creating your .resx file you need an easy and error-free way to get strings from your application (or component, or framework, or whatever you happen to be coding at the time!). SR tackled this by defining internal constant strings holding each resource’s ID:

 

internal sealed class SR {

     internal const String Calendar_TitleFormat = “Calendar_TitleFormat”;

     internal const String Assembly_not_compiled = “Assembly_not_compiled”;

     .

     .

     .

 

And by offering a bunch of utility methods to easily get resources of different types, i.e.:

 

static public string GetString (CultureInfo ci, string resid) {

     return SR.GetLoader ().resMgr.GetString (resid, ci);

}

 

static public int GetInt (CultureInfo ci, string resid) {

     int num = 0;

      object o = SR.GetObject (ci, resid);

     if (o != null)

     num = (int) o;

     return num;

}

 

 

Then you would always use the previously defined constant strings (just type “SR.” and intellisense will do the rest) as the parameters to feed the GetXXX methods, i.e.:

 

string errmsg = SR.GetString (SR.Assembly_not_compiled);

 

 

Giving a clue to the Resource Manager

 

The NeutralResourcesLanguageAttribute attribute is used to mark an assembly with the language used in writing the neutral culture; the resource manager will then use the value of this attribute as a hint to speed up the search when looking up resources in the same culture as the neutral one, saving any trips to satellite assemblies.

 

 

This should be enough of an intro to the SR type and a good starting point to a simple way of handling resources; you can download some skeleton code from here.

 

There are some implementation details about SR that I don’t like and some curiosities also that I haven’t touched here just to not bloat this post, but I will do so at my next post, hopefully within this year… :-)  

Posted by vga with 6 comment(s)
Filed under:
More Posts