Wednesday, March 07, 2007

Every ASP.NET developer knows (or at least should know) about the Life Cycle. Page has it's Life Cycle, controls have theirs Life Cycle (more or less the same as the one of the Page). There is a good article on MSDN regarding the Page Life Cycle. From it, you will learn that at any given moment, the Page and all controls are in the same "phase" of the Life Cycle, be it Init, Load, PreRender or Unload.

The interesting part about the Life Cycle is when it comes to dynamically added controls. The controls you add in code using Controls.Add call. Since controls also have the Init, Load and PreRender and Unload phases, what happens when we add a new control during a PreRender phase? As stated above, Page and all controls are always in the same phase. So what happens?

The same article explains this phenomenon and calls it "Catch-up". What it basically means is that at the time of adding a control to a Controls collection, the new control "walks" through all it's phases until it "catches-up" with the current phase of it's parent control (i.e. Page).

In order to better understand this, you can use the following example. On your page override an OnPreRender method and add a following code:

protected override void OnPreRender(EventArgs e)
{
    base.OnPreRender(e);
    Button b = new Button();
    b.Load += new EventHandler(b_Load);
    b.Init += new EventHandler(b_Init);
    b.PreRender += new EventHandler(b_PreRender);
    b.Unload += new EventHandler(b_Unload);
    Controls.Add(b);
}

You will also need to create the event handler methods. As the next step, put a break point on each of those handler methods and run the debugger to see what happens. You will notice that when control is added to a collection of Controls, it's events are fired immediately to catch up with the phase of its parent.

kick it on DotNetKicks.com

Wednesday, March 07, 2007 4:19:03 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, February 20, 2007

After a while of thinking and struggling with Control Adapters I was unable to find a good solution to get my Validation Controls render as images. I have came to the following conclusions:

  1. Control Adapters will not help
  2. Overriding each Validator is not a good solution
  3. Creating my own Validation Controls is not a good solution

Given the above, I have once again looked at everything I have learned. I have looked at the html code rendered by the controls and then... solution came to me! It turns out that we don't need ASP.NET to get things working. ASP.NET stands in our way when it comes to handling this task, so why not use a plain old CSS? So I did.

When Validaton Control:

<asp:CompareValidator runat="server" ID="V" ControlToValidate="c1" ControlToCompare="c2" Text="Error Text" ToolTip="Title Text"></asp:CompareValidator>

is rendered on a page it looks more or less like this:

<span id="ctl00_V" title="Title Text" style="color:Red;visibility:hidden;">Error Text</span>

To make a nice image out of it, we need few things. First we need one tradeoff: we have to remove the Text attribute, otherwise it will mess the looks a bit. Next we decorate the server control with a CssClass attribute with a value such as "error". Next we create a style:

span.error
{
  display: -moz-inline-stack;
  display: inline-block;
  background-image: url(error.gif);
  background-repeat: no-repeat;
  height: 16px;
  width: 16px;
}

Notice in the style few things. First, we need the <span> element to be "inline-block". That is because we need it to have a height and width. Furthermore, FireFox does not support "inline-block" (!!!) but we can use a simple workaround with "-moz-inline-stack" value as described by Nicholas in Pain with inline-block article (also see the comments). By default span (inline element) will only be as large as the text it contain. Since in the proposed solution, there will be no text in the <span> this is needed. Next, we set the background-image to a desired url and set the width and height of an element. That's it!

The important thing to note here is the "inline-block" value for a display property. It is a CSS 2.1 introduced value and browser support may vary. After analyzing the display declaration article on quirksmode, I've came to a conclusion that it should be safe to use this technique. Internet explorer "supports" it. Firefox "supports" it. Opera supports it.

Yet again. ASP.NET stands in the way... If you try to use a Display="Dynamic" property, you will find that the proposed solution does not work with FireFox. After a close analysis I came to a conclusion that it works with IE only by chance. The problem is that the validation scripts used by Validation Controls set elements display property to "inline" in case Display property was set to Dynamic on the server control. Internet Explorer somehow manages to use the value from the style which is "inline-block" and so it works. FireFox uses the "inline" value and so we have an <span> element with no content - an invisible element.

I have currently few ideas of how to overcome this problem. One way it could be done is to put an absolutely positioned Validation Control inside a relatively positioned <div> element like this. Remove the Display="dynamic" attribute and mark the containing div with a class="error" and change the styles as follow:

div.error
{
  position: relative;
  display: inline;
}
span.error
{
  position: absolute;
  left: 0; top 0;
}

The positioning of elements needs some work, but hey at least it works!

Complete code here: ValidationControlsAsImages.txt (.54 KB)

kick it on DotNetKicks.com

Tuesday, February 20, 2007 9:57:25 AM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
 Monday, February 19, 2007

