In my previous post about a memory leak, I was talking about EZWeb, and I’ve fixed the problem, profiled the app and have now released v1.1 of EZWeb on GotDotNet. For those of you who don’t know, EZWeb is an ASP.NET web application framework as well as a content management system all in one. It incorporates master pages functionality as well as Theming and skinning. But it does this in .Net v1.1. It takes building a web application from coding to configuring. ASP.NET 2.0 says you’ll write less code, but what if you could write even less code than that! With EZWeb, you could write a .Net application, and you would only have to write your business logic and screens specific to YOUR functionality. You wouldn’t have to worry about writing code or markup to keep the site consistent. I’m currently working on a port to ASP.NET 2.0, and I’ll take advantage of master pages and the actual theme feature in v2.0, but for now, EZWeb can give you those features using ASP.NET 1.1. Go check it out.
Monthly Archives: August 2004
SQL Server Reporting services integration with ASP.NET – level 100
As I’ve posted before, (and Jay has recently concurred), SQL Server reporting services is very cool. Some people think that it is an extension of SQL Server. What you may not know is that it is an ASP.NET library that installs on your web server. It also has a designer add-in for designer reports (very simple to use like MS Access reports) for VS. The reports are deployed to the web server, and served through a new ASP.NET HTTP Handler. You can put .Net code in them and fully integrate a report with your web application. One thing I plan to do in the future is take a screen where formatting has to be pretty and make a report from it. Then I’ll automatically get the cool features like export to Excel, PDF, .tif, CSV, etc.
Evil code that will break the garbage collector – level 300
I hadn’t done any profiling on EZWeb in a while, so I thought that I had better do some. I like Application Center Test that comes with VS 2003 EA, and I also watch my performance counters while it’s running. I tell you, it’s easy to cause a memory leak in .Net. I predict that fixing .Net memory leaks will be a sizable consulting niche in the near future as more .Net apps go into production. Especially web applications where the Page object is being created and handed over to the garbage collector many hundred times per second. I found a really nasty memory leak in EZWeb this morning, and it can happen to anyone with normal code. If you are currently using version 0.9 or 1.0 of EZWeb, I’ll tell you what code to change to fix it, and I’m going to post a v1.1 release to GotDotNet as well. So, here is the scenario. I define my own user object, and to conform to Forms-based authentication, I never wanted my User property to be null – System.Web.UI.Page.User is never null. If no one is authenticated, it comes back with an empty GenericPrincipal object. I created an “Empty” property of my User (WebPrincipal) object much like string.Empty and Color.Empty, so whenever there is no user logged in, the User will be WebPrincipal.Empty:
protected static WebPrincipal m_empty = WebPrincipal.InstantiateEmpty();
Then I have my Empty property, so I can test against WebPrincipal.Empty because as a static member, there will only be one instance. Well, I forgot about some code from when my User property was null:
private void SetUserEventListeners()
{
if(m_user != null)
{
m_user.LoggingOut += new EventHandler(User_LoggingOut);
m_user.LoggedOut += new EventHandler(User_LoggedOut);
}
}
So, this is what happens: m_user is an instance of WebPrincipal.Empty (a referenced by a static member that lives as long as the AppDomain). I am adding delegates in my Page class to events of WebPrincipal.Empty, so a persistent instance is maintaining references to methods of my Page class (EVERY SINGLE INSTANCE OF MY PAGE CLASS). What does this mean? It means that the garbage collector see that references are held to the Page instances, so it doesn’t garbage collect them. The gen 2 heap keeps getting bigger and bigger and bigger.
So watch out for this in your code. If you have long-lived objects that have references to short-lived objects, those short-lived objects become long-lived!
To fix this code, I only wire up event handlers when the User object is an actual good instance of WebPrincipal:
private void SetUserEventListeners()The Empty instance will have it’s IsAuthenticated property as false, so if it is true, then I know I have a good instance. Now I profile the app, and my gen 2 managed heap stays right where it should be.
{
if (m_user.Identity.IsAuthenticated)
{
m_user.LoggingOut += new EventHandler(User_LoggingOut);
m_user.LoggedOut += new EventHandler(User_LoggedOut);
}
}
CodeBehind attribute mysteriously reappears in VS 2005 – level 100
In my last post about CodeBehind, I stated that the CodeBehind attribute for the @Page directive was gone. It was, and VS 2005 Beta 1 threw an error when i tried to put it there. Mysteriously, now, it is back. It appears in the intellisense window and everything. I can use the code-behind attribute, but it literally does nothing now. It doesn’t make the “View Code” menu item work. It’s functionality is gone. If you want to implement a code-behind file as a base class, you can do that by making that type the Inherits”. . “ attribute, but it really won’t be a code-behind file because it wont work if you keep it next to the ascx file. You would have to put it in the Code directory for it to even compile. Then your user control would see it and be able to inherit its functionality, so you can still do the inheritence that code-behind gave you, but code seperation is done with the code-beside partial class.
To be honest, at first I was a bit bitter that Microsoft had taken away my code-behind, but now I do see the benefit of code-beside. I still think that code-behind should be an option. I don’t the the removal of features is the answer. I, as a developer, like options. I also want explicit compiling put back so that I can actually have a web-specific assembly. And I’d like to be able to designate more directories for dynamic compilation (not just /Code).
At last, I managed to convert my v1.1 web project to v2.0 (NOT 100% backwards compatible) – level 300
This is a chronicle of my adventure and probably indicative of some issues that you might face:
- I opened my project file which caused VS 2005 to run my project through it’s converter
- The converter pulls all my class files into the Code directory and converted all my code-behind classes to partial classes that compiled with the ascx and aspx files
- I tried to run the project: NO GO.
- I was using <head id=“head“ runat=“server“/> to expose the <head/> element to the server so I could programmatically add <title/> and other elements. Since v2.0 now has a Head property built in, my code is broken in this state.
- I refactored my code to use the new Head property, and I stripped out my own implementation of this feature.
- I tried to build my web site (which doesn’t produce a .dll by the way), it just does compile-time checking, and I was made aware of several more “errors“ throughout the site:
- My base page (in the Code directory) could not see any of my UserControl types – every page in my site has to be able to dynamically load one particular user control, and I was referencing that type in my base page. Since code outside the Code directory is not compiled until runtime, my base page had no visibility to that type; therefore, it could not compile.
- A side-effect of the code-behind model is a hierarchy of page and control inheritence. Every user control gets its own base class compiled into the assembly at compile time. You end up with this strongly-typed web library of all your user controls. Pages can reference controls in code, user controls can reference other user controls, etc. When you take that away and make all code dynamically compiled at runtime, you no longer have that library of classes at compile time, and your coding is limited.
- I retrofitted code-behind to my user control by making a base user control class (in the Code directory) and having the ascx inherit from that class. Then I can reference that base user control class in my base page and work with it. Remember, code-behind just mandates a base page for every control and page.
- I refactored all my code to reference the base page type instead of the actual user control type (which really doesn’t exist until it’s compiled just before runtime).
- I ran my web site, and I received a reflection exception (could not find my assembly).
- In my project, I define a web user abstract class that inherits from GenericPrincipal. For the app to run, I have to be able to instantiate a user class that inherits my abstract class. Since any class from any library could provide this user class, I have config information with the assembly name and fully qualified type. I use reflection to instatiate this type at runtime. With VS 2003, I knew exactly what my web assembly .dll was going to be called, so it was a no-brainer. With Whidbey, you don’t have a .dll until runtime, and then it’s a temporary .dll.
- I refactored my project and broke off the entire Code directory into a class library project within the same solution. This way I could guarantee the name of the assembly and perform the proper reflection code to instatiate my type.
- I ran the web site, and it worked!
- I proceeded to log in, and my site went into an infinite loop. The following is a REAL BREAKING CHANGE!
- When a user logs in, (upon authentication changing) I do a Server.Transfer(Request.Path, true) to start the request over fresh with the newly authenticated user. I do this because my login control is on every page instead of having a page as a dedicated login page (which would start a new request by going to another page). I pass true as the second parameter so that the querystring would be preserved. This is a very valuable feature. The problem with this in v2.0 is that this feature has been modified. Now, with that true parameter, both the querystring AND form variables are preserved and usable in the next request. This is a huge problem because when the user logs in with my login form, the page posts back and sends the data in the Form collection. The page authentications and does a Server.Transfer(. . . , true) and now sends the same form data to the next request (which logs the user in again and repeats the process all over again). This results in an infinite loop.
- I changed the line to Server.Transfer(Request.Path, false) so that the querystring or form is not sent, and all is well. My app seems to be functioning as normal. I probably will find some other issues, but for now it’s working. Of course, now if the user has some querystring data, and they log in, that data will be lost. I may have to resort to a Response.Redirect, but I’m trying to avoid it.
100% backwards compatible? Nope. The addition of the Head property and the Server.Transfer() change are the two Framework breaking changes I’ve found, but the whole elimination of code-behind is where I believe a lot of people will have problems. Honestly, it will take a while for everyone to wrap their brains around the change and realize that their apps are breaking because they don’t have a supporting class library as they did with all their code-behind classes. In those cases where compile time referencing is a must, we can put our code-behind files in the Code directory, and they will dynamically compile. This isn’t an ideal solution, though because then the code files and the ascx files are physically seperated from each other.
There are several bugs posted against Whidbey regarding this, and I’ve contributed one to suggest that dynamically compiled directories be configurable: Why “Code”. I may want my “Foo” directory to be dynamically compiled. What I would really like to see is for an explicit build process in Whidbey as their is in VS 2003. I want my web app to be compiled into a .dll in my bin folder. I want to know what the assembly name is going to be.
Whidbey *BUILD* web performance very slow – level 100
In addition to my previous post in response to Van’s post, I have found the build process in Whidbey to be especially slow when building a web site that has a helper class library project. When I build, the IDE hangs for at least 10 seconds before doing anything. I really hope this gets better.
Whidbey IDE performance – level 100
Van, from Microsoft blogged about Whidbey performance, so here is my experience in response to his query:
I have a Pentium M 1.8 Ghz with 1Gb RAM.
I open the IDE and open a 1MB web solution, and the IDE is consuming 128.5 MB of RAM. I don’t feel any hurt because I have plenty more, but when i close the solution, I get the hour-glass, and there is a noticeable delay. Also, when I create a new class file in the Code directory, I see a noticeable delay before the IDE is responsive again. Then, if I add a class library project to the solution (to reference from my web site), every build is noticeable slower than VS 2003. The IDE freezes for a moment before the build begins. There are some intermitten freezes that happen, and since I’m a developer, even 1 second is noticeable.
Since you asked, I’ve used the MS IDEs all the way back to Visual Notepad.
On a positive note, the intellisense menus (which are EVERYWHERE) are super fast and responsive. Kudos to the intellisense team!
VS 2005 Beta 1 project convert wizard performs well except. . . – level 100
When it pulls my code files into the Code directory, my casing is lost. MyObjectException.cs becomes myobjectexception.cs. I’ve already logged a bug with Microsoft, so hopefully this will get fixed. The code inside is good, but the filename is converted to all lowercase.
Otherwise the project convert wizard works well. I took my VS.NET 2003 project, and I opened the project file in VS 2005. The convert wizard was automatically launched, and it succeeded. It removed every CodeBehind and Inherits attributes from my @Page directives, and it converted all my code-behind files to code-beside (converted them from stand-alone classes to partial classes that merge with the aspx file upon compilation). It pulled all my class files into the Code directory, and it preserved all my namespaces.
The issue I’m wrestling with now is how to declare variables of type MyUsercontrol. All my usercontrols were converted to code-beside with partial classes, and my code can’t see the user controls (build error). There is code in the Code directory that is referencing a Usercontrol type (to dynamically load later on), and I’m guessing that the code in the Code directory is compile first (and it can’t find the user control which will be compiled later). I’m not sure if this is a bug or if I just haven’t figured out the *new* way yet.
CodeBehind attribute in @Page of Whidbey gone – level 100
In my journey down the Whidbey trail, I’m documenting key things I am discovering that are missing from the v2.0 books and articles I have read. A key piece of information is the the CodeBehind attribute of the @Page directive is gone. I’ve read that the code-behind model will still be supported in Whidbey, but I’m not seeing it. I have no problem converting to Code-beside with partial classes. There is still code separation, and the wizard is supposed to convert code-behind to code-beside, but it’s still a little buggy. It left all my code-behind files untouched, and they won’t compile unless they are in the Code directory. Of course the CodeBehind attribute has no bearing at runtime since it has always just been an IDE-specific attribute for linking the code file, but in the IDE, you’ll get the red squiggly line saying that no CodeBehind attribute exists. One thing is for sure. None of use will be using CodeBehind in Whidbey (but code-beside using the CompileWith attribute is better in my opinion).
CodeBehind does NOT seem to be supported in VS 2005 – level 100
I’m using VS.NET 2005 Beta 1, and I’m converting an existing web project to Whidbey format. The wizard pulled all my supporting code files (.cs) to the Code directory, but it left my code-behind files next to their aspx and ascx files. I learned that Web apps – called web sites in Whidbey – cannot be explicitly compiled as in VS.NET 2003. Meaning, I can’t put a Class1.cs in the root and have it compiled into the bin on Build. I have to either put this class in the Code directory or have it in a supporting class library project that I reference from the web site.
It appears that only code files in the Code directory get compiled on a Build, and the (legacy) code-behind files do not get compiled. Then on run, the page errors out because it cannot find it’s code-behind class from which to inherit.
Code-beside, however, does get compiled no matter where it is. The partial class linked through the CompileWith attribute gets compiled along with the aspx page.
So it seems that code-behind is really NOT supported in Whidbey. Am I doing something wrong? Is anyone else using Code-behind in Whidbey? or trying to.