2006-08-31

c# Anonymous Method Syntax

I always keep forgetting the sytnax for these whenever i start a new project and have nothing to copy and paste from. These two links are the most helpful i have found. They provide examples over and above the documentation in msdn2.
http://www.theserverside.net/tt/articles/showarticle.tss?id=AnonymousMethods
http://msdn.microsoft.com/msdnmag/issues/06/00/C20/default.aspx

Working Days in T-SQL

These two posts helped greatly in getting a function to work out the working days between two working days:
http://aaronjohals.blogspot.com/2005/10/number-of-working-days-between-2-dates.html
http://classicasp.aspfaq.com/date-time-routines-manipulation/how-do-i-count-the-number-of-business-days-between-two-dates.html


drop function dbo.GetWorkingDaysDiff
go
create function dbo.GetWorkingDaysDiff(@start datetime, @end datetime)
    returns int
as 
begin
    declare @countdays int
    set @countdays = 0
    while @start < @end
    begin
        if (select datepart(dw, @start)) < 6
        begin
            set @countdays = @countdays + 1
        end
        set @start = dateadd(d,1,@start)
    end
    return @countdays
end 
GO
print(dbo.GetWorkingDaysDiff('2006/08/21', '2006/08/27'))
go

2006-08-30

NHibernate 1.2.0.Alpha1

I finally got around to implementing this into my code base, but as you would expect not everything worked first up. The saving worked fine, i could see the rows in the database. It was just the loading. At initial start NHibernate complains about virtuals on all you proxys for lazy loading, but i fixed them. A gut feeling i had was that this was to do with all to do with lazy loading.

As it turns out all collections and associations are lazy loaded in this new version:
http://forum.hibernate.org/viewtopic.php?t=960004&start=15&sid=ba44698acc40eaae77d6d73d7561ba83
http://dotnet.org.za/kuate/archive/2006/05/29/52751.aspx
So just put that attribute into my mapping file and everything went back to normal.

The real underlying cause of all this is that when things get lazy loaded they are a proxy type, not the actual type in the domain model. So when i debugged it like this:
Console.WriteLine(n.GetType());
I was getting a type name like this with these names all joined together with under scores
ProxyInterfaceSystemObject
INHibernateProxy
ISerializable
My tests for type (x is MyType) all fail silently, they really should be converted to proxy interfaces, but i don't need to atm, and i get 20% extra speed.

2006-08-29

ASP.NET 2.0 Medium Trust

Here are some links for configuring some library binaries:

nHibernate
http://forum.hibernate.org/viewtopic.php?t=963084&view=previous

IMPORTENT: Turn off the relection optimizer as you guessed it you dont have ReflectionPermission on shared hosting in medium trust.

<configuration>
  <configSections>
    <section name="nhibernate" type="System.Configuration.NameValueSectionHandler" requirePermission="false"/>
  </configSections>
  <nhibernate>
    <add key="hibernate.use_reflection_optimizer" value="false" />
  </nhibernate>
</configuration>
I found also that the .NET 2.0 namespace declaration in the app.config/web.config caused exceptions, so just remove it, the application will still run in 2.0 no worries.

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">

Working Around Shared Hosting

I have been investigating the shared hosting issues with Spring and found that it is not as bad as it initially seems. There are a few steps that must be taken, very similar to those taken from other java ported libraries (eg nhibernate).
Firstly, all calls to GetCompiledPageInstance MUST be replaced with CreateInstanceFromVirtualPath. I have provided the fix for this in a previous thread (http://forum.springframework.net/showthread.php?t=407). This is a must because the GetCompiledPageInstance method has an attribute on it, pretty much killing calls to it unless you are running in full trust mode. On shared servers this will be highly unlikely.

[SecurityPermission(SecurityAction.Demand, Unrestricted = true)]

Now i had thought this had been commited into the main branch of SPring.Web, but the nightly build and the cvs repository on sourceforge both do not have the fix

The second step to take modifing the spring source, is to find the file src\Spring\Spring.Core\Core\IO\FileSystemResource.cs. This file has two calls like this

fileHandle.Directory.Root.ToString();

In the hosting trust mode, this bombs out with a FileIOPermission violation. The reason being, you don't have access to the root directory when you are on the shared host. The Root property of DirectoryInfo has this line in it causing the exception.

new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new string[] { text1 }, false, false).Demand();