Once again I have gone through the process of customizing the way the ValidationControls are rendered in particular I need them to render an image. I have described a workaround of how to get them to render as images. The problem is that you have to tweak each validator that you want to use. In the same workaround, I have described, why it is not possible to use use Control Adapters to achieve the goal - the really important part that makes validation controls work is hidden in the Render method which is not called by the WebControlAdapter. Today I have learned that Render is called by the ControlAdapter class which is a base class for a WebControlAdapter. If we forget recommendation to use a WebControlAdapter for controls that inherit from WebControl we are almost there.

Almost... It makes a big difference. It turns out, that you cannot customize the element name if you use the ControlAdapter so you cannot change the default <span> element to an <img> element, but at least you can still get the Render method of BaseValidator to be called.

What is my opinion on the whole Control Adapters feature of ASP.NET 2.0? The idea was great. This is only a step in a direction where we should have begin and not end. I mean: why the a control needs to know how to render itself? Differently on different browsers. Differently, depending on the configuration, etc. Adapters make it all right. No longer controls have more then one responsibility. But that is only a try. Nice, but still only a try. The example of Validation Controls shows that once something is done wrong, it is very hard to make it right again. The same holds true for most of the existing controls. Just take a look at he amount of code in the CSS Control Adapters.

I only hope that in v.next some of the issues will be fixed. I know unfortunately, that it can only be a hope. There is a lots of code that would have to be rewritten and I don't suppose Microsoft will do it anytime soon :-(

Monday, February 19, 2007 1:45:43 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
 Wednesday, February 14, 2007

Introduction of Nullable<T> was a great thing that many of us have been waiting for for a long time. One of the benefits is the implementation of lazy loaded properties.

There are however few gotchas that you have to be aware of. Something that surprised me the most was the implementation of the ToString method:

public override string ToString()
{
    if (!this.HasValue)
    {
        return ""
    }
    return this.value.ToString();
} 

What is unusual with it? Given the following code:

int? i = null;
string s = i.ToString(); 

What would you expect to happen? I would expect a NullReferenceException to be thrown. After some thinking though, I'm not so sure anymore. If we take into consideration a fact that ValueTypes are not ReferenceTypes i.e. there is no reference to a ValueType unless it is boxed, than having no NullReferenceException is perfectly legal and obvious in the described scenario.
The ToString implementation above clearly fulfils this assert so there will be no NullReferenceException even if Nullable value is null.
Is it good or bad? Now when I know about it, it doesn't really matter that much for me, but I was very surprised nonetheless. I think though that since null is not really null in case of ValueTypes, maybe there should only be a HasValue property? That would however made using Nullable types a lot more cumbersome... Nothing is ever easy :-).

kick it on DotNetKicks.com

Wednesday, February 14, 2007 11:28:17 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, February 12, 2007

Today while working with ASP.NET I have received a "Internet Explorer cannot display the webpage" error when I tried to get to one of the pages. Other pages worked well. My first thought was to use a debugger of course and so I did only to be presented with a following message:

---------------------------
Microsoft Visual Studio
---------------------------
Unable to start debugging on the web server. Could not start ASP.NET or ATL Server debugging.

Verify that ASP.NET or ATL Server is correctly installed on the server.
---------------------------
OK Help
---------------------------

Strange...
I haven't changed anything in my computer's software configuration for a while now. Why would debugging stop to work when it worked well just few minutes ago?
It had to be somehow connected with that one page I thought so to get this solved I needed a working debugger. First I have killed the w3wp.exe process - didn't help. Next I have restarted a website in IIS - didn't help. Finally I went and restarted the World Wide Web Publishing Service and it did the trick. I had a working debugger so I could work on the main problem.
As it came out, I have made a simple mistake and caused an infinite recursion which caused a StacOverflowException to be thrown. After I have found the problem and corrected it my problem with a debugger came back! Aha! So if there is a StackOverflowException, something gets broken in the IIS!
Few tests confirmed it. I have observed that if a StackOverflowException is thrown while navigating to a page (without debugger attached) - nothing happens. You can do it "safely". If however, you are debugging and StacOverflowException is thrown inside your debugger, it usually takes only one such exception to kill IIS.
How important is this problem? It depends of course, but imagine what would happen if you have debugged a server running a couple of sites and all went down for no apparent reason while you have debugged your code. Fortunately usually it is not possible to run a remote debugger on a shared hosting environment :-)

Monday, February 12, 2007 9:55:11 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
 Wednesday, February 07, 2007

