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.

 

Wednesday, March 16, 2005

Understanding HttpRequest URLs

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

Web applications often need to reference absolute paths, such as to retrieve images or Xml files. Fortunately, ASP.Net provides many ways to do this using the HttpRequest class. In code-behind pages this can be referenced as a property of the page like:

Page.Request.PhysicalApplicationPath()

For pages that aren't code-behinds, you can reference it through the current HttpContext like:

System.Web.HttpContext.Current.Request.PhysicalApplicationPath()

Given the following scenario, the table below shows the values for different types of paths.

  • ASP.Net application "Learning_VB", which resides on localhost (located at C:\Inetpub\wwwroot).
  • An aspx page, urltest, which is in the url/subfolder folder of the application
  • A querystring "id=5&name=Tim"

Path TypeValue
Page.Request.ApplicationPath/Learning_VB
Page.Request.CurrentExecutionFilePath/learning_VB/url/subfolder/urltest.aspx
Page.Request.FilePath/learning_VB/url/subfolder/urltest.aspx
Page.Request.Path/learning_VB/url/subfolder/urltest.aspx
Page.Request.PhysicalApplicationPathC:\Inetpub\wwwroot\Learning_VB\
Page.Request.PhysicalPathC:\Inetpub\wwwroot\Learning_VB\url\subfolder\urltest.aspx
Page.Request.QueryString.ToString()id=5&name=Tim
Page.Request.RawUrl/learning_VB/url/subfolder/urltest.aspx?id=5&name=Tim
Page.Request.Url.ToString()http://localhost/learning_VB/url/subfolder/urltest.aspx?id=5&name=Tim
Page.Request.Url.AbsolutePath /learning_VB/url/subfolder/urltest.aspx
Page.Request.Url.AbsoluteUrihttp://localhost/learning_VB/url/subfolder/urltest.aspx?id=5&name=Tim
Page.Request.Url.LocalPath /learning_VB/url/subfolder/urltest.aspx
Page.Request.Url.PathAndQuery/learning_VB/url/subfolder/urltest.aspx?id=5&name=Tim

The different types of paths have several differentiators:

  • Is it physical or virtual (note that web addresses use '/', and physical use '\') ?
  • Does it include the querystring?
  • Does it include the the full path or just start at the project folder Learning_VB)?