My solution is a little hacky at the moment but you get the idea. All it is doing is getting the root folder (ie c: or d:). This propably wont work on a network drive remember.

fileHandle.Directory.ToString().Substring(0, 3);

Third thing to do is to add requirePermission="false" to the configSections section in web.config. If you dont do this you will receive a Configuration security permission exception.

<configSections>
  <sectionGroup name="spring">
    <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" 
 requirePermission="false"/>
    <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" 
 requirePermission="false"/>
  </sectionGroup>
</configSections>

The last item on the list is probably the most obscure, and i will try to explain and give some background:

dll's can be signed, which gives them a strong name and a hash, which stops them being modified and re-distributed.
strong named dlls can be registered in the GAC.
From the GAC, dlls can be configured to run in full trust, depending on your .net framework configuration. (see somewhere in control panel -> administration tools).

When you run a web application in anything but full trust, all the dlls in the bin directory run in a partial trust mode.
Strong named assemblies that are NOT in the GAC but in you bin directory, can not by default be called from a partial trusted assembly

So in this case i have my project dll, spring, nhibernate and log4net in the bin directory, plus any dependant dlls. nhibernate and log4net are strong named, but i can only call log4net from my app, not nhibernate. Why is this? its because log4net has an assembly level attribute on it.

[assembly: System.Security.AllowPartiallyTrustedCallers()]

This attribute allows my partially trusted application to call into it without throwing an exception. Details can be found on msdn, its something to do with LinkDemand.

Now it gets tricky, that would mean all the dll's that i have in the bin directory need this attribute. How would i do this?, I could get all the sources for them and recompile, but what happens if i can't get the source, or i have a 3rd party app that is proprietary. I do the following instead:

1. get all the dll's and disassemble them
2. add the AllowPartiallyTrustedCallers attribute to them in the MSIL file
3. remove all signing code from the assembly
4. remove all public keys and hashes from the assembly
5. update any extern assembly declarations, by removing the public hash requirement
6. reassemble the dll's again.

What does this do? It removes all strong names from the assemblies and also updates the references to not require the strong named versions.
As we dont have the keys that sign the dll, we can't resign them, but we can remove the signing altogether.
We could resign them all with new keys that we created and update the references, but that sounds like a lot of work for no gain.
We are going to be running in partial trust mode so we just don't need strong named assemblies.
This process probably wont work in all circumstances mind you.

2006-08-28

NHibernateUtil.IsInitialized()

I have a nhibernate lazy loaded collection, well a bunch of them in a tree of parent-child relations. When i save some nodes, i have to loop over the active nodes and add a bit of data to them. Trouble is when i access the parents/children it initilises the collections. This is bad as it then loads the whole tree into memory on the saved.
I thought there must be a way to check whether a collection had been loaded lazyily. First i thought about checking the type to see if it was the dynamic proxy. But then ran into this gem at the nhibernate reference guide:
http://www.hibernate.org/hib_docs/nhibernate/html/performance.html

I could just pass the collection to this method, and it would check if it had been initialised. Just waht i was after. The only other place i found a reference to this function then was at the forums:
http://forums.hibernate.org/viewtopic.php?p=2282177&sid=b5989f2c3f2387add4188a6e13802019

So why dao function ended up as, because i dont want the nhibernate logic permeating my service layer:

        public bool HasBeenInitialised(ICollection collection) {
            return NHibernateUtil.IsInitialized(collection);
        }

2006-08-27

bindingRedirect

I ran into a wall today where i was getting an exception akin to this:

Could not load file or assembly 'dommons, Version=0.0.33.0, Culture=neutral, PublicKeyToken=873d6a369a01a6bd' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

Now im fine with the error, its a shared strong named assembly, that NOT in the GAC. So how do i fix it. It didn't take long to find the solution was to add a bindingRedirect. I was going to map the 0.0.33.0 version to the lastest 0.0.36.0 one. Easier said than done i'm afraid.
Here is a link explaining the redirect:
http://www.diranieh.com/NETAssemblies/Assemblies.htm