Today I have noticed the existance of an attribute inside System.Web.UI namespace, that made me curious. The attribute was: NonVisualControlAttribute. It was the first time I have seen it (or I don't remember it).

What does this attribute do? The name suggests that it maybe used by some visual tools. The MSDN documentation is not very useful (as usual) providing only information I have already figured out just by looking at the class name: "Defines the attribute that indicates whether a control is treated as a visual or non-visual control during design time" (MSDN). 

So what does this attribute do? I have searched the Internet for a while and found nothing useful, other than what I already knew. Then I have found that Visual Studio 2005 allows you to toggle whether to display Non Visual Controls using View menu. (you have to be in design mode to see this option). When you select not to display Non Visual Controls, they disappear from the design view like it would be expected. Is it useful? I don't know I have never needed such a feature and fortunately, by default, everything is visible.

Being curious, I have checked which controls have the NonVisualControl attribute applied and I have found that there are only 5 in the BCL:

  • DataSourceControl
  • HierarchicalDataSourceControl
  • ProxyWebPartManager
  • WebPartManager
  • HiddenField

When you look at the controls above, the important thing to notice is that "Non Visual" does not mean that the control does not render any html markup. As you can see, the HiddenField is also a NonVisualControl but it renders an input tag. WebPartManager on the other hand renders some JavaScript code.

Finally I have found a post on the very attribute written by Nikhil Kothari where he says the following: "Hopefully, it will be used to do more in the future, so start using it now, where it makes sense."

kick it on DotNetKicks.com

Wednesday, February 07, 2007 10:47:24 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 

While working with Visual Studio 2005 the other day I have noticed that my Keyboard Repeat delay has increased. It had happened to me a couple of times before. Always when I was working with Visual Studio so that is why I put the blame on it. Usually I haven't done anything to fix the problem, because it was not very annoying, and usually I could work with it until the end of day. After a restart, everything goes back to normal.

Today I had this problem again, but there were still few hours until the next restart. I had one idea that I wanted to try to see if it can fix the problem. The idea was to increase the Keyboard Repeat delay using Control Panel-Keyboard options. So I did. First I have increased the delay, applied the new settings and right after that I have decreased it to its normal level - the minimum. Voila, every thing worked like a charm. Even Visual Studio!

I wonder if any of you also has this strange problem?

Wednesday, February 07, 2007 10:33:33 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
 Tuesday, February 06, 2007

Last time I have posted my observations on the Remember Password feature of Microsoft SQL Server Management Studio. Today it got even worse! Not only MSSMS forgets my password on a random basis, It prevents me from logging in with a correct password! Yeah I have written about it last time, but this time I have entered the right password - 100% sure of that, and despite dozens of connect attempts it always said that login or password is incorrect! So I have retyped the exact same password and voila, after second connect attempt it worked.

Now. I know that there is SQL Server 2005 service pack comming out soon, but does anyone know if the login window will be fixed? Come on! Its only a UI with few imputs! How hard can it be?

Tuesday, February 06, 2007 11:29:32 AM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
 Saturday, February 03, 2007

There are couple of folders that have a special meaning in ASP.NET. Those folders include folders like App_Code where you usually put your code or App_Themes where you put themes. There is also an App_Data folder which "Contains application data files including MDF files, XML files, as well as other data store files" (MSDN).

From App_Data folder description it is obvious that it is where you should put your data. But how to do it? I have searched high and low for a methods or properties that help interact with this directory. The reason is because I don't like hard-coding strings in my code and I would have to hard-code at least one: "~/App_Data". I thought that since there are method to get the location of temp directory:

System.IO.Path.GetTempPath(); 

Or even to get the system direcotry:

Environment.SystemDirectory 

There should be a way to get the App_Data directory.

Apparently I was wrong. Unfortunately. There is no Strongly Typed method or property to get to the location of App_Data directory!

I have found 2 places in code where "App_Data" appears as a string (that's why I'm pretty sure there are no properties or methods). One place is a GetDataDirectory method in an internal System.Web.DataAccess.SqlConnectionHelper class and the other is in a SetUpDataDirectory method in a System.Web.HttpRuntime class.

My guess is that the first one is used for Membership Provider that by default uses Microsoft SQL Express database and App_Data directory to store the mdf files. The other one is probably not used at all - I have found no code that calls that method! 

When I have looked inside those methods I have found one thing that they have in common. Both set some data object in an AppDomain via:

AppDomain.CurrentDomain.SetData("DataDirectory"...) 

So I have made a test and used on one of my pages:

string dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory") as string; 

And of course it worked as expected. Unfortunately we cannot (or should not) use this kind of code since it is a dirty hack that relies on internal implementation of some internal classes and it also requires us to hard-code a string. So what's the benefit? The only one is that now I'm pretty sure, that there is no way to interact with App_Data folder using BCL so I will no longer have to search for it on the Internet - thing that I have done countless times.

kick it on DotNetKicks.com

Saturday, February 03, 2007 3:18:21 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  |