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]  | 
 Wednesday, August 15, 2007

A while back, I've posted about the problem with Visual Studio 2005 complaining about the site being configured for use with ASP.NET 1.1. I've lived with this problem since then, but today I had enough...

Here is the solution that works for me:

  1. Open Internet Information Services (IIS) Manager
  2. Select the root node
  3. Open Handler Mappings
  4. Remove each entry that points to ASP.NET 1.1

The entries from poing 4. are the handlers for files such as .aspx, .asmx and so on. Notice that there exist an entry for each of those files that maps to ASP.NET 2.0.

I'm not an IIS expert so I don't know if those deleted entries were necessary, but I haven't noticed any negative impact of not having them.

Before doing any changes to IIS I would suggest making a backup of all its configuration files, unless you are not afraid - like me (hence no screen shots and no concrete names for entries to delete :-) ).

Wednesday, August 15, 2007 7:46:45 PM (Central European Standard Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
 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]  |