All i would have to do would be to put this in my web.config:


  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="dommons" 
  publicKeyToken="873d6a369a01a6bd" culture="neutral" />
        <bindingRedirect oldVersion="0.0.33.0" newVersion="0.0.36.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>


Though this did not fix the problem. A lot of material seems to be geared towards the assemblies being in the GAC or running as a client application. Not my case of build versions mismateching. To a newer version as well.

So i then spent the next half a day figuring out what was going on.
First checking i was doing it correctly:
http://blogs.msdn.com/suzcook/archive/2004/05/14/132022.aspx
http://plans.thefrankes.com/tutorials/Assemblies/
http://blogs.msdn.com/junfeng/archive/2004/11/16/258081.aspx

I was sure i had the syntax right, time to start using the assembly loading debugger, a tool called fuslogvw. In the start menu, open up the .net framework command prompt and type that. Also make sure you restart IIS to register it, otherwise nothing happens. Here are some more links for debugging:
http://www.grimes.demon.co.uk/workshops/fusWSFive.htm
http://blogs.msdn.com/suzcook/archive/2003/05/29/57120.aspx
http://www.grimes.demon.co.uk/workshops/fusWSFive.htm

So what was my problem, it seems that the redirect was not working. This happens first in the process (msdn). But why was it failing.
The error from fusion log viewer was this:

  *** Assembly Binder Log Entry  (27/08/2006 @ 3:29:10 PM) ***
  The operation failed.
  Bind result: hr = 0x80131040. No description available.
  Assembly manager loaded from:  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
  Running under executable  c:\windows\system32\inetsrv\w3wp.exe
  --- A detailed error log follows.
  === Pre-bind state information ===
  LOG: User = NT AUTHORITY\NETWORK SERVICE
  LOG: DisplayName = dommons, Version=0.0.33.0, Culture=neutral, PublicKeyToken=873d6a369a01a6bd
  (Fully-specified)
  LOG: Appbase = file:///D:/projects/svn/project/trunk/project-web/
  LOG: Initial PrivatePath = D:\projects\svn\project\trunk\project-web\bin
  LOG: Dynamic Base = C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\project\91bd8e69
  LOG: Cache Base = C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\project\91bd8e69
  LOG: AppName = fec991e1
  Calling assembly : repository, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null.
  ===
  LOG: This bind starts in default load context.
  LOG: Using application configuration file: D:\projects\svn\project\trunk\project-web\web.config
  LOG: Using host configuration file: file:////?\c:\windows\microsoft.net\framework\v2.0.50727\aspnet.config
  LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
  LOG: Post-policy reference: dommons, Version=0.0.33.0, Culture=neutral, PublicKeyToken=873d6a369a01a6bd
  LOG: GAC Lookup was unsuccessful.
  LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Temporary ASP.NET Files
 /project/91bd8e69/fec991e1/dommons.DLL.
  LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Temporary ASP.NET Files
 /project/91bd8e69/fec991e1/dommons/dommons.DLL.
  LOG: Attempting download of new URL file:///D:/projects/svn/project/trunk/project-web/bin/dommons.DLL.
  LOG: Assembly download was successful. Attempting setup of file: D:\projects\svn\project\trunk\project-web\
 bin\dommons.dll
  LOG: Entering download cache setup phase.
  LOG: Assembly Name is: dommons, Version=0.0.36.0, Culture=neutral, PublicKeyToken=873d6a369a01a6bd
  WRN: Comparing the assembly name resulted in the mismatch: Build Number
  ERR: The assembly reference did not match the assembly definition found.
  ERR: Setup failed with hr = 0x80131040.
  ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

Note the two red lines. The redirect was not working, and as the 33 version could not be found, the application start failed. In frustration i tried a suggestion to put the redirect in the machine.config file, and what do you know, the whole thing started to work. Now at least i know why it isn't working it might be a little easier to figure out the cause. I think i read a permission on a security namespace item may need to be set.

2006-08-25

Collection was modified; enumeration operation may not execute.

For this exception i had always kept a cache array of elements to remove, but this guy creates a temperary array enumerator in the foreach loop. Nice work. But this doesn't work with generics, so he uses a delegate to do the same job. Someone also says that there is a powercollections framework that offers .net 2.0 some advanced features.