You can make your own version of this chart by simply creating a table on a WebForm, and then writing out the Path Type to the appropriate cell like so (note the code below is in VB, not C#):


    Private Sub Page_Load(ByVal sender As System.Object,
    ByVal e As System.EventArgs) Handles MyBase.Load

        Me.Label1.Text = Page.Request.ApplicationPath
        Me.Label2.Text = Page.Request.CurrentExecutionFilePath
        Me.Label3.Text = Page.Request.FilePath
        Me.Label4.Text = Page.Request.Path
        Me.Label5.Text = Page.Request.PhysicalApplicationPath
        Me.Label6.Text = Page.Request.PhysicalPath
        Me.Label7.Text = Page.Request.QueryString.ToString()
        Me.Label8.Text = Page.Request.RawUrl
        Me.Label9.Text = Page.Request.Url.ToString()
        Me.Label10.Text = Page.Request.Url.AbsolutePath
        Me.Label11.Text = Page.Request.Url.AbsoluteUri
        Me.Label12.Text = Page.Request.Url.LocalPath
        Me.Label13.Text = Page.Request.Url.PathAndQuery

    End Sub

I've found this a very useful chart for sorting out the different path types.

Monday, March 14, 2005

Three things you should know about DOS

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

Many developers never bothered to learn much about DOS because of the widespread availability of GUI applications, like Windows Explorer. However DOS is still useful in many cases, and essential to automate almost anything. Therefore it's worth knowing a couple basics beyond just making directories and copying files.

The Call Statement

As you break a big task into smaller ones, you will need to have one script call another. However DOS scripts effectively each run in their own thread, and are not like normal .Net methods where the caller automatically waits for the called-method to finish. The question to ask is "Do you want the parent script to wait for the child script to finish?"

  • Yes: Then use the call keyword, like:  call Child.bat.
  • No: Then simply the script directly, like: Child.bat.

This can be vital when having a main host script call a bunch of sub-scripts in sequence.

Passing in Parameters

DOS Scripts can take in and pass out parameters. The two batch scripts below show how:

Parent.bat: Pass the parameters into the child by adding it after the script being called. This passes in two parameters, "Hello" and "World!"

ECHO This is the host page.
Call Child_2.bat "Hello" "World!"
ECHO done with parent

Child.bat: Access the parameters being passed in by %n, where n is the ordinal of the parameter (starting at 1), such as %1 or %2.

ECHO I am the child
ECHO %1 Some Phrase %2
pause
ECHO done with child

Using Environmental Variables

DOS supports variables. You can create your own or use existing environmental variables, such as: SystemDrive, TEMP, USERNAME, windir. Type set at the command line to see all the existing environmental variables. For example, the System Drive may vary from machine to machine. Therefore instead of hard-coding it as "C", use %SystemDrive%.

You can also create your own variable using the syntax: SET [variable=[string]]. For example, run the following DOS commands:

Set MyDosVar="Hello World"
Echo %MyDosVar%

The Echo will output "Hello World", which is the value of the variable. Variable Scope encompasses all child windows opened by the parent window.

Conclusion

If all you have is a hammer, everything looks like a nail. By being aware of what good-old DOS has to offer, it opens up your options when trying to automate tasks.

Sunday, March 13, 2005

Understanding the Number of Bytes in Integral Types

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

As I prepare to teach about simple types in C#, one of the questions people will ask is "Why are there so many different integer types?"

C# supports nine integral types: sbyte, byte, short, ushort, int, uint, long, ulong, and char. Ignoring char, the table below shows the range and .Net Alias for each:

TypeAlias forAllowed Values

sbyte

System.SByte

Integer between –128 and 127.

byte

System.Byte

Integer between 0 and 255.

short

System.Int16

Integer between –32768 and 32767.

ushort

System.UInt16

Integer between 0 and 65535.

int

System.Int32

Integer between –2147483648 and 2147483647.

uint

System.UInt32

Integer between 0 and 4294967295.

long

System.Int64

Integer between – 9223372036854775808 and 9223372036854775807.

ulong

System.UInt64

Integer between 0 and 18446744073709551615.

The basic concept is that the larger the range of allowed values, the more memory the type requires to store that range. Range includes both magnitude as well as sign (+ or -). Therefore .Net provides different types to optimize for this. For example, no need to waste ulong when you only need to store the values 1 through 10.

Ultimately the types are based on binary storage. So storing the value 25 would really be stored as 11001, or: (1*2^4) + (1*2^3) + (0*2^2) + (0*2^1) + (1*2^0), or, more simply: 16 + 8 + 0 + 0 + 1. The following Excel spreadsheet demonstrates these calculations.

Notice that the range for unsigned integers start at 0. So byte (which has 8 bits) can store 2^8, or 256 values. This is spent covering 0 through 255. In order to make the type signed, or capable of storing negative values, there are two approaches:

  1. Use an extra bit to indicate the sign.
  2. Shift the entire range from 0 to some arbitrary negative number.

The second approach actually gives the larger range. For example, if sbyte used the first approach, it would use 1 bit for the sign, leaving only 7 bits for the magnitude. This would have a range of 0-127 (note: 2^7-1 = 127) in the positive direction, and 0-127 in the negative direction, for a total range of -127 to + 127. However, both the positive and negative directions cover 0, wasting a value. Therefore the datatype gets a larger range by simply offsetting the positive range: -128 to +127 instead of just -127 to + 127.

Given the power of today's computers, along with the simplicity of most applications, many developers can get away with just using the default int type (System.Int32) for all their integer needs. However it is still good to know what's going on behind the scenes because:

  • It is a common Computer Science principle and transcends merely the C# language.
  • You may work on an application where it does matter.
  • It will help you understand other applications that use these types.

Tuesday, March 8, 2005

How to reference a UserControl from a DataGrid

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

Sometimes you need to have a UserControl in a DataGrid, and sometime you also need to reference that control to either get/set its values. In ASP.Net, this is straight forward.

First let's create a UserControl and host Aspx page. The important sections are below, but you can download it here.

UserControl

Html:

<%@ Control Language="c#" AutoEventWireup="false" Codebehind="UCSimple.ascx.cs" Inherits="UIDemo.UC.UCSimple" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<asp:TextBox id="TextBox1" runat="server">asp:TextBox>
<
asp:Button id="Button1" runat="server" Text="Button">asp:Button>
<
asp:Label id="Label1" runat="server">Labelasp:Label>

CodeBehind:

private void Page_Load(object sender, System.EventArgs e)
{
   
// Put user code to initialize the page here
}

private void Button1_Click(object sender, System.EventArgs e)
{
    this.Label1.Text = this.TextBox1.Text;
}

public string TextValue
{
    get
    {
        return this.TextBox1.Text;
    }
    set
    {
        this.TextBox1.Text = value;
    }
}

Host Aspx Page

CodeBehind

private void Page_Load(object sender, System.EventArgs e)
{
   
// Put user code to initialize the page here
    if (!Page.IsPostBack)
    {
        string[] astr = new string[] {"aaa","bbb","ccc"};
        this.DataGrid1.DataSource = astr;
        this.DataGrid1.DataBind();
    }
}

private const int _UCColumn = 0;
private const int _UCControlPosition = 1;

private void Button1_Click(object sender, System.EventArgs e)
{
    int intRow = Convert.ToInt32(this.TxtRow.Text);
    UCSimple uc = (UCSimple)this.DataGrid1.Items[intRow].Cells[_UCColumn].Controls[_UCControlPosition];
    uc.TextValue = this.TxtSet.Text;

}

private void BtnGet_Click(object sender, System.EventArgs e)
{
    int intRow = Convert.ToInt32(this.TxtRow.Text);
    UCSimple uc = (UCSimple)this.DataGrid1.Items[intRow].Cells[_UCColumn].Controls[_UCControlPosition];
    this.LblGet.Text = uc.TextValue;
}

private void DataGrid1_SelectedIndexChanged(object sender, System.EventArgs e)
{
   
//Then this fires too.
    e = e;
}

private void DataGrid1_ItemCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e)
{
   
//First this fires
    e = e;
    UCSimple uc = (UCSimple)e.Item.Cells[_UCColumn].Controls[_UCControlPosition];
    this.LblGet.Text = uc.TextValue;

}

