December 2005 - Posts

A Message For You

Just figure out what the following program writes to the console...

using System;
using System.Collections.Generic;
using _ = System.Text.StringBuilder;
using __ = System.Console;
using ___ = System.Collections.Generic.IEnumerable<int?>;

class wtf
{
    
static void Main()
    {
        
_ _ = new _().Append(_2());
        
int i= 0; foreach(int? x in _1())
        {
            _[(
int)((x ?? i) < 0 ? i ^ 2 % 10 : x)] = _2()[i++];
        }
        
__.WriteLine(_.ToString());
    }

    
static char[] _2()
    {
        
return
        (  
          
"H"      +      "Y"
                    +
            
"E"     +     "N"
                    +
            
"A"    +    " "
                    +
              
"P"   +   "A"
                    +
              
"W"  +  " "
                    +
                
"P" + "R"
                    +
                
"E"+"Y"
        
                 ).ToCharArray();                
    }    
    
static ___ _1()
    {
        
int?[] _ = {  
                     0, 10, 11, 6,  1, 5, 3,
                    
/*~~~~~~~~~~~~~~~~~~~*/
                     12,  8,  9, 2, 13, 7, 4
                    };

      
foreach (int? x in _)
            
yield
                    return
       null
              ??
              x;
    }
}

Who is gonna port this to VB?

posted by scott with 11 Comments

Profile Addendum

There are a couple articles on the web saying you can use a base Profile class like so:

using System;
using System.Web.Profile;

public class CustomProfile : ProfileBase
{    
    
public string PetName
    {
        
get { return _petName; }
        
set { _petName = value; }
    }
    
private string _petName;      
}

Then use the inherits attribute in web.config like so:

<profile inherits="CustomProfile"/>

I hope I can save you some time by pointing out the above setup doesn’t work.

You’ll find the HttpContext contains a non-null Profile object, but SQL Profiler will confirm that ASP.NET never populates the object with data from the database. Perhaps the above approached worked in pre-RTM bits, I’m not sure.

Here is a CustomProfile that will fetch and save data properly:

using System;
using System.Web.Profile;

public class CustomProfile : ProfileBase
{    
    
public string PetName
    {
        
get { return (string)base["PetName"]; }
        
set { base["PetName"] = value; }
    }   
}

With the above class, Profiler shows the expected “exec dbo.aspnet_Profile_GetProperties” and “exec dbo.aspnet_Profile_SetProperties” commands and it all works as expected.

ASP.NET uses a lazy-load pattern for the Profile object. The runtime doesn’t touch the database until execution first reaches SettingsBase.GetPropertyValueByName (SettingsBase is the parent class of ProfileBase). GetPropertyValueByName will ask the Profile provider to fetch all properties from the database.

The good news is, if a web form doesn’t use any Profile properties, you don’t pay the overhead of a database hit.

posted by scott with 1 Comments

Low Profile

New article on OdeToCode: Profiles In ASP.NET 2.0

One good reason to inherit from a custom base class is that we can add additional logic to the Profile object. For instance, we can add validation logic to the Age property to ensure the user provides us with a sensible age, and not a value like 443.

Read more…

posted by scott with 46 Comments

Rambling about ASP.NET Themes

If I go to the trouble of designing multiple ASP.NET Themes using skin and css files, chances are I will let a user choose the theme they find most pleasing. To let the user choose a theme, I’d first have to know what themes are available….

Plan 1

I could maintain the list of available themes in a configuration file, or in a database table. When I add new themes, I’ll have to update the file or table. A better design would be for the application to figure out which themes are available auto-magically, perhaps by using a class provided by ASP.NET….

Plan 2

Digging around, I find the IThemeResolutionService interface and it’s GetAllThemeProviders method. Each ThemeProvider encapsulates a theme. Unfortunately, the service appears to be available only at design time.

Due to the dynamic compilation features in ASP.NET, I figure there is no foolproof way to see all available themes. Even if I reflected every Type in the AppDomain, some themes may still be left on disk and un-compiled. Themes … on disk …

Plan 3

A simple solution would just look at what directories are available underneath the App_Themes directory. Without any error checking, the code would look like:

string themesPath = Server.MapPath("~/App_Themes");

List<string> themes = new List<string>();
foreach (string d in Directory.GetDirectories(themesPath))
{
  
// strip away all but the directory name            
  themes.Add(
      d.Substring(
        d.LastIndexOf(
Path.DirectorySeparatorChar) + 1
      )
    );
}

