Friday, July 28, 2006

asp.net 2 postback

asp.net 2.0 introduced crosspage postback, with it the Page.PreviousPage property.

two scenerios are considered:
crosspage postback
server.transfer


usage differences:
IbuttonControl interface exposes PostBackUrl property, simply set this page to the destination page. with asp.net 1.1 , button event handler uses server.transfer to transfer to another page.

behavior differences:
when PostBackUrl is specified, an http post is sent to the destination page (to.aspx) url. with traditional server.transfer, http post is sent to the calling page (from.aspx) itself, then proceed to the destination page.



Page.PreviousPage and HttpContext.Current.Handler in to.aspx page.
Page.PreviousPage is the replacement for HttpContext.Current.Handler in Page classes.
with both methods, the PreviousPage is set to be post-from page, with a major difference that in cross-page method, PreviousPage uses lazy loading (load only on demand), post-from page's page events are all fired before onPreRender if PreviousPage is called. where in server.transfer, all post-from page events are fired up to the event handler for that action.
In both cases, Page.PreviousPage can be used, Post-to page can distinguish whether PreviousPage is a result of cross-page postback by the PreviousPage.IsCrossPagePosdBack property.

When using crosspage postback, unlike server.transfer, Handler is obviously set to the post-to page itself. this might cause confusion as in server.transfer, Handler is set to the from.aspx page. use of HttpContext.current.Handler should be eliminated in Page classes.


server-side validation
in cases serverside page validation is required, using crosspage method, the post-from page isn't validated on serverside unless requested in post-to page. post-to page needs to validate if previouspage is valid by this.PreviousPage.Validate() and IsValid.


URL:
probably only QA would benefit from this, with crosspage postback, form is posted to post-to page, thus url is updated.

Thursday, July 20, 2006

html header in content page in asp.net2.0

contentpage = contentpage for masterpage
htmlheader = this.Page.Header object

problem: master page hides the html head from content pages, in cases where more headers needs to be specified for each individual page, there must be a way to add more elements to header.

asp.net2.0 provides programmatic access to this.Page.Header property when header has the runat="server" set. page can then add header elements by calling this.Header.Controls.Add("some link, generichtml or meta controls").

fine, it works, but why do you want to write code to insert a simple CSS file? it has to be easily done in the markup. Scott Allen has an excellent idea on using ContentPlaceHolder in the header section: http://odetocode.com/Blogs/scott/archive/2006/04/10/3258.aspx. again, other than the html validation error, it works!
The drawback of Scott Allen's method is that you have to know the ID of that contentplaceholder, and that if there are multiple masterpages, contentplaceholder must be placed in all masterpages; which increases maintenance overhead.

the idea below comes from Scott Allen's "contentplaceholder in header", it's not neccessarily better in all cases, it's better in applications with more sophisticated design (e.g. nested masterpages, base masterpage classES, base page classES), it requires more coding in the front, but decrease amount of work later on.

main idea: Istead of using contentplaceholder, create a custom templated control that accept arbitrary markup, in page's prerender handler, dump everything from this templatecontrol into the page header.

requirements: html head tag must have runat=server, this is by default.

template control implementation:

namespace ServerControls
{
[DefaultProperty("HeadTemplate")]
[ToolboxData("<{0}:HeaderTag runat=server>")]
public class HeadTag : WebControl
{

private ITemplate _template;


[PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate HeaderTemplate
{
get
{
return _template;
}
set
{
this._template = value;
}
}
}
}

it's dead simple

how does the page use the control?

<cc1:HeadTag runat="server" ID="iheader">
<HeadTemplate>
whatever you want to add to the HEAD
</HeadTemplate>
</cc1:HeadTag>

ofcourse you need to register the control in page

how does the page then know to put it into html head?
there are two ways of doing this:

if you know the ID of the headertag control (assuming you are not using custom BasePage), then simply dump the controls in template into the page header.
in your page's codebehind:
headerTagControl.InstantiateIn(this.Header);


if you are using custom BasePage and do not know what the control's ID is, then you need to loop through all page controls to find HeaderTag control, there's performance overhead, but if you are using custom BasePage, you probably are looping through all controls for some reason.

call method below in basepage's prerender method.

private void UpdateControls(Control control)
{

if (control is Portal.ServerControls.HeadTag)
{
((ServerControls.HeadTag) control).HeadTemplate.InstantiateIn(this.Header);
}

if (control.HasControls())
{
foreach (Control _control in control.Controls)
{
UpdateControls(_control);
}
}
}

drawbacks:
the last piece of code loops through all controls to see if any is HeadTag, if HeadTag is the only control needs to be updated, then skip all this and use Scott Allen's method. in application with controls implementing some interfaces, the loop is mandatory, adding one more check does not do any more harm.

final words: for simple application, this is more work, might not worth spending time and effort setting it up, and might increase performance overhead. for more complicated systems, this is better than using contentplaceholder as aspx developers simply write:

<cc1:HeadTag runat="server" ID="head">
<HeadTemplate>
whatever content you want to be in the <head> tag
</HeadTemplate>
</cc1:HeadTag>

Wednesday, July 19, 2006

asp.net 2.0 Page.Controls in nested masterpage

WTF,

in content page, Page.Controls contains only one element, it's master page. this becomes a problem when accessing controls in the page (well, technically, they are not directly in the page.

with masterpages, contents are placed in the contentplaceholder, and those contentplaceholders belong to master page. masterpage and contentplaceholder both implement INamingContainer.

so to access these controls in contentplaceholder, this.FindControl(ID) would fail because controls are not in the page's NAMINGCONTAINER (FindControl only searches controls in parent's namingcontainer). to access A control, this.Master.FindControl(ContainPlaceID).FindControl(ID) would work, in the single level master page scenario.

In the nested masterpage scenario, the above method becomes impracticle. 1. the contentplaceholderid must be known, 2. masterpages might be loaded dynamically (from basepage class). contentplaceholder might not even be there 3. it's just stupid to write some code like that.

solving our problem, we can define a method that digs into controls (masterpage and contentplaceholder are simply controls), and find matching control.

Control FindControl(Control parent, string ID)
{
foreach(Control ctrl in parent.Controls)
{
if(ctrl.ID == ID)
return ctrl;
if(ctrl.hasControls())
return FindControl(ctrl, ID);
}
else
return null;
}

performance impact: O(n), so the more specific "parent" is, the less performance overhead there is.

Tuesday, June 27, 2006

atlas page onload event

<body onload> would not work in the atlas enabled page to execute remote WS JS. following should be used in the page.


<script type="text/xml-script">
<page>
<components>
<application load="onload" />
</components>
</page>

Friday, May 19, 2006

asp.net2 page life cycle

http://msdn2.microsoft.com/en-US/library/ms178472.aspx

asp.net2 master page event ordering

❑ Master page child controls initialization: All server controls contained within the master page are first initialized.
❑ Content page child controls initialization: All server controls contained in the content page are initialized.
❑ Master page initialization: The master page itself is initialized.
❑ Content page initialization: The content page is initialized.
❑ Content page load: The content page is loaded (this is the Page_Load event followed by the Page_LoadComplete event).
❑ Master page load: The master page is loaded (this is also the Page_Load event followed by the Page_LoadComplete event).
❑ Master page child controls load: The server controls on the master page are loaded onto the page.
❑ Content page child controls load: The server controls on the content page are loaded onto the page.

Sunday, February 26, 2006

FURPS+

FURPS =

Functional - features, capabilities, security.
Usability - human factors, help, documentationi.
Reliability - frequency of failure, recoverability, predictability.
Performance - response times, throughput, accuracy, availability, resource usage.
Supportability - adaptability, maintainability, internationalization, configurability.


[Applying UML and Patterns, Craig Larman]

Thursday, January 26, 2006

javascript getQueryString(key)

var locString = location.search;
function getQueryString(key)
{
var reg = new RegExp("(\\?|\\&)" + key + "=([^\\&]*)(\\&?)", "i").exec(locString);
return RegExp.$2;
}