Wednesday, May 21, 2008

Just few days ago, my friend at work found a peculiar error message in ASP.NET RangeValidator control. He was trying to validate length of a string in a TextBox. Controls on page definded as follows:

<asp:TextBox runat="server" ID="TB" />
<asp:RangeValidator runat="server" ID="RV" 
MinimumValue="3" MaximumValue="20" 
ControlToValidate="TB" Type="String" />

What he got was a best error message ever:

"The MaximumValue 20 cannot be less than the MinimumValue 3"

That's right! 20 cannot be less than 3!

Interesting isn't it?

I made some research of my own and I've found out that sane people should not look inside RaneValidator's (and other related classes) code! What it does inside is it uses a String.Compare to check if ranges are ok.

Of course, the problem are not the ranges, but the Type property of a validator. If set to String, it treates minimum and maximum values as strings and compares them as such - meaning that it compares character by character instead of just number to number.

That explains, why my friend got the error, but it certainly does not justify the text of the message! It might take long hours for an inexperienced developer to find where the problem lies. Come on Microsoft! You can do better than that!

Funny thing is that I never even thought about using RangeValidator to ensure string length, but suggested RegularExpressionValidator right from the start :-).

Wednesday, May 21, 2008 7:44:48 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
 Saturday, May 17, 2008

As we all know, ASP.NET uses one form model to do all it's magic. Love it or hate it, we have to live with it. 99% of the time, it is not a problem, but then there is this 1%...

The main problem with ASP.NET's model is that the form tag has a fixed action attribute. What if we want to change it? No, there is no simple way of doing it. Solutions vary. Most common one is to create your own FormControl that inherits from HtmlForm and override RenderAttributes method. Unfortunately, inside that method, we have to do everything the original method does and only change the action attribute to the desired value. Ugly!

Another one is to provide an OutputFilter for the Response but that is also a lot of coding.

My preferred way of dealing with this issue is to provide my own, special HtmlTextWriter. Its role is to intercept the WriteAttribute method call and provide my own value. Following code illustrates the concept:

class ActionAttributeWriter
    : HtmlTextWriter
{
    string action;
    public ActionAttributeWriter(
        HtmlTextWriter writer, string action)
        : base(writer)
    {
        this.action = action;
    }
    public override void WriteAttribute
        (string name, string value, bool fEncode)
    {
        if (name == "action")
        {
            value = action; 
        }
        base.WriteAttribute(name, value, fEncode);
    }
}

Only thing that is needed then is to use this writer instead of a normal one. Page.CreateHtmlTextWriter can be used for this purpose:

protected override HtmlTextWriter 
    CreateHtmlTextWriter(System.IO.TextWriter tw)
{
    ActionAttributeWriter writer = 
        new ActionAttributeWriter(
            base.CreateHtmlTextWriter(tw), 
            "action");
    return writer;
}

Solution is not very clean and I would certainly not recommend it for a public product, but it's better than nothing.

Saturday, May 17, 2008 2:09:17 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
 Wednesday, September 05, 2007

While working with any kind of configuration files in .NET, be it Web.config in case of ASP.NET or App.config in case of Windows Forms applications, we very often use the appSettings section. We use it to store all kinds of simple configuration options. Options, that are too simple for us to implement a completely new SectionHandler type. There is however one problem with appSettings section not very expressive.

What does it mean to be expressive? Consider the following example:

<appSettings>
  <add key="source1user" value="user" />
<add key="source1password" value="pass" /> </
appSettings>

In simple cases, it may be acceptable, but what happens if more user keys are required for some reason? Maybe we need to access few different locations, each of which requires a username and password? We may use some kind of prefix for each key like in the above example, but that is not very elegant. What is key and value anyway?

Another obvious problem here is when we need to have 2 parameters associated with a single logical functionality in the application, we need 2 entries in appSettings section.

If we still don't want to implement a new SectionHandler type, we have very nice option left: SingleTagSectionHandler.