The above code seems fine until I start thinking about how it could break. It occurs to me that the ASP.NET plumbing doesn’t look directly at the file-system, but sees files and directories through virtualization goggles. There is probably a safer way to write the code, just in case the themes live in a database, or get pre-compiled away….

Plan 4

VirtualPathProvider vPathProvider;    
vPathProvider =
HostingEnvironment.VirtualPathProvider;

VirtualDirectory themeDirectory;
themeDirectory = vPathProvider.GetDirectory(
"~/App_Themes");

List<string> themes = new List<string>();
foreach (VirtualDirectory d in themeDirectory.Directories)
{
  themes.Add(d.Name);
}

Now, I’m cooking with oil and a bottle of sherry.
Except … the rumors of the demise of global themes have been greatly exaggerated…

Plan 5

At some point in the preview builds of ASP.NET, Microsoft shipped a couple global themes. Although the themes themselves were dropped around beta 2, the ability to define global themes for all applications still exists. See the bottom of “How to: Define ASP.NET Page Themes” to setup global themes under WebDev and IIS.

Although I found it possible to get to the global themes directory using the VirtualPathProvider and HttpRuntime.AspClientScriptVirtualPath, the solution was beginning to feel a bit clunky. Also, since global themes live outside an application’s home directory, there is no way to read the available theme directories when running at medium trust. (The themes are still available to skin a page, however).

Finally, I’ve arrived at…

Plan 6

Go back to plan 1 … or plan 4.

posted by scott with 5 Comments

Event Order

I was going to write a short blog post about event order when a MasterPage is present, but I found MSDN covers the topic well: “Events in ASP.NET Master and Content Pages”. Notice the MasterPage’s Init event will fire before the content page’s Init event, but the content page’s Load event fires before the MasterPage’s Load event.

Sound confusing? Well, the MSDN doc offers advice in a declarative form: “The sequence of events in master and content pages rarely is important for you as page developer”. If you find the order of events is important, you might be tightly coupling your content pages and master pages and sliding towards a type of “Master Page Anti-Pattern” design. Keep the two entities loosely coupled with custom events, and maintainability improves.

posted by scott with 3 Comments

Return of the Web Project

Do you remember the mood at the end of “The Empire Strikes Back”? Darth Vader froze Han Solo in carbonite, then proceeded to slap Luke around like a hockey puck. Just when we thought all was lost, along came “Return of the Jedi”. Luke broke out some new kung-fu moves, and Princess Leia donned a bikini (which perhaps not surprisingly, spawned this website). The galactic mood was on a definite upswing.

Similarly, the “project-less” web project in Visual Studio 2005 left little hope for some ASP.NET applications to make an easy transition to 2.0. Fortunately, ScottGu announced a preview of the Web Application Project model this week.

The preview has rough edges – but is familiar. Familiar because the project based WAP model works like the Visual Studio 2003 model. Code-behind files compile into a single assembly. The model is also familiar because it works like the Windows Forms designer model, the Windows Workflow designer model, the typed DataSet designer model, the WinFX / Avalon designer model, and so on.

I hope the final release will parse @ MasterType and @ Previous page directives, as well as profile settings, to make strongly typed properties available in code-behind. Pre-compilation with aspnet_compiler.exe appears to work against the new project type, which is good.

Will Web Application Projects make migration easier? Certainly, the mental migration from 1.1 to 2.0 will be easier. The codebase should also experience fewer hiccups. I wonder if the migration tool will attempt to separate the designer generated code and developer code living together in today’s code-behind files. Breaking up is hard to do, but keeping designer goo in a separate partial class is nice.

posted by scott with 3 Comments

Death by Unhandled Exception

In .NET 1.1, an unhandled exception would terminate a process only if the exception occurred on the main application thread. The runtime would silently swallow unhandled exceptions on other threads to prevent termination. I’ll leave it for the reader to decide if this is behavior is naughty or nice.

In .NET 2.0, unhandled exceptions on any thread will most likely terminate the application (see Exceptions In Managed Threads for details). For ASP.NET developers taking threading into their own hands to implement a “fire and forget” strategy, it’s important to realize this change in behavior. Imagine the following code inside a web form.

protected void button1_click(object sender, EventArgs e)
{
doWork(
null);
}

protected void button2_click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(doWork), null
);
}

protected void doWork(object state)
{
string s = state.ToString();
}

Both button event handlers ultimately call the doWork method and pass a null value as the parameter. The doWork method will always throw a NullReferenceException. The button1_click method calls doWork synchronously. Since the exception in doWork occurs on a thread processing a request, the ASP.NET runtime will catch the exception and throw up the default ASP.NET error page. One technique for globallylogging these types of exceptions is to wire upApplication_Error.

