Monday, December 11, 2006

ASPMENU Source Code is now available !

The underivable AspMenu class that shipped with WSS 3.0 is now unsealed ! The class source code has been released lately to allow developers to extend its functionality. Download the MOSSMenu source code here and you can treat the class as your base class for your own custom menu.

Check Customizing the WSS 3.0/MOSS 2007 Menu Control -- MossMenu source code released for more information.

Inflexibility of WSS 3.0 Customization

Recently I came across the page customization in WSS 3.0 (Creating new custom page that using application.master under _layouts folder), and I found out that the master page is likely not edited for the company branding purpose because the master page is used and shared by all sites in the WSS v3. Any changes upon the application.master would eventually applied to the rest of the sites too.

This would be a PAIN for developers where easier customization feature is not ready for them. The very easy and straightforward solutions to the matter that I can think of are:

1. Clone the application.master and rename it to your own name. Change and apply the custom master page separately.

2. Develop a custom web control that check current SPSite or SPWeb to change master page accordingly.

Perhaps, there are more elegant solutions that can resolve this problem.

Tuesday, December 05, 2006

Installing Custom Group and Actions in WSS/MOSS Features

Another customization in WSS/MOSS! You can install your own custom feature other than out-of-box features that offered WSS/MOSS. You can add new actions or menus in any location in WSS/MOSS like Site Settings, Site Actions, Item Context Menu, and etc in Standard Menu.

By default, there have 5 groups - Look and Feel, Users and Permissions, Gallaries, Site Administration, Site Collection Administration.

To install new custom feature, create a new folder in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES. I name the folder as MyCustomGroupAndAction. Then we need to create an XML called feature.xml and another xml file that contains the feature definition. (featuredef.xml)

Feature.xml has several elements - <Feature>, <ActivationDependencies>, <ElementManifests> and <Properties> but the important ones are :

1. <Feature> (the root element) - Defines feature ID, scope (site, collection, etc), description and title.

2. <ElementManifests> - defines the feature definition, which links to the xml file that contains the definition.

In feature.xml

<?xml version="1.0" encoding="us-ascii"?>
<Feature Id="F863C1CF-897D-49c6-8600-7E6F3FC9D653"
Title="My New Feature"
Description="This is my new feature"
Scope="Web"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="featuredef.xml" />
</ElementManifests>
</Feature>


The ID of the feature is unique GUID. You need to generate new GUID for each new feature being created. To generate the GUID, you can go to Visual Studio -> Tools Menu -> Create GUID or launch the tool at C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\guidgen.exe.



The location attribute of <ElementManifests> specifies the location of feature definiton XML file.

In featuredef.xml

<?xml version="1.0" encoding="us-ascii"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomActionGroup
Id="MyCustomGroup"
Location="Microsoft.SharePoint.SiteSettings"
Title="My Custom Group" />

<CustomAction Id="MyCustomFeature"
GroupId="MyCustomGroup"
Location="Microsoft.SharePoint.SiteSettings"
Title="New Custom Feature"
Sequence="50">
<UrlAction Url="_layouts/layoutdesign.aspx"/>
</CustomAction>
</Elements>


The <CustomActionGroup> specifies the definition of new group to be created. Location attribute specifies where the custom group will reside. In this example, "Microsoft.SharePoint.SiteSettings" indicates that the new group will be in the Site Settings menu of WSS sites. Check Location and Group ID in MSDN for more information. Text in the Title attribute is the name of the group.

<CustomAction> is where the custom feature definition set. The location attribute MUST BE same as the location being specified in the group that the custom feature points to (in GroupID attribute). <UrlAction> element merely specifies URL of the custom application page.

It is about to install the feature ! Go to the command prompt, type

C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN>stsadm -o installfeature -name MyCustomGroupAndActions


The feature has just been installed. However, you need to activate the feature before using it. To activate it, you can type

stsadm -o activatefeature -filename MyFeature/feature.xml -url <server url>


or

go to http://<server name>/_layouts/manageFeatures.aspx, and you will see this



Click "Activate" button to activate the feature. Go to "Site Settings" and you will see this




You have completed installation of new custom group and feature !!

Monday, December 04, 2006

Converting String GUID to System.Guid

Simple matter. I was trying to convert the GUID in string to type of System.Guid and the code below apparently did not work for me.

System.Guid guid = (System.Guid)strGUIDInString;

I was given invalid specified cast error message and I noticed that direct casting wasn't the way. I ended up with

System.Guid guid = new System.Guid(strGUIDInString);


This was the final solution I could think of, so far !

Monday, November 27, 2006

MOSS 2007 and WSS3 Functional Architecture Diagram

Here is the colourful and comprehennsive diagram illustrating the functional architecture of the most latest of Microsoft Office Sharepoint Server 2007 and Windows Sharepoint Services 3.0.

Saturday, November 25, 2006

Release of WSS RTW and MOSS Standard and Enterprise Edition

YOu can download the Release-To-Web version of WSS (Windows SharePoint Services) and Microsoft Office SharePoint Server 2007 Evaluation version at

1. Microsoft Office SharePoint Server 2007 x86 English Evaluation
2. Windows SharePoint Services 3.0

CD Keys available for standard and enterprise edition are

SharePoint Server Standard Trial: XJMKW-8T7PR-76XT6-RTC8G-VVWCQ
SharePoint Server Enterprise Trial: F2JBW-4PDJC-HKXTJ-YCKRP-T2J9D

For more resources about installation, upgrade, versioning, check this link, from Microsoft SharePoint Products and Technologies Team Blog

Thursday, November 23, 2006

Efficient String Concatenation in JS

In .NET, we use StringBuilder if we need to concatenate strings for better string manipulation performance. For instance,

StringBuilder builder = new StringBuilder();
builder.append("This");
builder.append("is");
builder.append("really");
builder.append("good");
builder.append("for");
builder.append("performance");

string str = builder.ToString();

In JS, we can also do the same thing for better memory allocation in string concatenation too.

var builder = new Array();
builder.push("This");
builder.push("is");
builder.push("really");
builder.push("good");
builder.push("for");
builder.push("performance");

var str = builder.join("");


This method will perform faster if the number of string concatenation is huge. THe normal += operator will win, otherwise.

Check Efficient JavaScript for more information on optimizing JS code

Tuesday, November 21, 2006

Invoking Executeable File from ASP.NET Web Services

Below is the code snippet on how to invoke the executable file (exe) from the cmd.exew being executed.

// Execute the Command Prompt
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe");

// Indicating the input read from the process's standard input
psi.RedirectStandardInput = true;
psi.UseShellExecute = false;

// Do not show the GUI of the running app
psi.CreateNoWindow = true;

Process process = null;
try
{
// Execute the cmd.exe
process = Process.Start(psi);

StreamWriter writer = process.StandardInput;

// Write the command to the command prompt
writer.WriteLine("notepad");

}
catch (Exception ex)
{
// do something here
}
finally
{
if (process != null)
{
process.Close();
}
}


The code will simply run the notepad from the cmd.exe. You can just call "notepad" from at line the of ProcessStartInfo psi = new ProcessStartInfo("notepad");, but I am showing how are you going to write the command to the cmd using the StandardInput of Process object.

Similarly, you can call batch file from the cmd to execute command in the batch file too, or store those static command in the resource files (resx) inside the app_GlobalResources folder and get from the key by

Resources.<Resource file name>.<key name>

MSDN Magazine - HTML Help Downloads

If you want to read MSDN Magazine contents wherever you are, you can download the dozens of MSDN Magazine in portable chm format at http://msdn.microsoft.com/msdnmag/htmlhelp.aspx

Use of ResolveClientUrl() method in getting browser-acceptable relative URL

In .NET, we always use tilde (~) to refer to root virtual directory of the web application. For instance,

<asp:Image runat="server" ImageUrl="~/images/mypic.gif" />

However, in order to generate a URL that can be used by client-side browser, the URL is actually resolved in the AddAttributesToRender() of the Image server control.