Extension Methods

Recently at work we had a requirement to have enum values displayed as proper words rather than camle cased. But you can't override the ToString method. But what about using the Extension Methods feature of c# 3.0. Now it seems like agood idead to do what upon future investigate you can't override methods like you would a virtual, you can only add new methods. So then i begs the point, what is the point of Extension Methods. The only case that i can see is if the class is sealed in a 3rd party library that you can't change, that you want to add a method, rather than having a Utils class to do the work for you. Now this is good, becuase then you can see all the methods in the visual studio intellisense. But if you own the class, then there really is no point, you would just add the method yourself.

The could be a way to use numerous different methods with the same name, but in different namespaces, but i haven't fully thought about that yet, and propably wont until 3.0 has gone into release.

Here are some links, though they are kind of old:
http://blah.winsmarts.com/2006/05/18/demystifying-c-30--part-3-extension-methods.aspx
http://mtaulty.com/communityserver/blogs/mike_taultys_blog/archive/2006/03/20/5798.aspx
http://www.cincomsmalltalk.com/userblogs/malby/blogView?showComments=true&entry=3304188302
http://blogs.msdn.com/abhinaba/archive/2005/10/21/483337.aspx

2006-08-24

yield

So i found this keyword that i did not know about in c#. Intriguing. So what it does is creates an enumeration on the fly, without having to code a class to do it. Sounds good, but what could i use it in. A few examples suggest that it be used in tree traveral:

        public IEnumerator<Node> GetDepthFirstTraversalEnumerator() {
            yield return this.value;
            foreach(Node child in this.children) {
                IEnumerator<Node> enum_ = kidchildGetDepthFirstTraversalEnumerator();
                while(enum_.MoveNext()) {
                    yield return enum_.Current;
                }
            }
        }
 
and also found the map function from other laungauges:

        public delegate object MapFunction(object o);
        public static IEnumerable Map(MapFunction mapFunction, IEnumerable enumerable) {
            foreach(object o in enumerable) {
                yield return mapFunction(o);
            }
        }
        public static IEnumerable PositiveIntegers() {
            int a = 1;
            while(true) {
                yield return a;
                a = a + 1;
            }
        }
        public static IEnumerable SubList(int start, int end, IEnumerable enumerable) {
            int count = 0;
            foreach(object o in enumerable) {
                count++;
                if(count < start) {
                    continue;
                } else if(count <= end) {
                    yield return o;
                } else {
                    yield break;
                }
            }
        }
        IEnumerable set = I.SubList(5, 15, I.PositiveNumbers());
        foreach(int value in Map(delegate(object o) { return ((int)o) * 2; }, )) {
            //do something
        }
 
heres the link to a Fibonacci generator 
http://www.cerkit.com/cerkitBlog/2004/06/30/Using+The+Yield++Statement+In+Whidbey+C.aspx
 
a lazy paged collection:
http://haacked.com/archive/2006/08/14/FunIteratingPagedCollectionsWithGenericsAndIterators.aspx
 
and a textreader:
http://blogs.msdn.com/jmstall/archive/2005/08/08/textreader_yield.aspx

2006-08-23

WeakReference

Have you ever wanted to store a time consuming to construct object in a cache, but then it hangs around forever. Try storing a WeakReference to the object instead.

            object cached = new TimeConsumingToConstructObject();
            WeakReference wr = new WeakReference(cached);
            cached = null;
            if(wr.IsAlive) {
                cached = wr.Target;
            } else {
                cached = new TimeConsumingToConstructObject();
            }

To Ruby or not to Ruby

I was wondering if i should start tinkering with ruby to see what sort of framework it was. Then i read some items that suggested that it was still in its infancy as a technonolgy. Poor speed, not enough documentation.
http://discuss.joelonsoftware.com/default.asp?joel.3.309321.3
http://www.pankaj-k.net/archives/2005/11/ruby_or_java_a.html

I mean its sounds good to write less code, and have db mappping handled for you, but at what cost. I have spent years writting jscript asp with variable types, but the amount of errors that you miss without compile time and type checking support is painful. I prefer to let Visual Studio do the meanal tasks like remembering method names and type checking.