Get the UserControl

We can reference the control absolutely:

UCSimple uc = (UCSimple)this.DataGrid1.Items[intRow].Cells[_UCColumn].Controls[_UCControlPosition];

or from the argument in an individual row.

UCSimple uc = (UCSimple)e.Item.Cells[_UCColumn].Controls[_UCControlPosition];

Note what's going on:

  1. Get the row (via .Items[intRow] or just e.Item)
  2. Then get the column (via .Cells[_UCColumn] )
  3. Then get the control within that cell - a single cell can have multiple controls.
  4. Then cast that as the UserControl type that you need.
  5. Then reference the get/set of any public property.

This will allow you to reference user controls from either outside the grid, or with respect to any row.

Monday, March 7, 2005

Passing client data to the server

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

In my last post, I discussed how to set hidden fields in UserControls to ensure that the control is reusable. This post will expand on that, showing how to use hidden fields as a bridge to pass data between the client and server.

There are several cases where you'd want to have a client-side GUI control, let the user trigger it, do some client side activity first (validation, prompt, etc...), and then send the appropriate data from that control back to the server. For example:

  • MessageBox - Get the value of the clicked button.
  • Image Map - Get the value of the selected region.
  • Dynamically generated links - Get the specific link that was selected.

The basic approach to do this is:

  1. Create a hidden field, runat=server, viewstate enabled (this is default) to store the client side value.
  2. In the CodeBehind of the UserControl, wrap that hidden field in a public property This is especially useful if there's any transformation on it, such as a default value if empty, or encoding/decoding. It also easily lets external objects, such as the hosting page or nested control, get the data because the hidden field should be protected.
  3. Have your client-side object call a JavaScript function, passing in the UserControl ClientId.
  4. In that function, (1) set the hidden field to the value you need, and (2) submit the form.

For example, I created a UserControl with a client-side image map that returns the selected region to the server.

I first added the hidden field "HdnRegionId" (runat=server).

In the code-behind, I added the property:

public string RegionId
{
    get
    {
        return this.HdnRegionId.Value;
    }
}

Still in the code-behind, I also created a public instance variable strClientId to store the User Control's Client Id. This is set every time in the UC page load:

public string strClientId;

private void Page_Load(object sender, System.EventArgs e)
{
    strClientId = this.ClientID;
}

Moving to the Aspx page, I created this JavaScript method in the Html:

function GetRegion(strKey, strClientId) {
    eval('document.forms[0].' + strClientId + '_HdnRegionId').value = strKey;
    document.forms[0].submit();
}

However, I still need a client-side object to call the javascript method:


   
   

For review, here's the flow:

  1. Server:
    1. Page_Load instantiates strClientId variable to hold the UserControl's ClientID.
  2. Client:
    1. Aspx page is rendered, all the <%= strClientId %>"> store the actual UserControl id.
    2. User does some client action, like clicking an image on the image map. This triggers the JavaScript method GetRegion, passing in both the value and ClientId.
    3. Given the UserControl client Id, the JavaScript method dynamically assembles the code needed to set the hidden field on that UserControl. It then submits the form, returning flow to the server.
  3. Server:
    1. Optional logic can be done in the Page_Load.
    2. The hidden field value is persisted in viewstate and is now accessible to other controls.

Sunday, March 6, 2005

Setting hidden fields in a User Control

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

Hidden fields are so powerful in UserControls because they are a bridge between the client and server. JavaScript can set a hidden field value, and then the server can get that value (given that the field is runat=server). Therefore it is very common for UserControls to need to set the values of hidden fields from the client.

While it's easy to hard-code a simple case, truly reusable controls (such as calendars or employee look-ups) are more tricky. It can especially be frustrating when you've created a control, and then a co-worker tells you it's "broken" because they're using it in a legitimate way that you didn't anticipate. There are several cases that any such control should pass:

  1. Can you change the name of an instance of the control.
  2. Can it be nested in another UserControl?
  3. Can multiple instances of the UserControl be on the page at once?
  4. Can it handle the page's form name being changed (it might not always be Form1)?

There are two other issues to at least be aware of:

  1. Does it have external dependencies, like relying on Session State or QueryString values?
  2. Can it run in both IE and NN?

Ultimately the HTML to reference the hidden field from within the same page (i.e. not a popup) is something like:

document.Form1.NestedControl1_MyUserControl_HiddenField.value

We can see that here the Form and UserControl name are both hard-coded. The hidden field is prefixed with the UserControl Id. We can handle the form by referencing it as forms[0] instead of merely the default name like "Form1". Note that an Aspx page should only have 1 form (runat=server) per page, so this is a fair assumption.

We can handle the nested UserControl by making the name as a string and choosing either function below to translate this into actual JavaScript code:

  • use getElementById(string) - given the Id as a string, get the control.
  • use eval(string) - given the script as a string, evaluate it.

For example, we could pass in the variable strUcName (which contains the UC name) into a JavaScript function to reference the following hidden field:

document.getElementById(strUcName + '_HdnOrgId').value =myValue;

The UserControl name, strUcName, can be obtained from the UserControl itself at the server with ClientID.

By dynamically assembling the JavaScript to reference the hidden field, referencing the form as forms[0] instead of a hard-coded name, and passing in the UserControl's ClientID, we fulfill the first four criteria listed above. I will cover the other two criteria in another post.

Thursday, March 3, 2005

Brief Overview of Globalization

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

It is becoming more and more common to globalize a web applications, and fortunately .Net provides the features to easily do this.

Developing Web Applications With MS VB and C# explains of three main strategies (quoted from pg. 680):

ApproachDescriptionBest for
Detect and redirectCreate a separate Web application for each supported culture, and then detect the user's culture and redirect the request to the appropriate application.Application with lots of test content that requires translation and few executable components.
Run-time adjustmentCreate a single Web application that detects the user's culture and adjusts output at run time using format specifies and other tools.Simple applications that present limited amounts of content.
Satellite assembliesCreate a single Web application that stores culture-dependent strings in resource files that are compiled into satellite assemblies. At run time, detect the user's culture and load strings from the appropriate assembly.Applications that generate content at run time or that have large executable components.

I personally have used the resource files. While there are a lot of online tutorials already out there and reference, I have found a couple useful techniques not popularly discussed:

One of the problems with globalization is the Left-To-Right or Right-To-Left direction of text. This can complicate string concatenation. For example the expression: "Hello" + strYourName + " There" assumes a LTR direction that's fine for English, but not Arabic. Therefore I found it useful to create a GlobalUtilities.Concat method that takes an array of variables and the neutral culture (like "en" or "de"), and concatenates those variables in the correct direction.

Another problem is performing complex business logic, such as concatenating variables to create an output message to the user, or formatting DateTimes. This requires knowing the culture so that you can carry out the logic, or even get resources from the resource file. I have found it convenient to pass in the culture as a parameter into the object's constructor. I can then easily test those error-prone globalization methods.

Another tip I'm finding useful is applying FxCop's Globalization rules:

  • Avoid duplicate accelerators
  • Do not hardcode locale specific strings
  • Do not pass literals as localized parameters
  • Set locale for data types
  • Specify CultureInfo
  • Specify IFormatProvider
  • Specify MessageBoxOptions