writer.AddAttribute(HtmlTextWriterAttribute.Src, ResolveUrl(ImageUrl));

That is the reason why you can use "~" in the ImageUrl property. But I afraid this might be the case if you do the same thing upon the normal HTML elements or HtmlGenericControl, such as :

<img src="~/images/mypic.gif" alt="" />

because the browser does not recognise what the "~" symbol stands for. In order to workaround with that, this is where the ResolveClientUrl() method comes into place.

<img src='<%= ResolveClientUrl("~/images/mypic.gif") %>' />

Apart from using it in HTML, it can also be used in code-behind that involves in getting the relative path for the URL. For instance, ResolveClientUrl() method is handy when we are trying to register the javascript reference in code-behind,

this.Page.ClientScript.RegisterClientScriptInclude(this.GetType(),"MyScript", this.ResolveClientUrl("~/images/myscript.js"));

Not only that, you will always need this method in your custom server control development.

Thursday, November 02, 2006

Debugging JS in VS 2005 using Script Explorer

Breakpoint is one of the useful features available in Visual Studio 2003/2005 to allow developers to trace the current value of variable at the location where the debugger is currently running at. Nevertheless, you can set any breakpoint in the code-behind of the aspx page, but not in declaractive page. No particular client-side javascript function codes can simply be set as breakpoint in Visual Studio.

I rarely debug the client-side JS codes, or I can say NEVER! I have tried to debug it using Script Explorer today and it impressed me. To debug the client-side JavaScript functions, you can use the only-visible-in-debugging-environment Script Explorer in Visual Studio 2003/2005. There are few steps need to be followed:

1. Enable Client-side Script Debugging

IE -> Tools Menu -> Options Menu -> Advanced Tab -> Untick " Disable script debugging check box" in Browsing category.



2. In VS environment, write a simple JS function in external functions.js

function MyLoad(name)
{
var message = "Welcome, " + name;
alert(message);
}

Then, invoke the function in body's load() event in ASPX page.

window.onload = MyLoad("Alvin");

3. Press F5 to debug the page. In debug mode, go to Debug Menu->Windows-> Script Explorer (this option only appears in debug mode). The window of Script Explorer will be shown.



4. Once you debugging the page, you will see list of JS files/resources shown in Script Explorer in tree view.



Double click the "functions.js" and set the breakpoint at particular line. The debugger will stop at that line when it passing through it.




Additionals
If your javascript functions are in the aspx page, you can add breakpoint by

Debug Menu -> "Add Breakpoint" -> "Break At Function" -> type your method name there and choose right language.




Read more in MSDN
1. How to: Debug a Client-Side Script from Microsoft Internet Explorer
2. How to: Enable Client-Side Script Debugging
3. How to: Set a Function Breakpoint


I need a break....

Tuesday, October 31, 2006

Accessing GridView's DataControlFieldCell Programmatically

How would you access the auto-generated control in the HyperLinkField (HyperLink control) and ButtonField (LinkButton or Button control) in RowDataBound event ? You will find out that FindControl() method would no longer be working since there is no concrete ID is assigned to the control, and you are not intelligent enough to know what ID will be assigned automatically by the compiler. There are two workarounds, in which the second one is new in ASP.NET 2.0.

Assuming that the HyperLinkField is at 4th column.

First Workaround

protected void GridView1_RowDataBound(object sender,
GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HyperLink hl = e.Row.Cells[3].Controls[0] as HyperLink;
hl.Text = "Changing Text here";
}
}

This workaround is pretty straightward. Cells[3] refers to 4th column (index starting from 0) ; Controls[0] means the first control in that column, which is HyperLink control.

The first workaround is apparently classic way that we used in DataGrid control. But here is the another workaround, which works in different way !


Second Workaround

protected void GridView1_RowDataBound(object sender,
GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataControlFieldCell dField = e.Row.Cells[3] as
DataControlFieldCell;
HyperLinkField hlf = dField.ContainingField as HyperLinkField;
hlf.Text = "Changing Text here";
hlf.DataNavigateUrlFormatString = "nextpage.aspx?id={0}";
}
}

As you can see, I am accessing the HyperLinkField itself, and I am able to assign the DataNavigateUrlFormatString property in the RowDataBound event too. Of course, if you would like to access the control in that field, it can be done by

HyperLink hl = dField.Controls[0] as HyperLink;



Hope this helps...

SQL Server Connection Timeout !

Frustrated ! I was given an error message of "Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding." when I was trying to connect to SQL Server 2000 with VS 2005. The connection string was correct and I tried several connection strings :

1. Server=ALVIN;Initial Catalog=pubs;UID=sa;
2. Server=ALVIN;uid=sa; database=pubs";
3. packet size=4096;user id=sa;data source=ALVIN;persist security info=False;database=pubs

(I used sa account for simplication, don't use it in your production site)

But none of them worked for me. I tried it in VS 2003 and unbelievably it worked! (Don't say there is any discrimination) What the heck.. Without any patience left, I saught the answer from Google and I got this link at http://msdn2.microsoft.com/en-gb/library/ms190181.aspx. It explains several causes of the problem, but one of them seemingly is the cause of my problem, which is :

"Database Engine is not listening on port 1433 because it has been changed, or because it is not the default instance, and the SQL Server Browser service is not running."

I tried to go to Client Network Utility and Server Network Utility to change my port number of TCP/IP to 1433 AND reorder it to be the first before the "Named Pipes".




After restarting the SQL Server, it eventually went fine for me. :)

Monday, October 30, 2006

New Features of my Blog

I have implemented my blogger with new Blogger Beta, and it is pretty amazing. The template in HTML is different from the classic template style. There are some new features added in this blog, such as post count in the right-hand-side sidebar, new widgets, new navigation bar. Other features such as blogs searching will be added soon. Although it is not completely nice, it nears to perfection.

For those users who use this blogger, you can visit http://beta.blogger.com/ for the version switching, or visit these sites for helps.

1. http://betabloggerfordummies.blogspot.com/index.html
2. http://groups.google.com/group/blogger-help
3. http://betabloggerfordummies.blogspot.com/


Still figuring out its features and specialities....

Saturday, October 28, 2006

Changes on my ValidTextBox Server Control

I have made some changes to my ValidTextBox server control. The changes are:

1. Supports to display error image instead of text error message when the control is invalid.
2. Supports Tooltips for error image.
3. Fixed bug of email address expression, which allows symbols.

Screenshots:






Please check http://mind.com.my/forums/1018/ShowThread.aspx#1018 for more details...

Sample Programming Interview Questions

I have found there are a set of interview books, relating to Programming - ".NET Interview Questions", "Java Interview Questions", "SQL Server Interview Questions" and so on. These questions are commonly asked by companies during their interview/recruitment process. You may take a look on sample questions at http://www.questpond.com/ , which has a lot of sample questions to be downloaded in zip format.

Some questions are tough!

[ASP.NET] Building Tag Cloud in ASP.NET

What is Tag Cloud. A tag cloud is a way to display a weighted list such that the weight of each item is reflected by the size of the item's text. Tag clouds provide a quick way for one to eyeball a list and ascertain what items are more prevalent.

Scott Mitchell has just written an article of Creating a Tag Cloud in ASP.NET. That is very cool especially you are dealing with blogging or tagging-related sites. I have tested it, and that's nothing but COOL !

Wednesday, October 25, 2006

[ASP.NET] Basic of Custom Server Control Development Part II - ParseChildren(), PersistChildren() and PersistenceMode()

Let us boils down to the three attributes that important in implementing simple properties and subproperties in the custom control development - ParseChildrenAttribute, PersistChildrenAttribute and PersistenceModeAttribute.

Default and Inner Property Persistence
Default persistence is in constrast to Inner persistence, but they are identically same for its functionality. In our control development, we may have complex properties (class). To persist them, we can use hyphenated syntax (Default Property Persistence) or nesting them within your control tags (Inner Property Persistence). Example of Inner Property Persistence,

<asp:GridView ID="GridView1" runat="server">
<HeaderStyle BorderWidth="12" />
</asp:GridView>

In the example given, the BorderWidth is the subproperties of the HeaderStyle property of GridView. To enable this inner property persistence, you need to set the ParseChildren(true) and PersistChildren(false) in your control class.

[ParseChildren(true)]
[PersistChildren(false)]
public class MyWebControl : WebControl
{
...
}


1. ParseChildrenAttribute
This attribute tells the parser to parse the parse the contents within the control tag as properties but not child controls.

To enable the inner default property persistence, you have to specify the inner default property to the second parameter of ParseChildrenAttribute.

[ParseChildren(true, "<DefaultPropertyName>")]
public class MyControl : WebControl
{
...
}


2. PersistChildrenAttribute
On the other hand, this attribute tells the designer whether the child controls of the server control should be persisted as inner child controls. Setting to false indicates inner content corresponds to properties but not to child controls.

* Therefore, the ParseChildrenAttribute and the PersistChildrenAttribute attributes use opposing conventions for the semantics of their argument. Check more difference of these two attributes at Justin Lovell's Blog - The ParseChildren and PersistChildren Attributes


3. PersistenceModeAttribute
This attribute specifies how the property of server control is persisted declaractively in ASP.NET pages. It has 3 enumerations :

EncodedInnerDefaultProperty - Specifies that the property persists as the only inner text of the ASP.NET server control. The property value is HTML encoded. Only a string can be given this designation.

InnerDefaultProperty - Specifies that the property persists in the ASP.NET server control as inner text. Also indicates that this property is defined as the element's default property. Only one property can be designated the default property.

InnerProperty - Specifies that the property persists in the ASP.NET server control as a nested tag. This is commonly used for complex objects, those that have persistable properties of their own.

Picked from http://msdn2.microsoft.com/en-us/library/system.web.ui.persistencemode.aspx

[PersistenceMode(PersistenceMode.InnerProperty)]
public virtual TableItemStyle HeaderStyle { ... }

This indicates that the designer to persist the property as inner property. By default, it is persisted by using hyphenated syntax in control tag. To persist inner default property, you need to have

[ParseChildren(true, "<DefaultPropertyName>")]
public class MyControl : WebControl
{
...
}

and

[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public virtual ListItemCollection Items { ... }



These three attributes are confusing, but are not undifferentiable.

Monday, October 23, 2006

My ValidTextBox is OUT !

After spending 3 days of custom control development, I have successfully developed the beta-period ValidTextBox server control. It basically integrates validator controls (RegularExpressionValidator and RequiredFieldValidator) and normal textbox control to reduce the developers' time and efforts. Here are some screenshots of the ValidTextBox server control.






Check more about the ValidTextBox server control at MIND Forum here

Thursday, October 19, 2006

[ASP.NET 2.0] Post-Cache Substitution

Post-Cache Substitution, a new feature that is not so eye-catching compared to the other new features introduced in ASP.NET 2.0 like Master Pages, Personalization, DataSource Control and etc. Basically, Post-Cache Substitution allows developers dynamically update the contents of output-cached portions (eg. header, footer). When a header user control (header.ascx) is given the following directive

<%@ OutputCache Duration=3600 VaryByParam=none %>

It tells the page to be partially cached for an hour (3600 seconds). If there is current date and time showing in the header section, it is unlikely that the time will be updated for every second since it is cached for an hour long.

There are common 2 ways of implementation of Post-Cache Substitution solves this problem for you - Use of Substitution Control and Substitution API.


1. Substitution Control
This control tells the page not to cache the section for its dynamic contents. Every contents in the control would not be cached.

1. To use this control, drag the Substitution Control from VS 2005's ToolBox and drop it onto your WebForm.

2. The control has a MethodName property, which is assigned to a static method. In the code-behind, define a static method that accepting a page context as parameter.

public static string GetCurrentDateTime(HttpContext context)
{
return DateTime.Now.ToLongTimeString ();
}

3. Back to Design View. In the control's property window, assign GetCurrentDateTime to MethodName property. This ascertains that subsequent requests to the page call the method again to generate dynamic content.



2. Substitution API
This implementation uses the in-lline code, by calling the Response.WriteSubstitution() method that accepting name of method as parameter. Thus, in your ASPX HTML view, add this

<% Response.WriteSubstitution(new HttpResponseSubstitutionCallback(GetCurrentTime)); %>

It would change client-side cacheability to server cacheability, which the dynamic contents are not cached on clients.

Wednesday, October 18, 2006

[ASP.NET] Specifying DefaultButton in MasterPage

In normal ASP.NET 2.0, we can easily assign the DefaultButton property in the

<form runat="server" DefaultButton="btnSearch">


But what if we would like to make two different buttons from two pages that inheriting the MasterPage to be DefaultButton? It might not be working using the way above because MasterPage because it is publicly shared by its content pages. You, however, have to programmatically assign the DefaultButton in each of the content page.

In content Page,

this.Form.DefaultButton = "MyDefaultButton";

This is not the way of assigning the ID of button to DefaultButton property. Use this way,

this.Form.DefaultButton = MyDefaultButton.UniqueID



Cheeers

[ASP.NET] Redirecting Page after Emiting JS in Code-behind

To emit the JavaScript in code-behind in ASP.NET, we use RegisterStartupScript() or RegisterClientScriptBlock() method. But when we would like to redirect user to a specified page after the JS pop-up, we probably would use this (written in VS.NET 2003, use ClientManager for VS 2005)

string strScriptName = "AlertScript";
string strMessage = "There is an error";

string strScript += strMessage + "')<"
strScript += "/"
strScript += "script>"

if(!Page.IsStartupScriptRegistered(strScriptName))
objPage.RegisterStartupScript(strScriptName, strScript)

Response.Redirect("error.aspx");

If you run the code, you will notice that you will be redirected to the error.aspx WITHOUT being prompted the error message dialog box of "This is an error" because Response.Redirect() forces the browser not to render the HTML (sending a header to client to cause client to redirect to specified URL).

To overcome this problem, replace the Response.Redirect("error.aspx"); with

Response.AppendHeader("refresh","0;Url='error.aspx'");

Instead of redirecting the page, the browser would simply refresh the page within 0 second and "redirecting" to the error.aspx, as specified in the Url parameter.

Tuesday, October 17, 2006

[ASP.NET] Basic of Custom Server Control Development Part I

Developing custom server control in ASP.NET is fun! You are flexible to develop it either inheriting the existing ASP.NET server controls like Button, HyperLink, BoundField or create you own control by inheriting Control/WebControl classes from System.Web.UI namespace. There are dozens of cool and fabulous custom server controls developed by third-parties like Metabuilder or ExcentricWorld. I like to develop the custom server control because the tailored controls can specifically accomplish some jobs that normal shipped-in ASP.NET server controls can't. It serves the purpose on your needs.

There are basic concepts/rules in custom server control development in ASP.NET like :

1. Derive your control class from System.Web.UI.Control if your control is dealing with non-visual elements or merely render as HTML output. For instance, META tag. Otherwise, your class should inherit from System.Web.UI.WebControls class if your control is built to have visual appearance to the client.

2. Do not override the Render() method of in your control if it is inheriting from System.Web.UI.WebControls class because the method is responsible in rendering the outer tag and control styling to the output stream. Override its RenderContent() method instead!

protected override void RenderContent(HtmlTextWriter writer)
{
writer.Write("Test");
}


3. When your control inherting the System.Web.UI.WebControls, its outer tag is <span> by default. You can get rid of this and render any outer tags you want by overriding its HtmlTextWriterTag.TagKey or TagName (non-standard HTML tags).

protected override HtmlTextWriterTag TagKey
{
get { return HtmlTextWriterTag.Input; }
}

or

public Button() : base(HtmlTextWriterTag.Input)
{ }



4. Check whether the control is in the <form runat="server"> by

if (Page != null)
Page.VerifyRenderingInServerForm(this);


in either AddAttributesToRender() or Render()/RenderContent() method.


5. By default, the tag prefix of your custom server control would be auto-generated. For instance, when you drag and drop your control, the tag would be something like

<cc1:CustomMeta ID="CustomMetaTag1" runat="server" />

As you see, the "cc1" gives no meaning. You can add your own tag prefix by adding TagPrefixAttribute in the assemblyinfo.cs file.

using System.Web.UI;
[assembly:TagPrefix("SimpleControl", "Alvin")]

Now, it would become like

<Alvin:CustomMeta ID="CustomMetaTag1" runat="server" />


6. Take note of rendering methods of System.Web.UI.Control class

public void RenderControl(HtmlTextWriter writer) {
if (Visible) {
Render(writer);
}
}

protected virtual void Render(HtmlTextWriter writer) {
RenderChildren(writer);
}

protected virtual void RenderChildren(HtmlTextWriter writer) {
foreach (Control c in Controls) {
c.RenderControl(writer);
}
}


It is wise to call the base class's methods if you intend to override the method like RenderChildren method to ensure its child controls are recursively rendered.

protected override void RenderChildren(HtmlTextWriter writer)
{
base.RenderChildren(writer);

// do your stuff
}



7. To restrict the control to have NO CHILD CONTROLS, you need to return EmptyControlCollection(this) to the overidden CreateControlCollection() method.

protected override ControlCollection CreateControlCollection() {
return new EmptyControlCollection(this);
}


By doing that, no child controls/tags are allowed.

// Allow
<Alvin:CustomMeta ID="CustomMetaTag1" runat="server" />

// Not allow !
<Alvin:CustomMeta ID="CustomMetaTag1" runat="server"></Alvin:CustomMeta>

Saturday, October 14, 2006

Go for Google or Microsoft?

Cliff, who has been offered by Google and Microsoft is in trouble! He is in hestitation whether to work for Google or Microsoft, He posted a dicussion topic of Microsoft or Google? to ask Slashdot-ers about both companies' working environments and their thought about the companies. It is interesting to see the commenters posted their opinions about Google and Microsoft's working environment, working hours, management styles, pressure, corporate culture, benefits and so on, respectively.

Google or Microsoft? Hard to choose even to me.

Tips and Tricks on cloning data-bound controls

Here are some tips and tricks on cloning the Data-Bound controls.

Cloning DataGrid/GridView
It is common mistake when you would like to copy the assigned DataGrid's DataSource to another DataGrid's datasource like

DataGrid2.DataSource = (DataSet)DataGrid1.DataSource;

You would simply get the NullReference exception. It seems work but it doesn't. A better way is store the needed DataSet to Cache or Session and reuse it for subsequent data binding.

Object objDS = Cache["MyDS"];
if(objDS != null)
{
DataSet ds = (DataSet)objDS;
DataGrid1.DataSource = ds;
DataGrid2.DataSource = ds;
}
else
{
DataSet ds = new DataSet();
// open conn, fill the DS;
DataGrid1.DataSource = ds;
DataGrid2.DataSource = ds;

Cache["MyDS"] = ds;
}

THERE is another way cloning the content of Grid by rendering its HTML contents to HtmlTextWriter. Try to put this code in the Button's Click event.

StringBuilder strBuilder = new StringBuilder();
StringWriter writer = new StringWriter();

HtmlTextWriter textWriter = new HtmlTextWriter(writer);
strBuilder = writer.GetStringBuilder();
dgrdAuthors.RenderControl(textWriter);

string strContent = strBuilder.ToString();
Response.Write(strContent);


Once you click the button, the cloned Grid appears. This code is particularly useful especially you would like to send the content of Grid over email.


.....
objMail.Body = strContent
objMail.BodyFormat = MailFormat.Html
....



Cloning DropDownList/CheckBoxes/RadioButtonList
How do you make two DropDownLists, which bound to a datasource to have identical items? The very basic method is use of DataSet like

DropDownList1.DataSource = ds;
DropDownList1.DataTextField = "MyText";
DropDownList1.DataValueField = "MyValue";
DropDownList1.DataBind();

DropDownList2.DataSource = ds;
DropDownList2.DataTextField = "MyText";
DropDownList2.DataValueField = "MyValue";
DropDownList2.DataBind();

It works fine. No complain. What if you use forward-only IDataReader for performance wise? You may need to have two IDataReaders for each DDL's data-binding. Here is another trick where only one DataReader is needed.

reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
DropDownList1.DataSource = reader;
DropDownList1.DataTextField = "MyText";
DropDownList1.DataValueField = "MyValue";
DropDownList1.DataBind();
reader.Close();

// I am cloning the ListItemCollections of DDL1 to DDL2
DropDownList2.DataSource = DropDownList1.Items;
DropDownList2.DataTextField = "Text";
DropDownList2.DataValueField = "Value";
DropDownList2.DataBind();



Much simpler, much faster, much neat !

Friday, October 13, 2006

Browser DOM Supports and Compatibility Issues

I occasionally get some earful from other people how hard to develop an AJAX application. Well, it isn't that hard if you use on-ready AJAX development tools such as Atlas. Nevertheless, you may be cracking your head on writing remote scripting from ground up because there are few issues need to be taken care.

Other than the checking the types of the browser, you also need to concern about the DOM supports the particular browser can support. For instance, the innerText property of < span > is not supported in FireFox, you have to use textContent property or universal supported innerHTML property. Here are the listing of sites that you may need to check the DOM that the layout engines in each browser can support.


Links
1. Web browser HTML support
http://www.webdevout.net/browser_support_html.php

2. Web browser DOM support
http://www.webdevout.net/browser_support_dom.php

3. DOM Support in Mozilla
http://www.mozilla.org/docs/dom/mozilla/

4. Comparison of layout engines (DOM)
http://en.wikipedia.org/wiki/Comparison_of_layout_engines_%28DOM%29

5. Common Differences Among IE and Mozilla
http://www.htmlgoodies.com/primers/jsp/article.php/3624446

[ASP.NET] Serializing/Deserializing Passing Objects Across Pages with LosFormatter

On our ordinary basis, we pass the values or object values across two pages using Session, Form Posting, PreviousPage reference in ASP.NET. But however, we could not able to append the object to the query string (unless you use the Session state instead). There is another alternative way - passing the serialized the object values into string presentation in query string.

How ?? First of all, are you familiar with this ?


< input type="hidden" name="__VIEWSTATE" value="dDwxMzIwMTI1MjYwO3Q8O2w8aTwxPjs+O2w8dDw7bDx
pPDE+Oz47bDx0PHA8cDxsPE5hdmlnYXRlVXJsOz47b
DxXZWJmb3JtMi5hc3B4P3ZhbHVlPWJEeDBhR2x6T3o
0PTs+Pjs+Ozs+Oz4+Oz4+Oz5RXn3JAFz8V0ozE1lmu
5B1K2D7xw==" / >


If you do, that's good. It is ViewState, the hidden field that stores control state, which the state values (eg. object values, primitive type values) are serialized and deserialized into base-64 string using LosFormatter. Similarly, this approach can be used to serialize the object and pass it to the next page in query string.

The following example shows you how to pass the serialized ArrayList to the next page using LosFormatter.

Code
Firstpage.aspx

System.IO;
System.Collections;

private void Page_Load(Object sender, EventArgs e)
{
ArrayList ary = new ArrayList();
ary.Add("this");

System.Web.UI.LosFormatter formatter = new System.Web.UI.LosFormatter();
StringWriter writer = new StringWriter();

formatter.Serialize(writer,ary);
HyperLink1.NavigateUrl = "secondpage.aspx?value=" + writer.ToString();
}


Check the URL in the HyperLink control in Firstpage.aspx, it would be something like

http://localhost/WebTest/secondpage.aspx?value=bDx0aGlzOz4=


The ArrayList object has just been serialized ! How to deserialize the object back?


Secondpage.aspx

System.IO;
System.Collections;

private void Page_Load(Object sender, EventArgs e)
{
System.Web.UI.LosFormatter formatter = new System.Web.UI.LosFormatter();
ArrayList aryL = (ArrayList)formatter.Deserialize(Request.QueryString["value"]);

Response.Write(aryL[0]);
}


* Be noted, you need to explicitly specify the System.Web.UI.LosFormatter in the object instantiation. You will get the undefined Serialize()/Deserialize() method, otherwise. Watch out the number of characters supported in the URL. Not all objects are suitable to be serialized, only relatively small-size objects are appropriate to do so.


The LosFormatter class is extremely useful especially you override the SaveViewState() or LoadViewState() of the Page class/ Control, you need this class to do the serialization or deserialization of control states.

Thursday, October 12, 2006

[.NET 2.0] Foreach-ing Arrays with Iterator & Generics

Prior to the .NET 2.0, we have to use for statement to loop each of the element in the array. C# 2.0 offers you another one - Iterator, a familar word that in the Design Pattern, a method that can be used to enumerate through collection of values such as array and return each of the element in turn. For instance,

Code

string[] aryNames = {"Alvin","Westley","Howard"};

foreach(string str in IterateMe(aryNames))
Response.Write(str + " ");


private IEnumerable IterateMe(string[] str)
{
int iLength = str.Length;
for(int index=0;index < iLength;index++)
yield return str[index];
}
Output :
Alvin Westley Howard


Your Iterator method has to return either IEnumerable or IEnumerator type to the caller function, which in turn contains the element value of current iteration. Make it more usable with generic,

Code:

string[] aryNames = {"Alvin","Westley","Howard"};
int[] iValues = {1,2,15,4,6,9};

foreach(string str in IterateMe< string >(aryNames,true))
Response.Write(str + " ");

foreach(int value in IterateMe< int >(iValues,true))
Response.Write(value + " ");


private IEnumerable IterateMe< T >(T[] str, bool sorting)
{
if(sorting && !typeof(T).Name.Equals("Object"))
Array.Sort(str);

int iLength = str.Length;
for(int index=0;index < iLength;index++)
yield return str[index];
}

Output:
Alvin Howard Westley
1 2 3 6 9 15

Wednesday, October 11, 2006

My Revamped Blog !

I have just revamped my blog by changing the page template to my favourite color and font family + size combinations.

Testing..


Response.Write("Welcome to my newly-revamped blog!");

Tuesday, October 10, 2006

[AJAX] IE 7 getting Native XMLHTTPRequest object

Programming AJAX Web application would be in trouble when users turning off the ActiveX support in IE. The sentence of

var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");

would not be working. But luckily, there is native XMLHTTPRequest object like what non-IE browsers do.

var xmlHttp = new XMLHttpRequest();


No ActiveX object is needed, so far. Here is the code needs to be added to check the support of native XMLHTTPRequest object

if (window.XMLHttpRequest)
{
// If IE7, Mozilla, Safari, etc: Use native object
var xmlHttp = new XMLHttpRequest();
}
else
{
if (window.ActiveXObject){
// use the ActiveX control for IE5.x and IE6
var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
}

[ASP.NET] ASP.NET's FREE Components List

Jason'd compiled a long but yet comprehensive list of free components of ASP.NET, ranging from data-bound controls, graphing controls, navigation controls to templating and reporting controls..

Check Free Components for ASP.NET for more detailed info. (Check user comments for some other useful controls too)


Hunting for more !

Monday, October 09, 2006

[My Project] LVUtilities Lib v1.109 Updates : XmlHelper class

I have just done the following changes in this LVUtilities Lib v1.109

New XMLHelper class
1. ReadValuesByXPath()
2. ReadElementValues()
3. ReadElementList()
4. ReadSingleElementValue()
5. ReadAttributeValue()

6. UpdateValuesByXPath()
7. UpdateSingleValueByXPath()

8. InsertAttributeByXPath()
9. InsertElementByXPath()

10.RemoveAttributeByXPath()
11.RemoveElementByXPath()


Changelog
1. Overloaded Generic IsDBNullValue<>() method
2. Improve the string manipulation performance in string replacement



Download the library + examples here

Saturday, October 07, 2006

Updates : SecurityHelper and ValidationHelper classes

I have enhanced the SecurityHelper and the ValidationHelper classes to support :

1. ValidationHelper class
The IsValidStateNames(), IsValidPhoneNO() , IsValidHPNO(), IsValidICNO(), IsValidPostalCode() are no longer limited to Malaysia context. For instance, to validate the phone number of US,

if(ValidationHelper.IsValidPhoneNO(strInput,"(999)999-9999"))
// true or false

in which the "(999)999-9999" is the input mask pattern that used to validate the US phone number format.


2. SecurityHelper class
The CompareValueToHash() method can now accept both string parameters of user input and hashed string. For instance,

string strPassword = SecurityHelper.GenerateHashInString("abc");
if(SecurityHelper.CompareValueToHash("abc",strPassword))
// true or false



Download Examples and Library here

Friday, October 06, 2006

[.NET] Debugger, dont STEP INTO my method !

Had you experienced whenever you debug your application using the step-into feature (F11), the debugger will go through the implementation of the methods being called, which you might not want it to. How do you "tell" the debugger to skip the method and move on to next statement? Here is the answer.

using System.Diagnosis;

[DebuggerStepThrough]
public void MyMethod()
{
....
}


Be noted, the [DebuggerStepThrough] attribute can be used in the get/set of property, too.


public string MyProperty
{
[DebuggerStepThrough]
get { }
}



MyMethod : "Thanks for skipping over me, Debugger !"

Thursday, October 05, 2006

[AJAX] AJAX Tutorials !

Planning to develop the AJAX app on the fly? Here are AJAX tutorials links that you can't afford to lose....

1. 130+ AJAX Tutorials [AjaxMatters]
2. Top 126 AJAX Tutorials
3. 60 Tutorials of AJAX [Max Kiesler]

[My Project] My Helper library is OUT !

I have been working on creating a simple library which consists of 5 major helper classes in this version as following:

1. ValidationHelper class

a. IsValidFileName()
b. IsValidNumeric()
c. IsDBNullValue()
d. IsValidDateFormat()
e. IsAlpahbet()
f. IsAlphaNumeric()
g. IsValidUserName()
h. IsValidName()
i. IsValidStateName() // Malaysia Context only
j. IsValidPhoneNo() // Malaysia Context only
k. IsValidHPNo() // Malaysia Context only
l. IsValidICNo() // Malaysia Context only
m. IsValidPostalCode() // Malaysia Context only
n. IsValidEmail()



2. SecurityHelper Class

a. GenerateHash() // MD5, SHA1, SHA256, SHA384, SHA512
b. GenerateHashInString()
c. CompareValueToHash()
d. TDESEncrypt() and TDESDecrypt() // Triple DES


3. MailHelper Class

a. SendMessage()


4. HttpPostHelper Class

a. SendRequest()


5. ClientScriptHelper Class (ASP.NET only)

a. ShowMessage()



* I am working on the XmlHelper and FileHelper classes in coming release.


Download
Download Library DLL and Examples : http://www.megaupload.com/?d=1G96G4U9

Wednesday, October 04, 2006

[ADO.NET] 3 ways closing DataReader & Connection..

These are the 3 common ways I use to close the XDataReader and DB Connection...

1. Use CommandBehavior.CloseConnection

SqlDataReader reader = null;

try
{
   reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);

   // do stuff
}
catch(Exception ex)
{
   // logging error
}
finally
{
   // conn will be closed when reader is closed
   reader.Close();
}


2. Explicitly Close DataReader and Connection

SqlDataReader reader = null;

try
{
   reader = cmd.ExecuteReader();

   // do stuff
}
catch(Exception ex)
{
   // logging error
}
finally
{
   // conn will be closed when reader is closed
   reader.Close();
   conn.Close();
}


3. Use Using Statement

using(SqlConnection con = new SqlConnection(<connection string>))
{
   using(SqlCommand cmd = new SqlCommand(<query>,conn))
   {
      using(SqlDataReader reader = cmd.ExecuteReader())
      {
         // do stuff
      }
   }
}


The first one is my preference, what about you?

[.NET 2.0] New Methods / Operator in .NET 2.0

I summarize some of the useful new methods and operator introduced in .NET 2.0 here...

1. String.Contains()

Old way in .NET v1.X
string str = "Today is monday";

if(str.IndexOf("is")!= -1)
// do stuff


New way in .NET 2.0
string str = "Today is monday";
if(str.Contains("is"))
// do stuff


2. String.StartsWith()

Old way
string str = "Alvin Chooi";
if(str.IndexOf("Al")==0)
// do stuff


New way
string str = "Alvin Chooi";
if(str.StartsWith("Al"))
// do stuff


3. String.EndsWith()

Old way
string str = "Alvin Chooi";
if(str.IndexOf("Al")== str.Length-2)
// do stuff


New way
string str = "Alvin Chooi";
if(str.EndsWith("Al"))
// do stuff


4. String.IsNullOrEmpty()

Old way
string str = "Alvin Chooi";
if((str!=null) && (str.Length > 0))
// do stuff


New way
string str = "Alvin Chooi";
if(!String.IsNullOrEmpty(str))
// do stuff


5. TryParse()

Old way
int iValue;
try
{
iValue = Int32.Parse("2x");

return true;
}
catch(Exception ex)
{
return false;
}


New way
int iValue
bool isValid = Int32.TryParse("2x",out iValue);


6. Non-null operator (??)

Old Way
string str = null;

if(str!=null)
Response.Write(str);
else
Response.Write("It is null");


New way
Response.Write(str?? "It is null");


7. Eval() & Bind() in ASP.NET 2.0

Old way
<%# DataBinder.Eval(Container.DataItem,"MyField") %>

New way
<%# Eval("MyField") %> // one-way binding
<%# Bind("MyField") %> // two-way binding



Codes become lesser and lesser... (But why our work will never be lessen?, ha)

Tuesday, October 03, 2006

[ASP.NET] RequiredFieldValidator + OnClientClick issue

OnClientClick property was introduced in ASP.NET 2.0 to eliminate the need of developers to add the client-side "onclick" to a control programmatically. For instance,

JS script

function ConfirmMe()
{
   return confirm("Do you want to proceed?");
}


ASPX

<asp:TextBox id="txtName" runat="server"/>
<asp:Button id="btnSubmit" OnClientClick="return ConfirmMe()" Text="Submit" runat="server"/>


Well, that is pretty straightforward. BUT, it goes weird when you have a validator control (eg. RequiredFieldValidator) that is used to validate the "txtName" textbox server control. For instance,


<asp:TextBox id="txtName" runat="server"/>

<asp:RequiredFieldValidator id="rq1" ControlToValidate="txtName" ErrorMessage="Name cannot be blank" Display="Dynamic" runat="server"/>

<asp:Button id="btnSubmit" OnClientClick="return ConfirmMe()" Text="Submit" runat="server"/>


Whenever you press the button with no textbox value, the client-side confirmation dialog will be invoked first before the validator message is able to show up. This isn't what we expected it to behave. I tried several ways to overcome this problem, including using CLIENT CALLBACK, disabling the CauseValidation, but it failed. Finally, I was able to find a solution by adding JUST ONE line in the JS script.

function ConfirmMe()
{
   if(Page_ClientValidate())
      return confirm('Do you want to proceed?');

   return false;
}



Another discovery today !

Validator for CheckBox/CheckBoxList

By default, there is no validator server control available to validate the validity of checkbox in ASP.NET. On the basis practice, I have to use CustomValidator control or using pure client-side JS or the postback checking on server-side. But to ease the job, you can try Custom Checkbox Validator, created by Microsoft MVP, Scott Mitchell.

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



IsValid? True !

About SqlDataSource control

I've been running a problem of losing the selected items in a listbox, which is bound to the SqlDataSource control on every postback. The code is :


<asp:ListBox ID="lstBox" runat="server" CssClass="listbox-flat" DataSourceID="objSQL" DataTextField="userFullName" DataValueField="RID" SelectionMode="Multiple" Width="335px" Enabled="False"></asp:ListBox>

<asp:SqlDataSource ID="objSQL" runat="server" ConnectionString="<%$ ConnectionStrings:dbConnectionString %>" SelectCommand="SELECT * FROM Table1"> </asp:SqlDataSource>


As far as I remember, the selections of ListBox SHOULD be retained on the postback since the ViewState of the control will be saved in the SaveViewState event after the binding, but the thing goes weird unexpectedly :(. Since the automatic databinding performed by the SqlDataSource takes place in the Page_PreRender event (You can check it by using Page Tracing). Here is the screenshot:


* The ListBox is bound to the DataSource control.

Eventually, I used another way round by programmatically binding the ListBox in that PreRender event with IsPostBack checking. (No choice, this is the best way I could think of, I will find out the cause of the problem later)

Steps
1. Set the DataSourceID property of ListBox to empty (So that it would not be bound to the SqlDataSource until runtime)

2. Obtain the SqlDataSource's IEnumerable collection by calling the DataSource's Select() method with no argument.

3. Call the ListBox's DataBind() method


Code

protected void Page_PreRender(Object sender, EventArgs e)
{
if(!IsPostBack)
{
   lstBox.DataSourceID = String.Empty;
   lstBox.DataSource = objSQL.Select(DataSourceSelectArgument.Empty);
   lstBox.DataBind();
}
}


Good Practice
For ordinary data binding operations like binding DataGrid, ListBox, DropDownList, etc, we normally perform in Page_Load() event. Actually, we can do the binding in the Page_PreRender event (bind the data-bound controls as late as possible) before the controls are about to be rendered.

Do always check IsPostBack before performing any data binding to reduce the roundtirp to server.


Digging into detailed observations...

Friday, September 29, 2006

Patterns & Practices Guidance Explorer

ScottGu recommended a very useful tool,namely Patterns & Practices Guidance Explorer, which contains hundreds lists of security & performance best practices and patterns. The usage scenarios are

"1. Improve the security and performance of your application with guidelines and checklists that match your application exactly.
2. You can build custom sets of guidance and share with your team as recommended practice.

3. You can add new guidance to the library to share with your team, your company or the larger development community. "



Hope this helps...

Thursday, September 21, 2006

Free PDF Converter in .NET

I have been struggling looking for non-commercial PDF library to convert my ASP.NET pages to PDF for reporting purpose. Finally, I decided to choose iTextSharp v3.1.5 library among other free libraries. I have found out that the library is extremely handy with few cool features such as document watermarking and encryption, user permission on copying, printing the document and the list goes on.

Anyway, there is an annoying problem - the library has iTextSharp.text.Image class, which conflicts with the System.Drawing.Image class. Hence, the class will be ambiguous if both namespaces are imported in your project. Anyway, this matter is bearable for me. :)


Library Project Homepage : http://sourceforge.net/projects/itextsharp/
Library Download : http://prdownloads.sourceforge.net/itextsharp/itextsharp-3.1.5-dll.zip?download
Tutorial (C#) Download : http://prdownloads.sourceforge.net/itextsharp/iTextSharp.tutorial.01.zip?download
Tutorial (VB) Download : http://prdownloads.sourceforge.net/itextsharp/iTextSharp.tutorial.VB.NET.01.zip?download


Cool !

Tuesday, September 19, 2006

No more DbCommandWrapper class

I'm testing the Enterprise Library January CTP 2006, and I have been searching for the DbCommandWrapper class and the GetXCommandWrapper() methods of Database class but they do not exist. Eventually, I found out that they are actually removed from the DAAB in this new version.

Example of code for old versions of DAAB prior to January 2006 release

Database db = DatabaseFactory.CreateDatabase();
DBCommandWrapper dbCommand = db.GetStoredProcCommandWrapper("SelectAuthors");
dbCommand.AddInParameter("AuthorID", DbType.String, strAuthorID);
DataSet dsAuthors = db.ExecuteDataSet(dbCommand);


Example of code for DAAB January CTP 2006

using System.Data.Common;

Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand("SelectAuthors");
db.AddInParameter(dbCommand,"AuthorID", DbType.String, strAuthorID);
DataSet dsAuthors = db.ExecuteDataSet(dbCommand);


Be informed that some online examples are using DbCommandWrapper class. thus, make some modification like above. Visit Intro to DAAB January 2006 for more version migration issues.

Monday, September 18, 2006

EBook on Threading in .NET

Thinking of learning Threading in .NET? I've found out a very handy ebook that explains fundamentals about .NET Threading. Worth to read !

Web : http://www.albahari.com/threading/
Book (PDF) : http://www.albahari.com/threading/threading.pdf


Sharing~~

Corrections of ClientCallBack Example

I have tested the example of ASP.NET 2.0 new feature - ClientCallBack at ASP.NET 2.0's Client Callback Feature, but found not working due to:

1. There is no this.GetCallbackEventReference()
2. RaiseCallbackEvent() does not return string data type, from ICallbackEventHandler
3. Missing of GetCallbackResult(), that defined in ICallbackEventHandler


Finally I get it done by making some corrections:

1. Use this.ClientScript.GetCallbackEventReference()
2. Define the RaiseCallbackEvent() that returns no data type
3. Define GetCallbackResult() to return the result to the client-side


Corrected code:

protected void Page_Load(object sender, EventArgs e)
{
       sCallBackInvocation = this.ClientScript.GetCallbackEventReference(this, "message", "ShowServerTime", "context", "OnError",true);
}

public void RaiseCallbackEvent(string eventArgument)
{
       sCallBackInvocation = DateTime.Now.ToString();
}

public string GetCallbackResult()
{
       return sCallBackInvocation;
}



Recommendation
1. Check whether the browser does support callback feature in Page_Load() event


if (!Request.Browser.SupportsCallback)
    // error message

Page Redirect After Login in Forms Authentication

Normally, we will be redirected to the originally requesting page, with ReturnUrl query string appended in the URL after successful user login in Form Authentication using FormsAuthentication.RedirectFromLoginPage() method. Otherwise, the we will be redirected to default.aspx, by default.

The question is, what method do we need to use if we want to redirect the users to different page other than default.aspx? Here I demonstrate how it can be accomplished.


bool isAuthenticated = true;

if(isAuthenticated) // after user is authenticated
{
   if(Request.Params["ReturnUrl"] != null)
   {
      FormsAuthentication.RedirectFromLoginPage(txtUsername.Text, false);
   }
   else
   {
      FormsAuthentication.SetAuthcookie(txtUsername.Text, false);
      Response.Redirect("yourpage.aspx");
   }
}


Get rid of default ones.... !

Sunday, September 17, 2006

VIEWing your controls STATE

ViewState is one of the state managements in the ASP.NET and it is paramount especially in custom server control development. Proper understanding and use of ViewState could definitely save your life, notably in postback model in ASP.NET.

Here I recommend some articles of ViewState for your readings :

1. Understanding ASP.NET ViewState [MSDN]
2. TRULY Understanding ViewState [InfiniteLoop's Blog]
3. Understanding View State in ASP.NET [aspAlliance]
4. ViewState: All You Wanted to Know
5. The ASP.NET ViewState [MSDN Magazine]


You already mastered another ASP.NET 's state management ;)

ASP.NET 2.0 Full Page Life Cycle Diagram

Here is the big yet comprehensive diagram illustrating the page life cycle in ASP.NET 2.0




To recall the Page Life Cycle in ASP.NET v1.x




ASP.NET 2.0 ones much complex !

Checking Existence of Available SQL Server

Of late, I had read an article about determining list of SQL Servers that are available to your application.

.NET 1.1
There is no way but you need to use COM-based SQLDMO to have an interop call.


using SQLDMO;

try
{
NameList objSQLList;
ApplicationClass objSQLApp = new SQLDMO.ApplicationClass();

objSQLList = objSQLApp.ListAvailableSQLServers();

foreach(string name in objSQLList)
Response.Write(name + "
");
}
catch(Exception ex)
{

}
finally
{
objSQLApp.Quit();
}


* You have to reference the SQLDMO.dll, which located at :\Program Files\Microsoft SQL Server\\Tools\Binn by default.


.NET 2.0
It is much easier. You can retrieve the list of servers available using System.Data.Sql namespace, by enumerating each of the server instance.


SqlDataSourceEnumerator enumerator = SqlDataSourceEnumerator.Instance;
DataTable datatable1 = enumerator.GetDataSources();
foreach (DataRow row in datatable1.Rows)
{
Response.Write("Server Name:" + row["ServerName"] + "
");
Response.Write("Instance Name:" + row["InstanceName"] + "
");
}


Sometimes, these methods are better trying to connect the DB Server to see whether it is succesfully connected, but the output not always accurate due to :

1. Invalid Login / User credentials
2. Timeout due to network congestions


Neat !

Tuesday, September 12, 2006

Storing Static JavaScript in Resource File [ASP.NET 2.0]

In ASP.NET , we normally embedded the script string in the code-behind and invoke the RegisterStartupScript() to emit the JavaScript. The normal way we do like


ClientScriptManager csManager = Page.ClientScript;

StringBuilder strScript = new StringBuilder();
strScript.AppendLine("<script>");
strScript.AppendLine(@"var response = confirm('{0}, do you want to continue ?');","Alvin Chooi");
strScript.AppendLine("if(response)");
strScript.AppendLine(" alert('OK')");
strScript.Append("</script>");

if (!csManager.IsStartupScriptRegistered("ScriptTest"))
   csManager.RegisterStartupScript(this.GetType(), "ScriptTest", strScript.ToString());


The script is less readable and messy. What the worst is that would be a slightly string manipulation overhead. In ASP.NET 2.0, you can store this static script in the resource file resx, which is stored in the App_GlobalResources folder.

Screenshot



You could able to reference the script string from the resource file without hard-coding the script in the code-behind by


ClientScriptManager csManager = Page.ClientScript;

if (!csManager.IsStartupScriptRegistered("ScriptTest"))
{
  csManager.RegisterStartupScript(this.GetType(), "ScriptTest", String.Format(Resources.script.AlertMeScript,"Alvin Chooi"));
}



Neat and manageable !

Microsoft Interview Questions

Recently, I'd read the post of Jason Looney about questions asked Microsoft Interview. Amazing and extraordinary !

Worth to read
1. Microsoft Interview Questions Guide
2. ASP.NET Interview Questions (The only one I could answer well ;p)
3. .NET Interview Questions
4. The Guerrilla Guide to Interviewing

Hunting for more....

Friday, September 08, 2006

Fastest Ever Browser ?

Recently, I had read an article of What is the world's fastest browser, and it claimed that optimized firefox (swiftfox) is the fastest browser among others in 64-bit environment. Whereas, Konqueror is crowned best-performance browser in Linux.

Thursday, September 07, 2006

Accessing Text in DataGrid's TemplateField

If you try to access the content of TemplateField

<asp:TemplateColumn>
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem,"au_fname") %>
<%# DataBinder.Eval(Container.DataItem,"au_lname") %>
</ItemTemplate>
</asp:TemplateColumn>

using DataGrid1.Items[0].Cells[0].Text (I assume it is first column), you would probably get nothing. It is because the text would be placed in a special literal control called DataBoundLiteralControl, which is auto-generated by the compiler IF you place the data-bound expression in the ItemTemplate. Therefore, to access its content. You can use this,

((DataBoundLiteralControl)dgrdAuthors.Items[0].Cells[0].Controls[0]).Text


You get it !!!

Capitalizing Every First Letter of Words

How would you do that in your first thought? Would you create your own user-defined function for that purpose in .NET? Please do not reinvent the wheel because there is built-in method available.


using System.Globalization;

string str = "cool strINg";
string str1 = "COOL STRING";

TextInfo objTextInfo = new CultureInfo("en-US",false).TextInfo();
str = objTextInfo.ToTitleCase(str); // Cool String *CORRECT
str1 = objTextInfo.ToTitleCase(str1); // COOL STRING *WRONG
str1 = objTextInfo.ToTitleCase(str1.toLower()); // Cool String *CORRECT


* For FULL CAPITALIZED words, you need to convert them to lower case before passing it to the ToTitleCase() method.

Dynamically Adding Columns to GridView

I was asked in ASP.NET Forum why the dynamically inserted BoundField would be lost from the GridView's column collection on postback (eg. Button click in GridView)?

Many people would dynamically create controls in the Page_Load event. But I afraid it isn't a right place for the dynamic creation because the data in the control may not be pertained. (ViewState lost on postback). If possible, do the dynamic control creation in Initialization event (eg. Page_Init).

One of the differences between Page_Init and Page_Load is Page_Init event is only fired once and it is not fired on each postback, whereas the Page_Load event is always fired on every postback.

Back to the topic, hence, to avoid the dynamic GridView's fields gone from its GridView's collection on postback, you SHOULD always create it in GridView's Init event. For instance,

Protected Sub GridView_Init(sender as Object, e as EventArgs) Handles myGridView.Init
Dim field As New BoundField()
field.DataField = "data"

myGridView.Columns.Insert(0, field) 'To be first column in GridView
End Sub



The related discussion can be found here

Good luck !

Recovering DB with LDF only

Of late, I witnessed the loss of mdf (due to corrupted or accidentally removed/overwritten) is painful. It is easy to recover the data from the .bak (database backup) or mdf(database file), but how would it be done the same thing just using ldf (log file) ? Here are the 10 steps that needs to be followed in order you have data restored.

1. Find out your previous database .bak file (backup file).

2. Backup your updated .MDF file and the latest LDF file

3. Delete your current database
- If you cant access to SQL Queries Analyzer no worries just open with master
- type :
DROP DATABASE SAMPLE_DB
GO

p/s - Make sure your infected MDF and LDF fully deleted from C:\Program Files\Microsoft SQL Server\MSSQL\Data

4. Create a new database with FULL Mode
- Open SQL Analyzer type following codes:
- type :
USE master
GO

CREATE DATABASE myDB
ON(NAME='myDB',
FILENAME='C:\Program Files\Microsoft SQL Server\MSSQL\Data\myDB..mdf')
LOG ON(NAME='myDB',
FILENAME='C:\Program Files\Microsoft SQL Server\MSSQL\Data\myDB_Log')
GO

ALTER DATABASE myDB
SET RECOVERY FULL
GO

EXEC sp_dboption 'myDB', 'autoclose', true
GO


5. Delete existing data and log files
- type :
EXEC master..xp_cmdshell 'del C:\Program Files\Microsoft SQL Server\MSSQL\Data\myDB.mdf
EXEC master..xp_cmdshell 'del C:\Program Files\Microsoft SQL Server\MSSQL\Data\myDB_Log'
GO


- Make sure no more .MDF and .LDF in your C:\Program Files\Microsoft SQL Server\MSSQL\Data


6. Stop your whole database

7. Copy your previous infected .MDF and .LDF to C:\Program Files\Microsoft SQL Server\MSSQL\Data

8. Backup the log with NO_TRUNCATE
- Note that backup will error due to inaccessible data file, but log will still be backed up.
- type :
BACKUP LOG myDB
TO DISK='C:\Backups\myDB.bak'
WITH NO_TRUNCATE, INIT
GO

- Make sure backup success, check the .bak file if the file size too small if compare with your .LDF file size then might be error, maybe your infected .LDF file stored wrongly, but normally no problem.
- This is very important file, no error here then fine already.

9. Restore your database

- Restore your previous backup database. Doesn't matter if your data not up to date.
- type :
USE Master

RESTORE DATABASE DatabaseName
FROM DISK = 'c:\Backups\old_myDB.BAK
WITH NORECOVERY


- p/s Remember use WITH NORECOVERY



10. Restore your backup log

- type:
RESTORE LOG myDB
FROM DISK = 'C:\Backups\myDB.bak'
WITH RECOVERY


- p/s Remember use WITH RECOVERY

- Check your data again.
- Done !!!

JSON Reader

Today is a boring day, I decided to create a lightweight JSON reader for JSON manipulation using JavaScript (After I have not been touching JSON and JavaScript prototype since my FYP). My intention of creating this JSONReader is simply to manipulate/read the JSON value with string path supplied. To start off, I use a very simple JSON in my example.

var myJSON = {"Image": {
"Width":800,
"Width":200,
"Height":600,
"Title":"View from 15th Floor",
"Thumbnail":
{
"Url":"http:\/\/scd.mm-b1.yimg.com\/image\/481989943",
"Height": 125,
"Width": "100"
},
"IDs":[ 116, 943, 234, 38793 ]
}}


Now, we "instantiate" the object of JSONReader with the JSON format passed as parameter to its constructor.


var reader = new JSONReader(myJSON);


Then at the frontend, we allow the users to key in the string path in the TextBox.


<input type="text" id="txtPath" name="textfield">
<input type="button" onclick="GetValue()" name="Submit" value="Get the Value">

<span id="lblMessage"/>


The string path provided by user will be passed to the FindValueByKeyPath() method of JSONReader in the GetValue() function to obtain the value in JSON. The $F() is the method in the prototype.js that used to retrieve the value of specified HTML element.

var path = $F("txtPath");
lblMessage.innerHTML = reader.findValueByKeyPath(path);


Test Results
User Input : Image\Thumbnail
Output : {"Url":"http://scd.mm-b1.yimg.com/image/481989943","Height":125,"Width":"100"}

User Input : Image\Thumbnail\Url
Output : http://scd.mm-b1.yimg.com/image/481989943


Screenshot



Additional Libraries Needed
prototype.js
$F(), class.Create()

json.js
parseJSON(), toJSONString()


The complete example can be downloaded here


Still boring ~~ :|

Saturday, September 02, 2006

ASP.NET Best Practices

I have been collecting ASP.NET BEST PRACTICES articles for quite some time. Here are some articles/guidelines that may be handy to you.

ASP.NET Performance Best Practices
1. Improving ASP.NET Performance [MSDN]
2. Developing High-Performance ASP.NET Application [MSDN2]
3. Performance Tips and Tricks for .NET Applications [MSDN]
4. 10 Tips for Writing High-Performance Web Applications [MSDN Magazine]
5. Improving String Handling Performance in .NET Framework Applications [MSDN]
6. Performance Strategies for Enterprise Web Site Development [Code Project]
7. Improving SQL Server Performance [MSDN]
8. Developing High-Performance ASP.NET Applications [aspalliance]


ASP.NET Security Best Practices
1. Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication [MSDN]
2. Improving Web Application Security: Threats and Countermeasures [MSDN]
3. ASP.NET Security: 8 Ways to Avoid Attack [devx]
4. SQL Injection Attacks - Are You Safe? [sitepoint.com]
5. Security Practices: ASP.NET 2.0 Security Practices at a Glance [MSDN]
6. An Introductory Guide to Building and Deploying More Secure Sites with ASP.NET and IIS [MSDN Magazine]


ADO.NET Best Practices
1. Best Practices for Using ADO.NET [MSDN]
2. ADO.NET Best Practices [devx]
3. ADO.NET Best Practices, Part II [devx]
4. ADO.NET Best Practices [code-magazine]
5. Using Data with ASP.Net - 10 of my 'Best Practices'
6. Optimized ADO.NET [theserverside.net]
7. ADO.NET and SQL Server Performance Tips [sql-server-performance]


Error Logging / Exceptions Best Practices
1. Best Practices for Handling Exceptions [MSDN]
2. Exception Handling Best Practices in .NET [codeproject]
3. Exception Handling in Enterprise Applications [devcity]
4. Exception Handling Best Practices in .NET


Naming/Standards Guidelines
1. Naming Guidelines [MSDN]
2. C# Coding Standards and Best Programming Practices [dotnetspider]
3. SSW's Naming Conventions [SSW]


I'll post more useful ASP.NET links in the future. Hope this helps... :)