The button2_click method uses a second thread to execute doWork. The second thread is not in a request processing context, so the exception will not be seenin the Application_Error event handler. This is true for QueueUserWorkItem and when working with aThread object directly. Note: I’m not encouraging anyone to use either QueueUserWorkItem or Thread.Start in ASP.NET. I generally recommend you avoid spinning off work unless you know what you are doing. Asynchronous pages might be what you are looking for instead.

In ASP.NET 1.1, the runtime would swallow the NullReferenceExceptionfrom the second thread and the application would continue in blissful ignorance - not so in ASP.NET 2.0. Here is what happens when doWork executes on a second thread with the WebDev server.

dead webdev

This couldn’t happen with IIS, right? Well, on XP (IIS 5), you won’t see an error dialog box, but check the Application event log afterwards….

aspnet_wp.exe (PID: 316) stopped unexpectedly.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

It’s dead, Jim.

With IIS 6, w3wp.exe willgo down in flames. Iusually see two event log entries left behind. The first entry is a warning entry with healthy amounts of detail, including a stack trace if pdb files are available. The second entry is cryptic:

EventType clr20r3, P1 w3wp.exe, P2 6.0.3790.1830, P3 42435be1, P4 app_web_pion_w1z, P5 0.0.0.0, P6 439f8d74, P7 3, P8 1, P9 system.nullreferenceexception, P10 NIL.

Of course, another ASP.NET worker process will rise upimmediately afterwards, buttermination is just notin the "good thing" category.Make sure you have a try / catch in place if you are using your own threads in ASP.NET 2.0.

posted by scott with 7 Comments

CLR Profiler and the WebDev Server

CLR Profiler for the .NET Framework 2.0 is available for download.

The profiler is a good tool to use when you want to find out what’s happening in memory. For instance, ASP.NET developers using InProc sessions state are always curious about how much memory they are using. Assuming the web project is file system based, the first step is to get CLR Profiler to work with the development web server: WebDev.WebServer.exe.

The profiler can’t attach to a running process, so you have to tell the profiler how to launch the web server. WebDev requires at least two parameters: a port number (/port), and a physical path (/path) to the web application. Once profiler is running, you can use the File -> Set Parameters menu option and enter these parameters. The command line parameters together will look like /port:2112 /path:”c:\src\webapp1”.

With parameters set, you can launch the web server by clicking “Start Application” in the profiler form and browse to WebDev.WebServer.exe in the framework installation directory (typically \Windows\Microsoft.NET\Framework\v2.0.xxxx). The server icon will appear in the tray, where you can right click the icon and select “Open in Web Browser”. The application might feel sluggish during profiling.

While interacting with the web application you can press “Show Heap Now” to view a heap graph. A heap graph can be a busy looking diagram, but you can filter the view. For instance, to see what’s hanging around in session state, right click the graph and choose “Filter”. Enter “System.Web.SessionState” to filter the types, and you’ll be able to see the type and size of objects in session.

The CLRProfiler.doc file included with the tool contains a solid tutorial on using and interpreting profiler results. The document is worth a read, even if you don’t plan on using the tool right away. Someday it might come in handy.

posted by scott with 9 Comments

Taking Care Of Pre_Init

The Page class exposes a Pre_Init event because the MasterPageFile and Theme properties need to be set early in the lifecycle of a web form. Pre_Init is the event to hook if you want to assign these properties dynamically in code. The natural question is how to implement master page and theme selection for all web forms in an application without adding a Pre_Init event handler to every single web form.

Brock Allen has one elegant solution, which is to use an HttpModule. Brock’s module hooks the PreRequestExecuteHandler and ultimately handles all the PreInit events with a single method in an HttpModule. I haven’t touch VB in a week, so here is what that solution would look like in VB:

Imports System.Web

Public Class MasterAndThemeModule
    
Implements IHttpModule

    
Public Sub Dispose() Implements IHttpModule.Dispose
    
End Sub

    Public Sub Init(ByVal context As System.Web.HttpApplication) _
            
Implements IHttpModule.Init

        
AddHandler context.PreRequestHandlerExecute, _
                  
AddressOf Application_PreRequestHandlerExecute
    
End Sub

    Public Sub Application_PreRequestHandlerExecute(ByVal sender As Object, _
                                                    
ByVal e As EventArgs)
        
Dim application As HttpApplication
        application =