MSDN describes it as: "Handles configuration sections that are represented by a single XML tag in the .config file". And that's about it. Unfortunately, (as usual) MSDN provides no example of how to use it. Fortunately it is quite simple:

<configSections>
  <section name="remoteDataSource" type="System.Configuration.SingleTagSectionHandler" />
</configSections>

<remoteDataSource username="user" password="pass" url="http://remote/" />

Using the newly declared section from the code is also easy:

Hashtable remoteDataSource = 
(Hashtable)WebConfigurationManager.GetSection("remoteDataSource");
string username = (string)remoteDataSource["username"];
string password = (string)remoteDataSource["password"];
string url = (string)remoteDataSource["url"];

Simple, yet useful.

kick it on DotNetKicks.com

Wednesday, September 05, 2007 8:45:40 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [4]  | 
 Thursday, August 09, 2007

OnClientClick is a useful property introduced in ASP.NET 2.0 that allows us to add some client-side behavior to button control. Using is as simple as providing the script to be called when a button is clicked by a user:

<asp:Button runat="server" ID="Save" 
    OnClientClick="return confirm('Are you sure?');" />

The problem is that if you use it like that, client-side validation won't fire. Looking at the rendered HTML quickly explains the situation:

onclick="return confirm('Are you sure?');WebForm_DoPostBackWithOptions(...)"

As you can see, the validation doesn't even have a chance to fire (which happens when WebForm_DoPostBackWithOptions is called).

Solving the issue is simple (or not). All that has to be done is a little change in our OnClientClick script (a piece of code found somewhere on the Internet):

<asp:Button runat="server" ID="Save" 
    OnClientClick="if (!confirm('Are you sure?')) return false;" />

Now we only return false (preventing the submit) in case a user didn't confirm the action, otherwise, the rest of the script will be called thus firing validation.

The reason I said that it may not be a simple issue is the fact, that the validation happens AFTER the confirmation, which is not the best thing in my opinion. Why ask the user about saving his data if there are still errors on the form, of which we will inform him after he confirms that he wants to save it?

After analyzing a bit, the code responsible for dealing with OnClientScript, I have come to a conclusion, that solving this problem is not an easy task. It would require some dirty hacks on the server side to make it pretty or calling validation routines on the client, before displaying the confirmation dialog (keeping in mind that checking if there are validation routines present at all is necessary in this case).

I've just left it as it is. After all it's only a minor inconvenience - at least in my case.

Thursday, August 09, 2007 10:38:51 AM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
 Tuesday, August 07, 2007

ASP.NET Ajax comes with a nice way to attach to a load event of a page. To do it just call Sys.Application.add_load and pass it a function as an argument. Done. Everything works as expected... WRONG!

It comes out that add_load fires on each callback and not only when the page loads for the first time. That is of course a problem if you want something to happen on page load only.

From what I've been able to learn, this behavior is by design. Although it is never mentioned in a strigh forward way in a description:

"Raised after all scripts have been loaded and after the objects in the application have been created and initialized."

There are some places in the documentation, that suggests that this is a way it was intended to be. First of all, ASP.NET Ajax tries to mimic that ASP.NET Page life cycle and as such, fires the load event every time there is a callback. The other thing that makes me believe, that load's behavior is there by design is this:

"You can use the event arguments to determine whether the page is being refreshed as a result of a partial-page update and what components were created since the previous load event was raised."

So now I know, but I still cannot accept the naming convention. Sys.Application plainly suggests, it's a kind of singleton, and not a per load thingy.

Tuesday, August 07, 2007 12:18:19 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [3]  | 
 Friday, July 20, 2007

For a couple of months now I've been running Windows Vista and Visual Studio 2005 without major problems (other than the commonly known ones). Since the first day of this setup I have been working on solutions that inlcude from one to many ASP.NET web applications. All of them are configured to use IIS rather than the built in web server. For all that time, everything was working fine until recently...

One of those days, while opening one of the solutions in Visual Studio, I was presented with a message telling me that my site is configured to use ASP.NET 1.1:

---------------------------
Microsoft Visual Studio
---------------------------
The site 'http://localhost/WebSite' is currently configured for use with ASP.NET 1.1.4322.573. Microsoft Visual Studio has been designed for use with ASP.NET 2.0; if not configured some features may make incorrect assumptions, and pages designed with the tool may not render correctly.

Would you like the site to be configured for use with ASP.NET 2.0?
---------------------------
Yes   No   Cancel   Help  
---------------------------

Needles to say that there were no changes made to IIS configuration of Application Pools or the pool the site is running on, but just to be sure, I've checked IIS Manager. The pool for the site was ASP.NET V2.0. I have agreed and allowed Visual Studio to make the "necessary" change. Needles to say, that nothing was changed in scope of application pools by Visual Studio. Fortunately, my solution kept working after that... for few days.

After few days I've got the very same message. Again, nothing was changed in IIS. This time I decided to leave my supposedly ASP.NET 1.1 in place. Of course everything worked after that also. Including debugging! But then I have the same message every time I open any of the solutions :-(.

I have found that other people also had this problem, and "aspnet_regiis -i" helped them, but it doesn't work for me :-(

Today I noticed that it gets worse. Now I get the message every time I open any of my solutions that include web sites :-(

Friday, July 20, 2007 2:05:07 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [3]  | 
 Sunday, July 15, 2007

ASP.NET despite its many nice features, has also a lot of nasty ones. Some of them are critical - like a design flaw in the way controls are rendered - by the controls themselves (only in version ASP.NET 2.0 Microsoft introduced the concept of Adapters, but this thing is beyond repair. There is just to much logic already in Render methods of all the existing controls to make using adapters easy). Others are just plain annoying, but we mostly we can live with them and even find workarounds.

Today I simply had enough of the style="border-width:0px;" attribute that ASP.NET adds to every img tag it renders from the Image control. There is strightforward way (that I know of) to remove this thing! Try as you might, there will always be a border-width style attribute on you images with either 0px, or whatever value you assign in you ASPX file. But there is a workaround.

To make the border style gone, we have to create our own Image control (inheriting controls is usually a good thing). In this control we have to resort to a trick of overriding the BorderWidth property by returning anything other than Unit.Empty:

public override Unit BorderWidth
{
    get { return Unit.Pixel(0); }
    set { ; }
}

This will cause the border style not to be rendered at all. Additional side effect which is obvious when looking at the above code is that now it is impossible to set BorderWidth property in any way. The value will alwyas be Unit.Pixel(0). This is also a good thing since we really shouldn't set any of the style properties inline but rather use a css style sheets for this purpose.

Sunday, July 15, 2007 2:39:59 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [6]  | 
 Saturday, July 14, 2007

From time to time, there is a need to get something from a file system in our ASP.NET applications. In those cases, we use the Server.MapPath() call on our pages classes. But what about class libraries?

Usually in class libraries in order to get the physical path of a file on disk we can use something like HttpContext.Current.Server.MapPath() and it works as long as there is a context i.e.: HttpContext.Current is not null. Sometimes however it may happen that there is a task running on the server which does some work without any request being processed. What then?

Enter the HostingEnvironment.MapPath() method where HostingEnvironment is a class defined in System.Web.Hosting namespace. It works the same way, as Server.MapPath() but it is a static method requiring no context to be present.

Saturday, July 14, 2007 5:46:21 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
 Thursday, July 12, 2007

ASP.NET Pages offer us a declarative way to set some of the properties such as Theme, MasterPageFile or Title in the Page directive. A nice feature indeed. The problem is that the same ASP.NET or maybe the Web Forms framework and Visual Studio stand in our way when we try to set our custom properties this way. It is possible but not developer friendly in a least.

To do it, we have to use the CodeFileBaseClass property and set it to the same base class that our page inherits from. More on this on K. Scott Allen's blog. Although it is technically possible to set this attribute to some class upper in the hierarchy I have encountered random weird behavior of Visual Studio after doing so. To be safe it is better to use the same base class both in the inheritance and in the CodeFileBaseClass attribute.

What about generic types? The tool (Visual Studio) support for generic types has never been great (not to say there is virtually no support). The fact that Visual Studio makes it hard to use CodeFileBaseClass difficult does not make it easier when it comes to generic base pages, but it can be done!

Suppose we have a type in the App_Code directory:

public class MyType
{
}
And also, defined in the same directory, we have a base page class:
public abstract class BasePage<T> : Page
{
}

And finally there is a Default.aspx page in the project that inherits from the our BasePage class:

public partial class _Default : BasePage<MyType>
{
}

Obviously we cannot just put a type name as BasePage:

CodeFileBaseClass="BasePage"

It won't work, because there is no such type. The message is: "Could not load type 'BasePage'". Our type is generic so we have to use it's full name:

CodeFileBaseClass="BasePage<MyType>"

But this also won't work. It will fail with the same message. That's becuse it is a C# specific representation of a generic type name. What CLR sees is something different. In order to make it work with a generic class we have to lower ourselves to the CLR level and use it's notation. This would mean using something like:

CodeFileBaseClass="BasePage`1[[MyTypebecause]]"

This thing actually works! If your types reside in some kind of namespace, has many generic parameters or worse yet, is part of a strongly named assembly, the whole CodeFileBaseClass starts to look scary and I don't think it is worth it. There is a trick however that may civilize the thing you enter in CodeFileBaseClass that allows to use any kind of base page class without making it complex. Just create an intermediate class like this:

public class StandardBasePage : BasePage<MyType>
{
}

and inherit your page from it. Than you can use this new type's name in CodeFileBaseClass without having to deal with generic parameter issues.

kick it on DotNetKicks.com

Thursday, July 12, 2007 4:56:35 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, July 04, 2007

Following my last article on creating specialized validators, below I present the EmailValidator control which validates user input with a pattern of an email:

public class EmailValidator 
    : RegularExpressionValidator
{
    public EmailValidator()
    {
        ValidationExpression = 
        @"^[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]@
        [a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.
        [a-zA-Z][a-zA-Z\.]*[a-zA-Z]$";
        ErrorMessage = "Email is incorrect";
    }
}
Note that ValidationExpression is broken so it may be better displayed in the browser. As for how accurate, the expression is. It was taken from the Regular Expression Library page and I have had no problems with it.

Usage on a page after registration:

<my:EmailValidator runat="server" ID="EmailCorrect" 
    ControlToValidate="Email" />
Wednesday, July 04, 2007 6:03:19 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 

Validation controls are one of the best features that ASP.NET has to offer. They allow us to perform both client and server side validation and work very well well with the Control model that is given to us by the Web Forms model. Here I will describe how to use RegularExpressionValidator so that never again will you be searching for that email matching regular expression on all of your pages.

Usually when you use a RegularExpressionValidator you just drop it on a form (or code it by hand) and set few properties. Among them, there is the ValidationExpression. When done, it looks more or less like this:

<asp:RegularExpressionValidator runat="server" 
    ID="OnlyNormalLetters" 
    ControlToValidate="Login" 
    ErrorMessage="Login contains illegal characters" 
    ValidationExpression="[a-zA-Z]" />

As I have described in my article on the best practices of inheriting controls, it is a good idea to limit the number of times important things are repeated in the code. In case of RegularExpressionValidator, the important thing that gets repeated is of course the ValidationExpression property.

To avoid repeating the same expression on each page that requires it, it is better to create a new class that inherits from RegularExpressionValidator. In this class set the RegularExpression property to some constant string like on the following example:

public class NormalLettersValidator 
    : RegularExpressionValidator
{
    public NormalLettersValidator()
    {
        ValidationExpression = "[a-zA-Z]";
    }
}

And that's it. Using this validator is the same as using the built in one, but you don't need to provide the same ValidationExpression any more. Just register it in either web.config file or on the page and you are good to go.

Of course the example is very simple, but I hope it demonstrates a useful concept.

kick it on DotNetKicks.com

Wednesday, July 04, 2007 5:55:43 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, June 25, 2007

Almost every time I'm working on an ASP.NET project I create a Visual Studio solution that consists of at least two projects: the web project and a class library. The first one is obviously needed. As for the second, what I put there include all kinds of ASP.NET related classes such as the BasePage class or just custom controls. This makes it easy to use those controls since Visual Studio (usually) automatically adds them to the Toolbox.

There are times however, when I need to make something quick. Perhaps a small project to test a new idea. In those cases, I rarely go for the 2+ projects solution layout since Visual Studio is standing in my way a bit - i.e. by hiding the possibility of adding new project to an already existing Web Site project (solution node is not visible on the tree view in Solution Explorer, but it is still possible to add the project using File menu). So I end up with only one project and the App_Code folder.

Working with App_Code is not a problem as long as you don't need to make some configuration in the Web.config file. Some elements require you to specify a type name. Normally in such a case, you need to provide a valid type format name in a form of <typename>,<assemblyname>. As long as you know the assembly name it's OK, but wait! There is no explicit assembly for App_Code. There is however an assembly behind the App_Code directory. It is simply called App_Code!

That said, it is usually enough to just specify the type name, without assembly name, for types defined in the App_Code directory.

So what about controls? In order to work with a control defined in App_Code directory we need to either register it on a page or in a Web.config file. There is however one issue. In order to register a control in a Web.config we need a namespace. By default however, neither pages nor classes added to an App_Code folder have a namespace. This is only a minor inconvenience because ASP.NET does not prevent us from adding a missing namespace declaration to a class in an App_Code directory. By adding such a namespace to a class representing ASP.NET Control, we can then add a registration in a Web.config file like the following one:

<pages>
  <controls>
    <add namespace="MyControls" tagPrefix="m"/>
  </controls>
</pages>

Notice that assembly attribute is not required.

For working with code, there is also a special class that helps with issues arising from the fact that there is no explicitly assembly nor a namespace for types in an App_Code directory. If at any time, there is a need to work with a type object of a class from the mentioned directory, .NET framework offers us a class called BuildManager which defines a GetType. Using this method it is possible to get an instance of a type object by providing just a name of a class defined in the App_Code directory.

kick it on DotNetKicks.com

Monday, June 25, 2007 6:17:51 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, June 20, 2007

After reading my article on recursive properties of ASP.NET controls, where I point out that not all properties are recursive, I have decided to fix one annoying behavior. The problem is that one of the most important property of all, the EnableViewState property is not recursive. This of course makes it useless in most scenarios. Never will we be able to rely on it while authoring our controls since ViewState can be disabled on any of the parent controls thus preventing our control from saving its state.

To solve this a very simple method can be used to check for the state of EnableViewState property:

public bool IsViewStateEnabled(Control control)
{
    if (control.Parent == null)
    {
        return control.EnableViewState;
    }
    return control.EnableViewState && 
        IsViewStateEnabled(control.Parent);
}
Wednesday, June 20, 2007 7:44:05 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, June 19, 2007

ASP.NET, or more accurately Web Forms, offer us a completely new way to create web pages. We can now work with control just like Windows developers. We even get to use an event driven model. How make best use of this? Below I present a useful pattern that I'm almost always following while working with ASP.NET.

Suppose that you are building a web application with lots of pages and forms for data input. On those forms you typically have input fields in form of TextBoxes, DropDownLists etc. Usually there are also some buttons that allow for invoking actions. Those actions include things like "Add", "Update" or "Cancel".

The standard way to create a form for inputing data would be to use mentioned before standard ASP.NET controls. That is fine. It gives us access to all that ASP.NET Web Forms can offer in terms of Page structure and event model. There is however one issue. In most cases there we will be several pages with the same buttons on them. Take for example the "Cancel", "Add" or "Update" buttons. Almost every time there is a data to be edited, there will be those buttons. If we use the "out of the box" approach, we end up with code similar to the following, on lots of pages:

<asp:Button ID="Add" runat="server" Text="Add" />

At first glance, there is not much wrong with it. If you look closer however, we can see the potential problems. One of the is certainly the Text property.

Why is it a problem? Suppose that now we need to localize the application? In this case, we will have to make a change in many places. Simple technique would be to decorate the Button control with attributes used by the Localization feature of ASP.NET like meta:resourcekey. But still we end up with one major problem: every time a change is required (that cannot be dealt with using Localization, Skins or other built in feature), we have to make it in many places. As we know: change in many places is a BAD PRACTICE.

What if we find out, that our add buttons need to have some special CssClass attribute? What if all our "Cancel" Buttons should have CausesValidation property set to false? Once again: a change is required in many places - which is ... BAD PRACTICE!

For localization, we can add an implicit localization attributes as mentioned above. What about CausesValidation or CssClass properties? Some of them we can try to set using Skin files, but as you will sooner or later discover, theming support in ASP.NET is VERY limited, especially when it comes to localization. You cannot localize skin files, some of the properties are not themeable etc. There are many examples of potential problems but what is a solution? It seams that there has to be a better way.

In my practice I have found that it is usually good not to use the standard controls that come with ASP.NET but rather make new ones that directly inherit from them. Doing so we inherit all the functionality without loosing anything (almost). As an example, take the aforementioned "Cancel" button. If we create a new control like this:

public class CancelButton : Button
{
    protected override void OnInit(EventArgs e)
    {
        Text = "Cancel"; // get value from resource
        CausesValidation = false;
        base.OnInit(e);
    }
}

And on pages, instead of the standard button, use this new control:

<my:CancelButton ID="Add" runat="server" />

In doing we allow ourselves to make changes in one place that will affect the whole application. In this way, without much work, we have gained a lot of flexibility for the future and saved a lot of potential work. If some time in the future, we need to localize the Text property for all Cancel buttons, we can do it in just one place which is a GOOD PRACTICE.

Benefits do not end there! If some day, there is a requirement, that all buttons should now be LinkButtons instead of normal Buttons we can easily do it bu just changing the base class from which our CancelButton inherits and the same technique can be used with other controls too (as long as their public interfaces match at least in naming).

Now the question is if you should always use the inherited controls. As usual, there is no simple answer to that question. There is a cost of having a lots of additional classes in the project if we try to follow this rule. Imagine that just for standard buttons, there will be quite a few: Add, Cancel, Remove, Back, Change, Edit just to mention some of them. For small, fast'n'dirty projects it will of course be a huge overkill (or will it?), but if you know that the project is not a small task, it is, in my opinion, a thing that should be seriously considered.

kick it on DotNetKicks.com

Tuesday, June 19, 2007 8:32:37 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [4]  | 

I'm a big ASP.NET lover mostly because of the fact that I can work with HTML in a more abstract way presented to me in form of controls. While authoring controls, it is always my goal to write as little HTML code as possible. To make it possible I relay heavily on composite controls. Sometimes however it is not possible or simply to complex to achieve a result using a composition of controls. That's where the Render method comes in handy.

Using Render method and accompanying HtmlTextWriter object we can write plain HTML using writer.Write() method. This however forces us to write HTML which I try to avoid. Here also the  HtmlTextWriter offers some alternatives that include writer.RenderBeginTag() method and HtmlTextWriterTag enumeration. Using them, we can generate HTML in a way that allows for some degree of compile time checking and some enhancements. If we just used the following code:

writer.RenderBeginTag("h1");

there is little that protects us from misspelling the tag name. There is also no way for a RenderBeginTag method to help us adjust the output to target concrete platform. We are simply telling it to write "h1" element and so it does because we expect it to. Consider however an alternative version:

writer.RenderBeginTag(HtmlTextWriterTag.H1);

This time, instead of passing "h1" string literal, we pass a value of a HtmlTextWriterTag enumeration. Now we are suggesting that we need the H1 element, but we leave a space for interpretation. What the writer object renders is up to it. Keep in mind however that HtmlTextWriter class and moreover the XhtmlTextWriter class are there to allow for customization. If there is a device that requires all tags to be uppercase, than it can be done using a special writer object that knows and targets the concrete device.

One thing that I only recently discovered however is how to write a "<br />" without writing "<br />". If we try to use the mentioned overload like this:

writer.RenderBeginTag(HtmlTextWriterTag.Br);
writer.RenderEndTag();

We will get an invalid HTML:

<br>

</br>

The solution is to use the writer.WriteBreak() method. It will output the required form of "<br />" and shield us from using plain text.

You may ask if it really matters. True, it is a very thin line of abstraction here but I like it this way.

kick it on DotNetKicks.com

Tuesday, June 19, 2007 7:22:24 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, June 18, 2007

While working with ASP.NET, from time to time, I need to change some parameter that is common to all controls of on a page. An example of such operation might be setting ReadOnly property for all TextBox controls etc.

Below is a sample method code I use to get a flattened hierarchy of controls on a page:

public static Control[] FlattenHierachy(Control root)
{
    List<Control> list = new List<Control>();
    list.Add(root);
    if (root.HasControls())
    {
        foreach (Control control in root.Controls)
        {
            list.AddRange(FlattenHierachy(control));
        }
    }
    return list.ToArray();
}

As you can see, it is pretty simple. The method recursively traverses control hierarchy and collects each control it finds on its way to a collection which is finally returned to the caller in a form of an array.

As mentioned above we can use this method to set the ReadOnly property of all TextBox-es on the page. To do this, a code similar to the one below can be used:

private void MakeTextBoxesReadOnly()
{
    Control[] allControls = FlattenHierachy(Page);
    foreach (Control control in allControls)
    {
        TextBox textBox = control as TextBox;
        if (textBox != null)
        {
            textBox.ReadOnly = true;
        }
    }
}

Using a combination of the above outlined methods it is easy to implement a kind of ReadOnlyMode page filter. Just identify what controls need to be ReadOnly and how to make them so (RadioButton for example doesn't have a ReadOnly property). When you know how and what you want to make ReadOnly, just override Page's OnPreRender method by adding a call a MakeTextBoxesReadOnly method (or whatever method you create).

Of course all of this is possible thanks to the great ASP.NET control model which is one of the things that I really like about ASP.NET.

kick it on DotNetKicks.com

Monday, June 18, 2007 11:07:38 AM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [3]  | 
 Tuesday, June 12, 2007

Today I've got a question if it is possible to make ASP.NET not to render the div tag around it's special hidden fields (i.e.: "__EVENTTARGET"). I have never thought about it before, so I didn't know the answer. I had to investigate. After a brief overview of the state of things, I have come to believe that there is no easy way to do achieve this. To confirm my suspicions I used the Reflector.

I have found that it is indeed possible to make ASP.NET not render the div tag if RenderDivAroundHiddenInputs property of HtmlTextWriter class returns false or if LegacyRendering is enabled. You can enable the later by setting xhtmlConformance mode to Legacy in Web.config file. Unfortunately the RenderDivAroundHiddenInputs property of HtmlTextWriter class always returns true and you cannot change it because it is internal. Additional investigation has shown that there is a class that overrides that property to return false. The class was: XhtmlTextWriter.

How to make ASP.NET use XhtmlTextWriter instead of normal HtmlTextWriter? I was unable to find a way to configure ASP.NET to do it. Setting xhtmlConformance mode to strict doesn't help. Google also is not very helpful. The only way seams to be either override Render method of a Page class like this:

protected override void Render(HtmlTextWriter writer)
{
    base.Render(new XhtmlTextWriter(writer));
}

Or better yet to override the CreateHtmlTextWriter like this:

protected override HtmlTextWriter CreateHtmlTextWriter(System.IO.TextWriter tw)
{
    return new XhtmlTextWriter(base.CreateHtmlTextWriter(tw));
}

This however requires you to use a kind of BasePage class for each page in your project (which is good, but not everyone likes it). Another concern I have is the fact that there is very little information on XhtmlTextWriter class, and the one that is available seams to suggest that the class is meant rather for mobile devices.

There is one more way you can try to solve the problem. You can use Response.Filter to do the job, but I would not recommend it unless you really, REALLY need to get rid of the div. Creating such a filter can really hurt performance. If you decide you REALLY need to, Mads Kristensen has an example of how to make a filter. He is using Response.Filter to move ViewState to the bottom of the page.

kick it on DotNetKicks.com

Tuesday, June 12, 2007 8:53:08 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [4]  | 

In my last article, I have described a "feature" of some of the properties of ASP.NET controls: recursive properties. It is obvious why it is important to know about it, but how does it impact the development?

Imagine that you need the following functionality: Page with on it controls and among them, there is a panel containing buttons such as Save, Cancel etc. This panel is inside some kind of container control - like div tag. The goal is to detect if there is at least one visible button inside the container. If so, render the container, otherwise, containing div should not be rendered at all.

<div runat="server" id="ActionPanel">
    <asp:Button runat="server" ID="Save" />
    <asp:Button runat="server" ID="Cancel" />
</div>

The code to accomplish this is "easy". Get the reference to the div control (which was made to runat="server"). Iterate over its child controls and for each control, that was a Button, check its Visible property. If at least one of the property returns true, the div should also be visible. Sample code to achieve this:

protected override void OnPreRender(EventArgs e)
{
    ActionPanel.Visible = GetActionPanelVisibleStatus();
}
private bool GetActionPanelVisibleStatus()
{
    foreach (Control control in ActionPanel.Controls)
    {
        if ((control is Button) && (control.Visible))
        {
            return true;
        }
    }
    return false;
}

I'm using a loop over all child controls to make it more generic.

The only problem is that above implementation does not work in some cases. The problematic situation only occurs if the div's Visible property is set to false. Once invisible, it stays that way with no way of going back to visible state! Why is that? Of course it is because of the recursive nature of Visible property. With this in mind it is easy to fix the problem by setting Visible property of the container control to true, before processing it's child controls:

protected override void OnPreRender(EventArgs e)
{
    ActionPanel.Visible = true;
    ActionPanel.Visible = GetActionPanelVisibleStatus();
} 

Makes sense?

Gathering it all up, it is now easy to build a self-hiding ASP.NET control (or UserControl). Just remember about recursion!

kick it on DotNetKicks.com

Tuesday, June 12, 2007 8:33:37 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 

One of the other days I encountered a strange problem. I was unable to set the Visible property of one of built in ASP.NET controls to true. I had verified that it is indeed true that I'm passing as a new value for the property. I had even used the Watch and Immediate Windows to set that value - nothing worked. I had decided to see what is going on and so I looked at the source code of the Control's Visible property...

What I have discovered is that the Visible property is in fact a recursive property! What does it mean? In short, the Visible property will only be true if the Parent's Visible property is true which in turn will be true if... and so on, up to the top of the control hierarchy. No a bad idea after if you think about it.

This feature obviously has some impact on how everything in ASP.NET works. As an example take a look at the following code:

Control parent = new Control();
Control child = new Control();
child.Visible = false;
Response.Write(child.Visible + "<br />");
child.Visible = true;
Response.Write(child.Visible + "<br />");
parent.Controls.Add(child);
parent.Visible = true;
Response.Write(child.Visible + "<br />");
parent.Visible = false;
Response.Write(child.Visible + "<br />");
child.Visible = true;
Response.Write(child.Visible + "<br />");
parent.Visible = true;
Response.Write(child.Visible + "<br />");

What would you expect the output to be? Below is the output generated by the above code.

False
True
True
False
False

True

The marked values are not so obvious, but if we take into consideration, the fact that the Visible property is recursive, everything starts to make sense... or does it?

At first I thought that there should be more of those type of properties. It makes sense for a Visible property to be recursive since if we do not render a parent, we won't render a child. Why then, wouldn't the other, well known and widely used property: EnableViewState work in a similar way? If we repeat the same experiment we will get a different set of results: