Sunday, April 17, 2005

Maintaining Scroll Position on PostBacks

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/maintaining_scroll_position_on_postbacks.htm]

A classic problem is ASP.Net is then when you postback on a long page, you lose your position. For example, if you were at the bottom of the page and hit a server control, the page may refresh and put you at the top. This can be very frustrating for pages that are more than one screen long.

One solution is to use the Page property, SmartNavigation. This supposedly will persist position upon postback, but it is very delicate and can induce many rendering bugs. The page may work fine on your local machine, but may have all its styles messed up in other environments. I've tried using SmartNavigation before, only to have more hassle than its worth.

A more durable solution is described in an article by Steve Stchur: http://aspnet.4guysfromrolla.com/articles/111704-1.aspx. It walks through a solution and provides a custom control.

Monday, April 11, 2005

Adding and Finding UserControls

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/adding_and_finding_usercontrols.htm]

Dynamically adding a UserControl to a page provides great flexibility and code reuse. It's also relatively easy. You can add a control to a page by putting it in a PlaceHolder, and then retrieve it later using the Page.FindControl method. While there are other articles that address this, this blog post will highlight 3 tips:

  1. Make sure you give your added-control an ID so that you can reference it later
  2. Call the method that adds the controls from the OnInit method. This will then handle viewstate for you.
  3. Use Request.ApplicationPath to get the application path of the UserControl.

The code below provides a method, InitializeUserControl, which is called from the OnInit of the page. The method first gets the path of the UserControl, then loads it into the page, sets the ID, and then adds it to a placeholder. Note that if you don't set the ID, then you can't (easily) reference it later.

One convenient convention is having all directory paths end with a "/". By creating a utility method GetApplicationPath, we can wrap the Request.ApplicationPath method and add the "/" to the end. In real applications this Utility method would be abstracted to its own class.

public void InitializeUserControl()
{
   
// Put user code to initialize the page here
    string strUrl = GetApplicationPath() + "AddControls/WebUserControl1.ascx";
    UserControl uc = null;
    uc = (UserControl)Page.LoadControl(strUrl);
    uc.ID = "UC1";
    this.PlaceHolder1.Controls.Add(uc);
}

public static string GetApplicationPath()
{
    return System.Web.HttpContext.Current.Request.ApplicationPath + @"/";
} //end of method

We can find the control using the Page.FindControl method and the ID we assigned above. In the snippet below we cast the UserControl to the appropriate type (WebUserControl1), and then call its custom property MyNewProperty.

UserControl uc = null;
uc = (UserControl)Page.FindControl("UC1");
this.Label1.Text = ((WebUserControl1)uc).MyNewProperty;

Thursday, April 7, 2005

Extending WebControls to make your own Server Controls

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/extending_webcontrols_to_make_your_own_server_controls.htm]

There are several different groups of controls in ASP.Net, ranging from the foundational HtmlControls to the advanced Custom Server Controls:

  1. HtmlControls - standard HTML controls. (In the System.Web.UI.HtmlControls namespace).
  2. WebControls - ASP.Net controls. These include controls with similar Html counterparts like Button and Dropdown, but also have advanced controls like Validators and DataGrid (In the System.Web.UI.WebControls namespace).
  3. UserControls - Combines multiple controls into a single, reusable control (Inherits from System.Web.UI.UserControl class).
  4. Custom Server Controls
    1. Composite Custom Controls - create new controls from existing server controls.
    2. Rendered Custom Controls - create entirely new controls from raw HTML.
    3. Extended Controls - creates a new server control by inheriting from a previous control.

While everything ultimate reduces to Html, grouping controls together for reusable packages lets us save a lot of time. One such technique is to create an Extended Control by inheriting from an already existing control. This is great for when you want to build off a single control and extend its functionality. For example you could inherit from the TextBox class and add a new method ToLower which makes all the text lowercase.

There are several benefits

  1. Very easy - just create a new class that inherits from the control you need
  2. Has all the properties of the base control
  3. Has Design-time support (unlike User Controls)

This is easy to do, here's how:

  1. Create a new WebControlLibrary (compiles to a DLL). This is used for Composite and Rendered controls as well.
  2. Add a new class called TextBoxA, and make it inherit from System.Web.UI.WebControls.TextBox
  3. Add the methods and properties you need.

using System;using System.Web.UI.WebControls;namespace WebControlLibrary1{    ///     /// Summary description for TextBoxA.    ///     public class TextBoxA : System.Web.UI.WebControls.TextBox    {        public TextBoxA()        {        }        public void ToLower()         {            this.Text = this.Text.ToLower();        }        public string NewProp         {            get             {                if (ViewState["NewProp"] == null)                    return "";                else                    return ViewState["NewProp"].ToString();            }            set             {                ViewState["NewProp"] = value;            }        }    } //end of class}

 In the code snippet, we've added a method ToLower which references the textbox property "Text" and makes it lowercase. We've also created an arbitrary property NewProp and made it save data using ViewState.

We can load this easily into Aspx pages by first adding the DLL to the project like any other reference, and then adding the control itself to the toolbox. This lets us perform drag & drop operations like any other WebControl.

  1. In the ToolsBox, right click for the context menu and select "Add/Remove Items"
  2. A new window appears with two tabs: (1) .Net Framework Components (selected by default) and (2) COM Components. Within the tab there is a list of controls with checkboxes.
  3. Click the browse button to find the WebControlLibrary  we just created, and add it.
  4. Select the checkboxes for the controls you want to appear in the ToolBox.
  5. The controls are now in the toolbox, and you can drag them onto a page just like any other.

If you don't want to add it to your toolbox, then you can also directly type the Html. You need to first Register the assembly by putting something like this at the top:

<%@ Register TagPrefix="cc1" Namespace="WebControlLibrary1" Assembly="WebControlLibrary1" %>

And then reference the control in the page by:

<cc1:TextBoxA id="TextBoxA1" runat="server">cc1:TextBoxA>

In summary, this is a quick technique with high return, and therefore a good skill to have.

Monday, April 4, 2005

Unit Testing the Data Access Layer

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/unit_testing_the_data_access_layer.htm]

I had the opportunity to write an article for 4guysfromrolla - "Unit Testing the Data Access Layer".

"Unit testing is becoming very popular among .NET projects, but unit testing the Data Access Layer (DAL) still remains a common obstacle. The problem stems from the very nature of databases: they are slow, common, persistent, external, and relational. This conflicts the nature of unit tests, which should be quick, independent, and repeatable..."

You can read the entire article on the 4GFR website at:

http://aspnet.4guysfromrolla.com/articles/040605-1.aspx

Sunday, April 3, 2005

Resolving Http 500 Server Errors in ASP.Net and IIS 5.1

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/resolving_http_500_server_errors_in_aspnet_and_iis_51.htm]

Every developer likes to take certain things for granted - like ASP.Net being configured correctly with IIS. However sometimes there will just be something non-obvious that is preventing ASP.Net pages from being served, returning an Http 500 error instead. The frustrating thing is that these are often caused by system configuration issues that most developers should never need to worry about. Below I offer some advice intended for IIS 5.1 on a local dev machine that resolves some of these errors. The problem is most likely:

  1. IIS or ASP.Net simply not installed correctly
  2. Security configuration

0. The Basics

First, try the classic: reboot your machine.

If that doesn't work, then turn off friendly errors in IE (tools > options > turn of friendly errors). This will give you a more helpful message like "Logon failure: user not allowed to log on to this computer." instead of just "500 Server error".

1. Check that IIS works

Be aware of the difference between ASP.Net and IIS. ASP may be installed fine, but IIS may be messed up. Some general tips:

  • See if you can view http://localhost/iishelp
  • Try viewing an HTML page through IIS. This totally bypasses any ASP.Net issues.

If you can't view IIS, then perhaps IIS is disabled or turned off.

2. Other Web Servers interfering with IIS

If this is the first time you installed IIS, perhaps there is another webserver running on your machine that is interfering with it (or if you disabled IIS and installed another Web Server). For example sometimes Java developers have another server using port 80 that blocks IIS. Try turning this other server off.

3. Uninstall and reinstall IIS and ASP.Net

Perhaps uninstalling and reinstalling will fix it.

  • Restart IIS by typing iisreset at the command line.
  • Reinstall ASP.Net by typing "aspnet_regiis.exe -i" at the command line.

If that doesn't work, you can uninstall IIS and ASP.Net, rename the inetpub directory to effectively delete it (while still saving your files), and then reinstall IIS and ASP.Net. This may reset user account systems.

4. Set ASP.Net security permissions

Make sure that the ASP.NET user has rights on Inetpub. Add the ASPNET user to INETPUB folder's users (Security tab in Properties) and granted it full control.

5. Check the Local security policy

In Admin Tools > Local Security Settings > Local Policies > Security Options > Audit Shut down system immediantly if unable to log secuiryt aufits --> should be disabled.

6. Check the Registry

In the registry editor (type regedit at the command line), check HKEY_LOCAL_MACHINE\SYSTEM\CurrentControLSet\CONTROL\LSA\CrashOnAuditFail

Set default = "0" (should not be "value not set")

7. Check the Machine.config for security settings

As a last resort, change machine.config,probably located in a directory like: C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\CONFIG\machine.config

Look for  the xml tag "

Note that this is highly un-secure, but may be useful for letting you continue development while your IT staff investigates issues further.

 

Conclusion

I've had the misfortune of needing to fix this on many laptops now, and these hard-learned-tips have helped me out.

Wednesday, March 23, 2005

JavaScript URL encoding with Apostrophe

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/javascript_url_encoding_with_apostrophe.htm]

In a previous post I discussed using HttpUtility.UrlEncode to encode querystrings. While this is a great start, we can extend our encoding abilities using JavaScript's escape and unescape methods.

Sometime you'll need to encode at the client side, such as passing data to and from a pop-up window using querystrings (solely a client activity). While escape is very similar to HttpUtility.UrlEncode, there are some slight differences. Escape will encode both the apostrophe (%27) and space (%20 instead of '+').

The problem is that sometimes the security filter on the Web Server won't even allow the escaped chars. They won't allow apostrophe, but they won't allow %27 either. An easy way to test the allowed URL characters on a development site is to just append a dummy querystring, such as www.mySite.com?url=. Depending on the security system installed, you may get an error like "Inline Html scripts are not allowed in URLS for security purposes."

One solution is to take advantage of the safe '*' character. You could first encode the string, and then replace all '%' with '*'. This would give you the safe sequence %*27 instead of  ' or %27. We could then synchronize our server side encoding functions to match this pattern to allow us to freely pass encoded data between the client and server. Below is the HTML for a page to demonstrate this. It contains a encode and decode textbox and button. The buttons call their respective functions to encode/decode the data and store it in the other textbox.

DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
 <HTML
>
     <HEAD
>
         <title>Encodetitle
>
         <meta name="GENERATOR" Content
="Microsoft Visual Studio .NET 7.1">
         <meta name="CODE_LANGUAGE" Content
="C#">
         <meta name="vs_defaultClientScript" content
="JavaScript">
         <meta name="vs_targetSchema"
             content
="http://schemas.microsoft.com/intellisense/ie5">
         <script language
="javascript">
            

         script
>
     HEAD
>
     <body MS_POSITIONING
="FlowLayout">
         <form id="Form1" method="post" runat
="server">
             <P>Encoding TestP
>
             <P><INPUT id="TxtEncode" type="text" name="TxtEncode">
             <INPUT id="BtnEncode" title="Encode"
                     onclick
="DoEncode(document.Form1.TxtEncode.value)"
                     type="button" value="Encode" name="BtnEncode">
             <INPUT id="TxtResult" type="text" name
="TxtResult">
             <INPUT id="BtnDecode" onclick="DoDecode(document.Form1.TxtResult.value)"
                     type="button" value="Decode" name="BtnDecode">P
>
         form
>
     body
>
 HTML>

We can encode our data between client and server by combining JavaScript's escape and unescape methods, HttpUtility's UrlEncode and UrlDecode methods, and taking advantage that '*' isn't encoded in either.

Sunday, March 20, 2005

Method and Constructor Calling Order in OOP

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/method_and_constructor_calling_order_in_oop.htm]

I'm starting OOP in my C# class, and one of the issues to explain is the order that methods and constructors are called for inherited objects. People with a vague idea of inheritance know that one object (derived) can inherit another (base), where the derived object can reuse parts of the base. However, the behavior of the objects depends on what order the members are called in. Given a base and derived object, we want to know the code flow if the derived constructor or method is called.

For constructors, the base member is always called first. For methods, the question is really not-applicable because when there is a base and derived method both with the same name, the base member is only called if the the developer explicitly calls it with the base keyword. Let's flush this out.

Constructors

Given the classes:

public class MyBase
{
    public MyBase()
    {
        Console.WriteLine("Mybase()");
    }
}

public class MyDerived : MyBase
{
    public MyDerived()
    {
        Console.WriteLine("MyDerived()");
    }

    public MyDerived(string strName)
    {
        Console.WriteLine("MyDerived(string strName)");
    }

    public MyDerived(string strName, int intId) : this(strName)
    {
        Console.WriteLine("MyDerived(string strName, int intId)");
    }

}

Running MyDerived d = new MyDerived("name",5); will display:

Mybase()
MyDerived(string strName)
MyDerived(string strName, int intId)

As we walk through with the debugger, before executing any code, it will start at the overloaded MyDerived and walk down to the MyBase constructor. Once there, it executes the base constructor and walks back up to the calling point - executing MyDerived(string), and fthen finally MyDerived(string,int).

This makes sense - the base object should be instantiated first because we need to build the individual parts before building the whole.

Methods

Given that base class constructors are executed, many people subconsciously think that in cases where the base and derived methods have the same name, that base methods are executed too. However, this only occurs if the developer explicitly makes it that way, by using the "base" keyword (note that the derived can only call the immediate base, i.e. base.base would return an error):

public new void MyMethod(string strName)
{
    base.MyMethod(strName);
}

If "base.MyMethod(strName)" is omitted, then MyMethod will not be called - not with inheritance, polymorphism, or anything else. As we look at the keywords used in OOP, we see that this makes sense in each individual case:

Base Method: Virtual/AbstractDerived Method: Override/NewResult for calling Derived Method
virtualoverrideOnly current method is called.
abstractoverrideNothing to call (abstract has no implementation)
- (no keyword)newnew keyword hides base, therefore base won't be called by the very nature of what this keyword does.