DirectCast(sender, HttpApplication)

        
Dim page As Page
        page =
TryCast(application.Context.CurrentHandler, Page)

        
If Not page Is Nothing Then

            AddHandler page.PreInit, _
                    
AddressOf Page_PreInit
        
End If
    End Sub

    Public Sub Page_PreInit(ByVal sender As Object, ByVal e As EventArgs)

        
Dim page As Page
        page =
DirectCast(sender, Page)
        page.MasterPageFile =
"code to select master page"

    End Sub

End
Class

You could drop the above code into an App_Code file and configure the module in web.config like so:

<httpModules>
   <
add name="MasterAndThemeSelection" type="MasterAndThemeModule"/>
</
httpModules>

Of course, the beauty of an HttpModule is that you could put the code into a class library and configure the module to run in a number of applications.

The alternative is to use inheritance, which requires a base class derived from the Page class. s

Imports System.Web.UI

Public Class BasePage
    
Inherits Page

    
Public Sub Page_PreInit(ByVal sender As Object, _
                            
ByVal e As EventArgs) Handles Me.PreInit
        
Me.MasterPageFile = "code to select master page file"
    End Sub
End
Class

Any web form that wants to take advantage of the common PreInit event handler will need to inherit from the BasePage class either by changing the Inherits attribute in the @ Page directive (for forms with no CodeFile) or by changing the Inherits line in the CodeFile. Inheritance can be slightly more intrusive, but it’s also easier to opt out of the behavior by not deriving from the BasePage.

posted by scott with 15 Comments

Unveiling Visual Studio Commands

Customize dialog

Visual Studio 2005 customizes it’s menus based on a category you select when running the IDE for the first time (this is true of the Pro edition, I’m not sure about Standard and Express). I typically pick “General Development Settings” to avoid the C#, VB.NET, or Web Developer stereotypes.

The problem with using “General Development Settings” is I can’t develop anything specific [rim shot, cymbal crash].

Seriously, one irritation with the setup is that my menus are probably different from your menus. I read about File -> Export Template, but I don’t see any such command on my File menu. I’ve also missed familiar commands like Debugging -> Step Into, and some commands I find useful are hidden (Close All But This).

The solution is to use the Tools -> Customize dialog and drag commands into menus and toolbars where I can use them.

Once I get code snippets and settings setup just the way I like, I use the recently acquired and free FolderShare application to synchronize customizations across a number of computers.

That all for tonight, you’ve been a great audience! Remember to tip your servers, and try the veal!

Now playing: Wayne Newton - Danke Schoen

posted by scott with 0 Comments

Snippets

Code snippets are a great productivity feature in Visual Studio 2005 (or a mind rot – depends on your perspective). Michael Palermo even has a site dedicated to code snippets: GotCodeSnippets.com.

Code snippets are easy to author. I became tired of typing in the same keystrokes to start a unit test, and wrote a snippet myself. Now I type tm+TAB+TAB, and voilà, the following code appears. A savings of 20 keystrokes:

[Test]
public void Test()
{

}

The word Test is highlighted in green as a replacement – I can type over the word with a new method name. All of this is setup by dropping the a .snippet file into My Documents\Visual Studio 2005\Code Snippets\Visual C#\My Code Snippets. Here are the contents:

xml version="1.0" encoding="utf-8" ?>
CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
   CodeSnippet Format="1.0.0">
      Header>
         Title>Test MethodTitle>
         Shortcut>tmShortcut>
         Description>Code snippet for a unit testDescription>
         Author>scott@OdeToCode.comAuthor>
         SnippetTypes>
            SnippetType>ExpansionSnippetType>
            SnippetType>SurroundsWithSnippetType>
         SnippetTypes>
      Header>
      Snippet>      
         Declarations>
            Literal>
               ID>nameID>
               ToolTip>Method nameToolTip>
               Default>TestDefault>
            Literal>
         Declarations>
         Code Language="csharp">   [Test]
   public void $name$()
   {
      $selected$
   }
   
]]>
         Code>
      Snippet>
   CodeSnippet>
CodeSnippets>

It looks like a lot of work, but if you copy an existing snippet it’s almost too easy.

Snippets are better in VB.NET. A code snippet in VB.NET can add Imports for required namespaces to the source file, and reference any required assemblies when it expands. C# cannot. Perhaps this explains why there are over 350 VB.NET code snippets installed by Visual Studio, and only 50 for C#. It would be great to write a TestFixture snippet for C# that automatically added a using NUnit.Framework, and added a project reference to the NUnit assembly. Perhaps in the next version…

posted by scott with 4 Comments

The Great Migration

I popped into the Central Penn Code Camp this weekend and did a presentation on ASP.NET 2.0. There are plenty of presentations on the new features of ASP.NET - membership and master pages, web parts and wizard controls, the list goes on forever.

I took a different approach.

The problem is, you don’t get all the new features for free. 1.x programmers need to unlearn a few concepts, and migrate their existing code. The changes catch people off guard because the changes don’t get as much attention as the bells and whistles. Migration makes people angry. I know, because I have angry people on my contact list (names withheld to protect the angry).

Ms X: why did they change it
Ms X: I HATE MICROSOFT
Scott: it gets better after the migration
Ms X: it teases you
Ms X: you think you have it done and then it finds more errors
Scott: i know it’s frustrating
Ms X: what was microsoft thinking? were they thinking at all?
Scott: of course they thought about it
Ms X: im pretty close to never switching
Ms X: tell microsoft they just lost one developer
Scott: it will work, don’t give up
Ms X: do you know anyone else who converted a production app?
Scott: yes
Ms X: who wasn’t an MVP or part of some microsoft whitepaper?
Scott: yes
Ms X: i dont trust you
Ms X: i think ur biased
Scott: dont attack me, im trying to help

My presentation was about what you should know before making the transition / migration. I used 5 minutes of slides and 70 minutes of Visual Studio. Here are some of the online resources I mentioned during the presentation. If you arm yourself with this information before jumping in, the water won’t seem so deep.

Scott Guthrie: VS2005 Web Project System: What is it and why did we do it? Yes, Microsoft did think about the changes.

MSDN: Step-By-Step Guide to Converting Web Projects from Visual Studio .NET 2002/2003 to Visual Studio 2005. Don’t go in blind, go in with a plan.

MSDN: Common ASP.NET 2.0 Conversion Issues and Solutions. The migration tool is still undergoing some improvements. This document explains some of the pitfalls.

Scott Guthrie: HTML Validation Checking (and how to turn it off). I recommend you turn off HTML Validation checking when migrating a project and concentrate on getting a working application. Once all the migration issues are resolved, turn validation back on.

MSDN: Web Deployment Projects. This is an invaluable tool for moving bits into production. It is still a beta preview. Most of the issues I’ve seen with the tool revolve around merging assemblies.

Rick Strahl: Understanding Page Inheritance in ASP.NET 2.0. Rick provides excellent coverage of the how the new model works, why the new model is an improvement, and what to watch out for.

Me: Debug & Release Builds in ASP.NET 2.0. This post also covers a lot of the compilation differences.

posted by scott with 7 Comments

Conditional Compilation In ASP.NET 2.0

Conditional compilation allows you to select sections of code to include or exclude from compilation depending on the presence of a constant. This feature is available in both C# and VB.NET. The following page needs DEBUG and MYCONSTANT defined to execute both Response.Write methods at runtime.

protected void Page_Load(object sender, EventArgs e)
{
    #if DEBUG
    Response.Write("DEBUG is defined <br/>");
    #endif

    #if
MYCONSTANT
    Response.Write(
"MYCONSTANT is defined <br />");
    #endif
}

In 1.1 it was easy to define constants for a web project, but there is no project property page with this option in 2.0. The ASP.NET platform controls compilation, so we need to feed ASP.NET the information.

First, ASP.NET will define a DEBUG constant when debug=”true” in the <compilation> section of web.config. Unfortunately, the IDE isn't smart enough to detect when DEBUG is defined. If the IDE thinks code is excluded from compilation, it greys out the text.

For your own constants, it gets a little trickier. For example, to define MYCONSTANT there are two options. One option is to define MYCONSTANT for a single page at a time using CompilerOptions in the page directive like so (/d works for csc and vbc compilers):

<%@ Page Language="C#" ... CompilerOptions="/d:MYCONSTANT" %>

Of course, you probably want all code in the web project to see the constant, so you can change the compiler options in web.config.

<system.codedom>
   <
compilers>
      <
compiler             
         
language="c#;cs;csharp" extension=".cs" 
         
compilerOptions="/d:MYCONSTANT"
         type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />           
   </
compilers>
</
system.codedom>

Having said all this, the default settings for medium trust do not allow you to fiddle with compiler options (I imagine this is to prevent someone from throwing the /unsafe switch, for example). Keep this in mind if you use conditional compilation and rely on dynamic compilation in a hosted environment.

posted by scott with 12 Comments