I think i saw somewhere that threading and internationalisation were issues, so it doesn't sound like an enterprise framework.

2006-08-21

COLLATE and Coalesce

I came across both of these items a while ago, but keep forgetting about them when i need to use them. The first is the COLLATE statement in T-SQL. Sometime different databases have different collations and when you try to query between them a collation error occurs. Now i used to always use one of the collations, ie collate Latin1_General_CS_AS. But i knew there was a default one, and i finally found it again (COLLATE database_default).
The other function Coalesce is a C# 2.0 item that does a thing similar to T-SQL's isnull()'s function. So:
string x = null;
string y = null;
string z = "123";
string value = x ?? y ?? z;
(value == "123") == true
So instead of using the :? statement checking nulls, it makes it alot cleaner.

2006-08-19

Javascript Includes not Included

Another 2 hours wasted this morning. It all started when a few atlas extender controls started throwing javascript debug alerts. I knew it used to work, and i couldn't see any recent changes that would cause it to break, like extra braces or colons. Then started the debuggin by removing the includes. This lead me back to the webresources, then to inline scripts. Finally i commented out the whole files text and had an alert, but no alert was firing.

Finally i stumbled accross a similar problem here. But then i tried it in firefox, and i got no errors. Doh, this was that IE bug where the cache gets filled an nothing seems to work anymore. I know that happens with view source, but it must also happen with this. As soon as i cleared the temporary internet files, everything worked again. Lucky with subversion i can just revert, not too much damage done.

Static Code Analysis

Intergrating FxCop into the cruisecontrol .net build process is not too hard. Also finding the SuppressMessage attribute was by pure luck. This attrbiute allows you to flag exceptions to FxCop rules in your source, rather than in the FxCop project file. But that doesn't phase me too much as i would still like the project file for message historys etc. I just created another file in the properties folder of the assembly for Analysis.cs.

The trouble with fxcop is that it only checks the compiled source, it doesn't check the actuall source code. I need a tool to intergrate with cruise control to check coding standards. The is a tool called PREfast in team studio, but i think it only does c/c++ for device drivers. And from the look of this article, thats all that microsoft offers. There is a java open source project called checkstyle that looks promising, but i will have to see that it doesn't throw huge amounts of errors for c#. I am surprised there is not a port yet. The last tool that i had a look at is SSW Code Auditor but it seems there server is having troubles at the moment and i can't download the trial. But it says it overs a large amount of source code checking, from cs, to html, to templates and sql.

2006-08-16

A MulitView with dynamic Views inside an UpdatePanel Exception

After having a hard day coding just before i hit the sack i got this exception that i couldn't find any google results on:

ActiveViewIndex is being set to '0'. It must be smaller than the current number of View controls '0'. For dynamically added views, make sure they are added before or in Page_PreInit event.
Parameter name: value

I have an multiview in an updatepanel which has the individual view dynamically generated in OnLoad. So how was i supposed to register them in PreInit if the multiview hadn't even be initialised. Then i stumbled on a solution.

I added some empty dummy views in the ascx file. Then i just cleared them before loading my own dynamic ones. I only added about 10 as i dont think ill ever need more than that, but if i do ill just add some more.

<atlas:UpdatePanel ID="MultiView1UpdatePanel" Mode="Conditional" runat="server">
    <ContentTemplate>
        <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
            <asp:View ID="View0" runat="server">
                Empty
            </asp:View>
            <asp:View ID="View1" runat="server">
                Empty
            </asp:View>
            <asp:View ID="View2" runat="server">
                Empty
            </asp:View>
            <asp:View ID="View3" runat="server">
                Empty
            </asp:View>
            <asp:View ID="View4" runat="server">
                Empty
            </asp:View>
            <asp:View ID="View5" runat="server">
                Empty
            </asp:View>
            <asp:View ID="View6" runat="server">
                Empty
            </asp:View>
            <%-- add more if needed --%>
        </asp:MultiView>
    </ContentTemplate>
    <Triggers>
        <atlas:ControlEventTrigger ControlID="Menu1" EventName="MenuItemClick" />
    </Triggers>
</atlas:UpdatePanel>
 
I tried adding this in code in both PreInit and Init before and after the call to base.x() but that didn't work. Ill see later if i can cleanup this solution any better

2006-08-10

WebServiceClientFactory

I found something with this Spring.Net webservice class.
When you define the context object:
  <object id="authServerStub" 
 type="Spring.Web.Services.WebServiceClientFactory, Spring.Services">
    <property name="ServiceUrl" value="http://localhost:81/auth/MembershipWS.asmx?wsdl"/>;
    <property name="ServiceInterface" 
 value="security.web.ISpringMembershipProviderAuthServer, dsecurity"/>
  </object>
and an interface like this:
    public interface ISpringMembershipProviderAuthServer {
        bool ValidateUser(string name, string password);
    }
when implementing this interface on the server end, you have to make sure that the parameter names match.
normally in c# you dont have to make the names match, only the types, but in this instance i expect that the client proxy generator uses the interface to pass arguements to the server. If you have them named different then you seems to only get null's on the server end.

Spring.Net WebApplicationContext

I was tring to use Spring.Net to configure an authentication application that i have been working on. The idea was to have a single-sign on webservice exposed by Spring and also have the client dynamically proxy the service via the same interface. This was all going well until the application would hang at load time with a timeout connection trying to download the webservice wsdl.

First i narrowed the problem to when spring started, which was when the application initialised a custom membership provider. I could also get to the webservice okay via the browser, so it must have been a context issue. I dropped the dependancy injection and created the webservice client in code and things worked fine. Next i ditched the AOP advice around the service.

Finally i removed a piece of code i had custom loading the webcontext and replaced it with:

            IApplicationContext ctx = WebApplicationContext.Current;

This did the trick, but how much time did i waste because of some legacy code i had for a work around for an older version on Spring.NET. Note to self, always work with the latest nightly build.

2006-08-09

Authenticate on LoginControl

I just spent 2 hours trying to get my custom membership provider to authenticate. No matter what i did i couldn't get the ValidateUser method to call. I know the provider was getting initialised because the Name and ApplicationName properties were being accessed.
Then i released that i had put this:

    protected void Page_Load(object sender, EventArgs e) {

        Login1.Authenticate += new AuthenticateEventHandler(Login1_Authenticate);

        Login1.LoggingIn += new LoginCancelEventHandler(Login1_LoggingIn);

        Login1.LoggedIn += new EventHandler(Login1_LoggedIn);

        Login1.LoginError += new EventHandler(Login1_LoginError);

    }

this was left over from some other debbuing and the OnAuthenticate was the problem. It was overriding the default provider login. Doh. So either remove the event or but my custom authentication in here. Kind of simple.

Security.dll

Now heres an interesting problem. I can run a vs2005 site in IIS no problems, but when i try to open it with the debugger in vs2005, i get the exception Unable to start Debugging System.Net.DigestClient. Plug the message into google and the first answer is it.
I have a dll called security and this apparently conflicts with a system dll of the same name.
What do i do, i rename the output of the dll to descurity.dll, clear out the bin directory, restart vstudio and no more problems. Unfortunately i now have to change the names of all the type declarations in web.config and spring files.
forums.microsoft.com
forums.asp.net

2006-08-08

Sandcastle CTP

At last i will be able to intergrate an api documentor into my cruisecontrol.net build process. Since i have migrated to .net 2.0 i have been without this feature. There are a few people building scripts and vs2005 plugins, so time to build the nant task.
Whats this, someone has already done it at http://blog.jkowalski.net/?p=52. Thanks Jaroslaw.

CodeFileBaseClass to the rescue of Page Inheritance

So i had a page that i needed to drop back into a compiled assembly, rather than just having it as a partial class next to the aspx file. This is always good, as you get compile support in the assembly. The only hard part is decalring all the controls you reference in the file as protected. Then i created a skeleton class that just extended the one from the assembly.

Trouble was that all the control definitions in the base class didn't get wired up. You know how it goes with the protected variables. So i spent a whilte trying public, didn't work. Reading blogs suggested using master pages.. Then Scott Allen on Rick Strahl's blog came to the rescue with the CodeFileBaseClass attribute on the page directive.

Nice. Rick's blog

Heres an example: jotek's sample