Use simple cursor and syntax

•April 18, 2007 • Leave a Comment
A. Use simple cursor and syntax

The result set generated at the opening of this cursor includes all rows and all columns in the authors table of the pubs database. This cursor can be updated, and all updates and deletes are represented in fetches made against this cursor. FETCH NEXT is the only fetch available because the SCROLL option has not been specified.

DECLARE authors_cursor CURSOR
   FOR SELECT * FROM authors
OPEN authors_cursor
FETCH NEXT FROM authors_cursor
B. Use nested cursors to produce report output

This example shows how cursors can be nested to produce complex reports. The inner cursor is declared for each author.

SET NOCOUNT ON

DECLARE @au_id varchar(11), @au_fname varchar(20), @au_lname varchar(40),
   @message varchar(80), @title varchar(80)

PRINT "-------- Utah Authors report --------"

DECLARE authors_cursor CURSOR FOR
SELECT au_id, au_fname, au_lname
FROM authors
WHERE state = "UT"
ORDER BY au_id

OPEN authors_cursor

FETCH NEXT FROM authors_cursor
INTO @au_id, @au_fname, @au_lname

WHILE @@FETCH_STATUS = 0
BEGIN
   PRINT " "
   SELECT @message = "----- Books by Author: " +
      @au_fname + " " + @au_lname

   PRINT @message

   -- Declare an inner cursor based
   -- on au_id from the outer cursor.

   DECLARE titles_cursor CURSOR FOR
   SELECT t.title
   FROM titleauthor ta, titles t
   WHERE ta.title_id = t.title_id AND
   ta.au_id = @au_id   -- Variable value from the outer cursor

   OPEN titles_cursor
   FETCH NEXT FROM titles_cursor INTO @title

   IF @@FETCH_STATUS <> 0
      PRINT "         <<No Books>>"     

   WHILE @@FETCH_STATUS = 0
   BEGIN

      SELECT @message = "         " + @title
      PRINT @message
      FETCH NEXT FROM titles_cursor INTO @title

   END

   CLOSE titles_cursor
   DEALLOCATE titles_cursor

   -- Get the next author.
   FETCH NEXT FROM authors_cursor
   INTO @au_id, @au_fname, @au_lname
END

CLOSE authors_cursor
DEALLOCATE authors_cursor
GO

html email

•April 18, 2007 • Leave a Comment

No sure whether the problem is something incorrect when you interop call
your vb6 COM dll.
Can you correctly use CDO component directly to send mail in .net
application through COM interop? From my local test , I can successfully
use CDO to send html mails with embeded images in a winform app. Here is
the test code:

=========================
private void btnSendCDO_Click(object sender, System.EventArgs e)
{
try
{
CDO.Message msg = new CDO.MessageClass();

msg.To = txtEmail.Text;

msg.Subject = “Test Image Mail”;
msg.From = “Alaindel***@gmail.com”;

msg.CreateMHTMLBody(“http://www.asp.net“,CDO.CdoMHTMLFlags.cdoSuppressNone,”
“,”");

CDO.Configuration config = new CDO.ConfigurationClass();

ADODB.Fields fields = null;

fields = config.Fields;

ADODB.Field field = null;

field =
fields["http://schemas.microsoft.com/cdo/configuration/sendusing"];
field.Value = 1;

field =
fields["http://schemas.microsoft.com/cdo/configuration/sendusing"];
field.Value = CDO.CdoPostUsing.cdoPostUsingPort;

field =
fields["http://schemas.microsoft.com/cdo/configuration/smtpserver"];
field .Value = “smtphost”;

fields.Update();
msg.Configuration = config;
msg.Send();

msg = null;
config = null;
fields = null;
field = null;

}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}

}

Parsing XML messge in VB.Net

•April 18, 2007 • Leave a Comment

When I try to parse: I get the following error message:

Unable to cast COM object of type
‘Microsoft.SqlServer.MSXML6.DOMDocumentClass’ to interface type
‘MSXML2.ServerXMLHTTP40′. This operation failed because the QueryInterface
call on the COM component for the interface with IID
‘{2E01311B-C322-4B0A-BD77-B90CFDC8DCE7}’ failed due to the following error:
No such interface supported (Exception from HRESULT: 0×80004002
(E_NOINTERFACE)).”}

This is my code:

Private Sub cmdLogin_Click()
Dim loginXml As String
Dim loginResponse As MSXML2.DOMDocument40

loginXml = “<?xml version=’1.0′ encoding=’ISO-8859-1′?>” & _
“<Login xmlns=”"urn:schemas-tms:Login”">” & _
“<CustomerName>Test Closet</CustomerName>” & _
“<UserName>test</UserName>” & _
“<Password>none</Password>” & _
“</Login>”

loginResponse = SendXmlRequest(loginXml)

If Not loginResponse Is Nothing Then
If ParseLoginResponse(loginResponse) Then
cmdQueryAssetList.Enabled = True
End If
Else
Console.WriteLine(“Login request failed.”)
End If
End Sub

Private Function SendXmlRequest(ByRef xml As String) As MSXML2.DOMDocument40
Dim xmpRequest As MSXML2.ServerXMLHTTP40

xmpRequest = New MSXML2.ServerXMLHTTP40

‘ Set known timeout values so we have more control over our request.
Call xmpRequest.setTimeouts(10000&, 10000&, 30000&, 30000&)

‘ Open the Xmp Url for a Post operation and make the call synchronously.
Call xmpRequest.open(“POST”, XmpUrl, False)

‘ Set the necessary Http headers.
Call xmpRequest.setRequestHeader(“Accept”, “text/html, text/plain”)
Call xmpRequest.setRequestHeader(“User-Agent”, “Custom App Name v1.0″)
Call xmpRequest.setRequestHeader(“Content-Type”, “text/xml”)

Call xmpRequest.send(xml)

‘ If the request times out, it throws an error, but we can simply check
the readyState
On Error Resume Next

If xmpRequest.readyState = 4 Then
‘ Turn error handling back on.
On Error GoTo 0

‘ The Http request was completed. However, this does not mean
‘ that it was necessarily successful. A successful Http response
‘ will have a Status Code of 200.
If xmpRequest.Status = 200 Then
‘ The Http request/response was successful, now we
‘ need to check the Xml that was returned for any errors.
If Not RequestHasErrors(xmpRequest.responseText) Then
‘ The overall request was successful so we can begin
‘ to parse the response Xml as necessary.
SendXmlRequest = xmpRequest.responseXML
End If
Else
‘ There was an Http error.
Console.WriteLine(“Status Code: ” & xmpRequest.Status)
Console.WriteLine(“Status Text: ” & xmpRequest.statusText)
Console.WriteLine(“Response Text: ” & xmpRequest.responseText)
End If
Else
Call MsgBox(“There was an error. ReadyState = ” &
xmpRequest.readyState)
End If
End Function

Private Function RequestHasErrors(ByRef xml As String) As Boolean
‘ Check for the high level error Xml in any response before
‘ trying to parse the results.
If InStr(xml, “<Response><Error>”) >= 1 Then
RequestHasErrors = True
End If
End Function

Private Function ParseLoginResponse(ByRef loginDom As MSXML2.DOMDocument40)
As Boolean
‘ See if the login was successful. If so, get the SessionID.
‘ Otherwise, log the error.
ParseLoginResponse = False

‘ Setup the Dom to use XPath queries and also setup
‘ an Xml namespace prefix for use in the XPath queries.
Call loginDom.setProperty(“SelectionLanguage”, “XPath”)
Call loginDom.setProperty(“SelectionNamespaces”,
“xmlns:ns=’urn:schemas-tms:LoginResponse’”)

Dim node As MSXML2.IXMLDOMNode

node = loginDom.selectSingleNode(“ns:LoginResponse/ns:Status”)

If node.Text = “Success” Then
‘ The login was 100% successful so get the SessionID.
node = loginDom.selectSingleNode(“ns:LoginResponse/ns:SessionID”)
g_SessionID = node.Text

ParseLoginResponse = True
Else
‘ The login was not 100% successful.
node = loginDom.selectSingleNode(“ns:LoginResponse/ns:SystemMessage”)
Console.WriteLine(“Login unsuccessful: ” & node.Text)
End If

loginDom = Nothing
node = Nothing
End Function

Private Sub cmdQueryAssetList_Click()
Dim queryAssetListXml As String
Dim queryAssetListResponse As MSXML2.DOMDocument40

queryAssetListXml = “<?xml version=’1.0′ encoding=’ISO-8859-1′?>” & _
“<QueryAssetList2
xmlns=”"urn:schemas-tms:QueryAssetList2″”>” & _
“<SessionID>” & g_SessionID & “</SessionID>” & _
“</QueryAssetList2>”

queryAssetListResponse = SendXmlRequest(queryAssetListXml)

If Not queryAssetListResponse Is Nothing Then
Call ParseQueryAssetListResponse(queryAssetListResponse )
Else
Console.WriteLine(“Query Asset List failed.”)
End If
End Sub

Private Sub ParseQueryAssetListResponse(ByRef assetListDom As
MSXML2.DOMDocument40)
‘ Setup the Dom to use XPath queries and also setup
‘ an Xml namespace prefix for use in the XPath queries.
Call assetListDom.setProperty(“SelectionLanguage”, “XPath”)
Call assetListDom.setProperty(“SelectionNamespaces”,
“xmlns:ns=’urn:schemas-tms:QueryAssetList2′”)

Console.WriteLine(assetListDom.xml)

Dim organizations As MSXML2.IXMLDOMNodeList
Dim org As MSXML2.IXMLDOMNode
Dim assets As MSXML2.IXMLDOMNodeList
Dim asset As MSXML2.IXMLDOMNode

organizations =
assetListDom.selectNodes(“ns:QueryAssetList2/ns:Organization”)

For Each org In organizations
Console.WriteLine(org.Attributes.getNamedItem(“Name”).Text)
assets = org.selectNodes(“ns:AssetList/ns:Asset”)

For Each asset In assets
Console.WriteLine(” ” &
asset.Attributes.getNamedItem(“ID”).Text)
Next
Next
End Sub

RegisterClientScriptBlock Method(control, type, key, script, addScriptTags)

•April 18, 2007 • Leave a Comment

Registers a client script block for a control inside an UpdatePanel control with the ScriptManager control, and then adds the script block to the page.

Syntax

CSharp

public static void RegisterClientScriptBlock (
	Control control,
	Type type,
	string key,
	string script,
	bool addScriptTags
)

VisualBasic

Public Shared Sub RegisterClientScriptBlock ( _
	control As Control, _
	type As Type, _
	key As String, _
	script As String, _
	addScriptTags As Boolean _
)

ManagedCPlusPlus

public:
static void RegisterClientScriptBlock (
	Control^ control,
	Type^ type,
	String^ key,
	String^ script,
	bool addScriptTags
)

JSharp

public static void RegisterClientScriptBlock (
	Control control,
	Type type,
	String key,
	String script,
	boolean addScriptTags
)

Parameters

control (Control)

The control that is registering the client script block.

type (Type)

The type of the client script block. This parameter is usually specified by using the typeof (C# Reference) operator (C#) or the GetType Operator operator (Visual Basic) to retrieve the type of the control that is registering the script.

key (String)

The string that uniquely identifies the script block.

script (String)

A string that contains the script.

addScriptTags (Boolean)

A Boolean value that indicates whether to enclose the script block in <script> tags.

Remarks

The RegisterClientScriptBlock method is used to register a client script block that is compatible with partial-page rendering and that has no Microsoft AJAX Library dependencies. Client script blocks that are registered with this method are sent to the page only when the control parameter is inside an UpdatePanel control that is updated. To register a script file each time an asynchronous postback occurs, use the RegisterClientScriptBlock(Page, Type, String, String, Boolean) overload of this method. If you are registering a script file that does not pertain to partial-page updates and you want to register a script file only one time during initial page rendering, use the RegisterClientScriptBlock(Type, String, String) method of the ClientScriptManager class. You can get a reference to the ClientScriptManager object from the ClientScript property of the page.

If the addScriptTags parameter is true, the RegisterClientScriptBlock method adds <script> tags around the script literal. Pass false for addScriptTags when you want to create <script> tags yourself, such as when you want to set the attributes of specific <script> tags. If addScriptTags is false and the script parameter contains multiple script blocks, an exception is thrown.

The RegisterClientScriptBlock method adds a script block to the page after the opening <form> element tag. The script blocks are not guaranteed to be output in the same order in which they are registered. If the order of the script blocks is important, concatenate your script blocks into a single string (for example, by using the StringBuilder object), and then register them as a single client script block.

Examples

CS

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    protected void Page_PreRender(object sender, EventArgs e)
    {
        string script = @"
        function ToggleItem(id)
          {
            var elem = $get('div'+id);
            if (elem)
            {
              if (elem.style.display != 'block')
              {
                elem.style.display = 'block';
                elem.style.visibility = 'visible';
              }
              else
              {
                elem.style.display = 'none';
                elem.style.visibility = 'hidden';
              }
            }
          }
        ";

        ScriptManager.RegisterClientScriptBlock(
            this,
            typeof(Page),
            "ToggleScript",
            script,
            true);
    }

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>ScriptManager RegisterClientScriptInclude</title>
</head>
<body>
    <form id="Form1" runat="server">
        <div>
            <br />
            <asp:ScriptManager ID="ScriptManager1"
                                 EnablePartialRendering="true"
                                 runat="server">
            </asp:ScriptManager>
            <asp:UpdatePanel ID="UpdatePanel1"
                               UpdateMode="Conditional"
                               runat="server">
                <ContentTemplate>
                    <asp:XmlDataSource ID="XmlDataSource1"
                                       DataFile="~/App_Data/Contacts.xml"
                                       XPath="Contacts/Contact"
                                       runat="server"/>
                    <asp:DataList ID="DataList1" DataSourceID="XmlDataSource1"
                        BackColor="White" BorderColor="#E7E7FF" BorderStyle="None"
                        BorderWidth="1px" CellPadding="3" GridLines="Horizontal"
                        runat="server">
                        <ItemTemplate>
                            <div style="font-size:larger; font-weight:bold; cursor:pointer;"
                                 onclick='ToggleItem(<%# Eval("ID") %>);'>
                                <span><%# Eval("Name") %></span>
                            </div>
                            <div id='div<%# Eval("ID") %>'
                                 style="display: block; visibility: visible;">
                                <span><%# Eval("Company") %></span>
                                <br />
                                <a href='<%# Eval("URL") %>'
                                   target="_blank"
                                   title='<%# Eval("Name", "Link to the {0} Web site") %>'>
                                   <%# Eval("URL") %></a>
                                </asp:LinkButton>
                                <hr />
                            </div>
                        </ItemTemplate>
                        <FooterStyle BackColor="#B5C7DE" ForeColor="#4A3C8C" />
                        <SelectedItemStyle BackColor="#738A9C" Font-Bold="True" ForeColor="#F7F7F7" />
                        <AlternatingItemStyle BackColor="#F7F7F7" />
                        <ItemStyle BackColor="#E7E7FF" ForeColor="#4A3C8C" />
                        <HeaderStyle BackColor="#4A3C8C" Font-Bold="True" ForeColor="#F7F7F7" />
                    </asp:DataList>
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
    </form>
</body>
</html>

vb

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim script As String
        script = _
        "function ToggleItem(id)" & _
        "  {" & _
        "    var elem = $get('div'+id);" & _
        "    if (elem)" & _
        "    {" & _
        "      if (elem.style.display != 'block') " & _
        "      {" & _
        "        elem.style.display = 'block';" & _
        "        elem.style.visibility = 'visible';" & _
        "      } " & _
        "      else" & _
        "      {" & _
        "        elem.style.display = 'none';" & _
        "        elem.style.visibility = 'hidden';" & _
        "      }" & _
        "    }" & _
        "  }"

        ScriptManager.RegisterClientScriptBlock( _
            Me, _
            GetType(Page), _
            "ToggleScript", _
            script, _
            True)

    End Sub
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>ScriptManager RegisterClientScriptInclude</title>
</head>
<body>
    <form id="Form1" runat="server">
        <div>
            <br />
            <asp:ScriptManager ID="ScriptManager1"
                                 EnablePartialRendering="true"
                                 runat="server">
            </asp:ScriptManager>
            <asp:UpdatePanel ID="UpdatePanel1"
                               UpdateMode="Conditional"
                               runat="server">
                <ContentTemplate>
                    <asp:XmlDataSource ID="XmlDataSource1"
                                       DataFile="~/App_Data/Contacts.xml"
                                       XPath="Contacts/Contact"
                                       runat="server"/>
                    <asp:DataList ID="DataList1" DataSourceID="XmlDataSource1"
                        BackColor="White" BorderColor="#E7E7FF" BorderStyle="None"
                        BorderWidth="1px" CellPadding="3" GridLines="Horizontal"
                        runat="server">
                        <ItemTemplate>
                            <div style="font-size:larger; font-weight:bold; cursor:pointer;"
                                 onclick='ToggleItem(<%# Eval("ID") %>);'>
                                <span><%# Eval("Name") %></span>
                            </div>
                            <div id='div<%# Eval("ID") %>'
                                 style="display: block; visibility: visible;">
                                <span><%# Eval("Company") %></span>
                                <br />
                                <a href='<%# Eval("URL") %>'
                                   target="_blank"
                                   title='<%# Eval("Name", "Link to the {0} Web site") %>'>
                                   <%# Eval("URL") %></a>
                                </asp:LinkButton>
                                <hr />
                            </div>
                        </ItemTemplate>
                        <FooterStyle BackColor="#B5C7DE" ForeColor="#4A3C8C" />
                        <SelectedItemStyle BackColor="#738A9C" Font-Bold="True" ForeColor="#F7F7F7" />
                        <AlternatingItemStyle BackColor="#F7F7F7" />
                        <ItemStyle BackColor="#E7E7FF" ForeColor="#4A3C8C" />
                        <HeaderStyle BackColor="#4A3C8C" Font-Bold="True" ForeColor="#F7F7F7" />
                    </asp:DataList>
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
    </form>
</body>
</html>

App_Data

<Contacts>
    <Contact id="1"
             Name="Aaber, Jesper"
             Company="A. Data Corporation"
             URL="http://www.adatum.com/"/>
    <Contact id="2"
             Name="Canel, Fabrice"
             Company="Coho Winery"
             URL="http://www.cohowinery.com/"/>
    <Contact id="3"
             Name="Heloo, Waleed"
             Company="Contoso, Ltd"
             URL="http://www.contoso.com/"/>
    <Contact id="4"
             Name="Rovik, Dag"
             Company="Wingtip Toys"
             URL="http://www.wingtiptoys.com/"/>
</Contacts>

Exceptions

Exception Condition
ArgumentNullException

The client script block type is null.

- or -

The control that is registering the script block is null.

ArgumentException

The control that is registering the script block is not in the page’s control tree.

See Also

Assembly: System.Web.Extensions (Module: System.Web.Extensions)

•April 18, 2007 • Leave a Comment

New @ Page Directive Attributes

ASP.NET 2.0 adds many new attributes to the @ Page directive. The following attributes are new in ASP.NET 2.0.

Async

The Async attribute allows you to configure page to be executed asynchronously. Well cover asynchronous pages later in this module.

AsyncTimeout

Specified the timeout for asynchronous pages. The default is 45 seconds.

CodeFile

The CodeFile attribute is the replacement for the CodeBehind attribute in Visual Studio 2002/2003.

CodeFileBaseClass

The CodeFileBaseClass attribute is used in cases where you want multiple pages to derive from a single base class. Because of the implementation of partial classes in ASP.NET, without this attribute, a base class that uses shared common fields to reference controls declared in an ASPX page would not work properly because ASP.NETs compilation engine will automatically create new members based on controls in the page. Therefore, if you want a common base class for two or more pages in ASP.NET, you will need to define specify your base class in the CodeFileBaseClass attribute and then derive each pages class from that base class. The CodeFile attribute is also required when this attribute is used.

CompilationMode

This attribute allows you to set the CompilationMode property of the ASPX page. The CompilationMode property is an enumeration containing the values Always, Auto, and Never. The default is Always. The Auto setting will prevent ASP.NET from dynamically compiling the page if possible. Excluding pages from dynamic compilation increases performance. However, if a page that is excluded contains that code that must be compiled, an error will be thrown when the page is browsed.

EnableEventValidation

This attribute specifies whether or not postback and callback events are validated. When this is enabled, arguments to postback or callback events are checked to ensure that they originated from the server control that originally rendered them.

EnableTheming

This attribute specifies whether or not ASP.NET themes are used on a page. The default is false. ASP.NET themes are covered in Module 10.

LinePragmas

This attribute specifies whether line pragmas should be added during compilation. Line pragmas are options used by debuggers to mark specific sections of code.

MaintainScrollPositionOnPostback

This attribute specifies whether or not JavaScript is injected into the page in order to maintain scroll position between postbacks. This attribute is false by default.

When this attribute is true, ASP.NET will add a <script> block on postback that looks like this:

<script src="/website/WebResource.axd?d=jBAvpwrdOM_V_Xzeox989A2
        &amp;t=632653133849531250"
        type="text/javascript">
</script>

Note that the src for this script block is WebResource.axd. This resource is not a physical path. When this script is requested, ASP.NET dynamically builds the script.

MasterPageFile

This attribute specifies the master page file for the current page. The path can be relative or absolute. Master pages are covered in Module 4.

StyleSheetTheme

This attribute allows you to override user-interface appearance properties defined by an ASP.NET 2.0 theme. Themes are covered in Module 10.

Theme

Specifies the theme for the page. If a value is not specified for the StyleSheetTheme attribute, the Theme attribute overrides all styles applied to controls on the page.

Title

Sets the title for the page. The value specified here will appear in the <title> element of the rendered page.

ViewStateEncryptionMode

Sets the value for the ViewStateEncryptionMode enumeration. The available values are Always, Auto, and Never. The default value is Auto. When this attribute is set to a value of Auto, viewstate is encrypted is a control requests it by calling the RegisterRequiresViewStateEncryption method.

Setting Public Property Values via the @ Page Directive

Another new capability of the @ Page directive in ASP.NET 2.0 is the ability to set the initial value of public properties of a base class. Suppose, for example, that you have a public property called SomeText in your base class and youd like it to be initialized to Hello when a page is loaded. You can accomplish this by simply setting the value in the @ Page directive like so:

<%@ Page Language="C#" SomeText="Hello!" Inherits="PageBase" %>

The SomeText attribute of the @ Page directive sets the initial value of the SomeText property in the base class to Hello!. The video below is a walkthrough of setting the initial value of a public property in a base class using the @ Page directive.

preview

InitPlayer();

Download Video

New Public Properties of the Page Class

The following public properties are new in ASP.NET 2.0.

AppRelativeTemplateSourceDirectory

Returns the application-relative path to the page or control. For example, for a page located at http://app/folder/page.aspx, the property returns ~/folder/.

AppRelativeVirtualPath

Returns the relative virtual directory path to the page or control. For example for a page located at http://app/folder/page.aspx, the property returns ~/folder/page.aspx.

AsyncTimeout

Gets or sets the timeout used for asynchronous page handling. (Asynchronous pages will be covered later in this module.)

ClientQueryString

A read-only property that returns the query string portion of the requested URL. This value is URL encoded. You can use the UrlDecode method of the HttpServerUtility class to decode it.

ClientScript

This property returns a ClientScriptManager object that can be used to manage ASP.NETs emission of client-side script. (The ClientScriptManager class is covered later in this module.)

EnableEventValidation

This property controls whether or not event validation is enabled for postback and callback events. When enabled, arguments to postback or callback events are verified to ensure that they originated from the server control that originally rendered them.

EnableTheming

This property gets or sets a Boolean that specifies whether or not an ASP.NET 2.0 theme applies to the page.

Form

This property returns the HTML form on the ASPX page as an HtmlForm object.

Header

This property returns a reference to an HtmlHead object that contains the page header. You can use the returned HtmlHead object to get/set style sheets, Meta tags, etc.

IdSeparator

This read-only property gets the character that is used to separate control identifiers when ASP.NET is building a unique ID for controls on a page. It is not intended to be used directly from your code.

IsAsync

This property allows for asynchronous pages. Asynchronous pages are discussed later in this module.

IsCallback

This read-only property returns true if the page is the result of a call back. Call backs are discussed later in this module.

IsCrossPagePostBack

This read-only property returns true if the page is part of a cross-page postback. Cross-page postbacks are covered later in this module.

Items

Returns a reference to an IDictionary instance that contains all objects stored in the pages context. You can add items to this IDictionary object and they will be available to you throughout the lifetime of the context.

MaintainScrollPositionOnPostBack

This property controls whether or not ASP.NET emits JavaScript that maintains the pages scroll position in the browser after a postback occurs. (Details of this property were discussed earlier in this module.)

Master

This read-only property returns a reference to the MasterPage instance for a page to which a master page has been applied.

MasterPageFile

Gets or sets the master page filename for the page. This property can only be set in the PreInit method.

MaxPageStateFieldLength

This property gets or sets the maximum length for the pages state in bytes. If the property is set to a positive number, the pages view state will be broken up into multiple hidden fields so that it doesnt exceed the number of bytes specified. If the property is a negative number, the view state will not be broken into chunks.

PageAdapter

Returns a reference to the PageAdapter object that modifies the page for the requesting browser.

PreviousPage

Returns a reference to the previous page in cases of a Server.Transfer or a cross-page postback.

SkinID

Specifies the ASP.NET 2.0 skin to apply to the page.

StyleSheetTheme

This property gets or sets the style sheet that is applied to a page.

TemplateControl

Returns a reference to the containing control for the page.

Theme

Gets or sets the name of the ASP.NET 2.0 theme applied to the page. This value must be set prior to the PreInit method.

Title

This property gets or sets the title for the page as obtained from the pages header.

ViewStateEncryptionMode

Gets or sets the ViewStateEncryptionMode of the page. See a detailed discussion of this property earlier in this module.

New Protected Properties of the Page Class

The following are the new protected properties of the Page class in ASP.NET 2.0.

Adapter

Returns a reference to the ControlAdapter that renders the page on the device that requested it.

AsyncMode

This property indicates whether or not the page is processed asynchronously. It is intended for use by the runtime and not directly in code.

ClientIDSeparator

This property returns the character used as a separator when creating unique client IDs for controls. It is intended for use by the runtime and not directly in code.

PageStatePersister

This property returns the PageStatePersister object for the page. This property is primarily used by ASP.NET control developers.

UniqueFilePathSuffix

This property returns a unique suffic that is appended to the file path for caching browsers. The default value is __ufps= and a 6-digit number.

New Public Methods for the Page Class

The following public methods are new to the Page class in ASP.NET 2.0.

AddOnPreRenderCompleteAsync

This method registers event handler delegates for asynchronous page execution. Asynchronous pages are discussed later in this module.

ApplyStyleSheetSkin

Applies the properties in a pages style sheet to the page.

ExecuteRegisteredAsyncTasks

This method beings an asynchronous task.

GetValidators

Returns a collection of validators for the specified validation group or the default validation group if none is specified.

RegisterAsyncTask

This method registers a new async task. Asynchronous pages are covered later in this module.

RegisterRequiresControlState

This method tells ASP.NET that the pages control state must be persisted.

RegisterRequiresViewStateEncryption

This method tells ASP.NET that the pages viewstate requires encryption.

ResolveClientUrl

Returns a relative URL that can be used for client requests for images, etc.

SetFocus

This method will set the focus to the control that is specified when the page is initially loaded.

UnregisterRequiresControlState

This method will unregister the control that is passed to it as no longer requiring control state persistence.

Changes to the Page Lifecycle

The page lifecycle in ASP.NET 2.0 hasnt changed dramatically, but there are some new methods that you should be aware of. The ASP.NET 2.0 page lifecycle is outlined below.

PreInit (New in 2.0)

The PreInit event is the earliest stage in the lifecycle that a developer can access. The addition of this event makes it possible to programmatically change ASP.NET 2.0 themes, master pages, access properties for an ASP.NET 2.0 profile, etc. If you are in a postback state, its important to realize that Viewstate has not yet been applied to controls at this point in the lifecycle. Therefore, if a developer changes a property of a control at this stage, it will likely be overwritten later in the pages lifecycle.

Init

The Init event has not changed from ASP.NET 1.X. This is where you would want to read or initialize properties of controls on your page. At this stage, master pages, themes, etc. are already applied to the page.

InitComplete (New in 2.0)

The InitComplete event is called at the end of the pages initialization stage. At this point in the lifecycle, you can access controls on the page, but their state has not yet been populated.

PreLoad (New in 2.0)

This event is called after all postback data has been applied and just prior to Page_Load.

Load

The Load event has not changed from ASP.NET 1.X.

LoadComplete (New in 2.0)

The LoadComplete event is the last event in the pages load stage. At this stage, all postback and viewstate data has been applied to the page.

PreRender

If you would like for viewstate to be properly maintained for controls that are added to the page dynamically, the PreRender event is the last opportunity to add them.

PreRenderComplete (New in 2.0)

At the PreRenderComplete stage, all controls have been added to the page and the page is ready to be rendered. The PreRenderComplete event is the last event raised before the pages viewstate is saved.

SaveStateComplete (New in 2.0)

The SaveStateComplete event is called immediately after all page viewstate and control state has been saved. This is the last event before the page is actually rendered to the browser.

Render

The Render method has not changed since ASP.NET 1.X. This is where the HtmlTextWriter is initialized and the page is rendered to the browser.

Cross-Page Postback in ASP.NET 2.0

In ASP.NET 1.X, postbacks were required to post to the same page. Cross-page postbacks were not allowed. ASP.NET 2.0 adds the ability to post back to a different page via the IButtonControl interface. Any control that implements the new IButtonControl interface (Button, LinkButton, and ImageButton in addition to third-party custom controls) can take advantage of this new functionality via the use of the PostBackUrl attribute. The following code shows a Button control that posts back to a second page.

<asp:Button ID="SubmitReport" PostBackUrl="~/Default.aspx"
            runat="server" Text="Submit Report" />

When the page is posted back, the Page that initiates the postback is accessible via the PreviousPage property on the second page. This functionality is implemented via the new WebForm_DoPostBackWithOptions client-side function that ASP.NET 2.0 renders to the page when a control posts back to a different page. This JavaScript function is provided by the new WebResource.axd handler which emits script to the client.

The video below is a walkthrough of a cross-page postback.

preview

InitPlayer();

Download Video

More Details on Cross-Page Postbacks

Viewstate

You may have asked yourself already about what happens to the viewstate from the first page in a cross-page postback scenario. After all, any control that does not implement IPostBackDataHandler will persist its state via viewstate, so to have access to the properties of that control on the second page of a cross-page postback, you must have access to the viewstate for the page. ASP.NET 2.0 takes care of this scenario using a new hidden field in the second page called __PREVIOUSPAGE. The __PREVIOUSPAGE form field contains the viewstate for the first page so that you can have access to the properties of all controls in the second page.

Circumventing FindControl

In the video walkthrough of a cross-page postback, I used the FindControl method to get a reference to the TextBox control on the first page. That method works well for that purpose, but FindControl is expensive and it requires writing additional code. Fortunately, ASP.NET 2.0 provides an alternative to FindControl for this purpose that will work in many scenarios. The PreviousPageType directive allows you to have a strongly-typed reference to the previous page by using either the TypeName or the VirtualPath attribute. The TypeName attribute allows you to specify the type of the previous page while the VirtualPath attribute allows you to refer to the previous page using a virtual path. After youve set the PreviousPageType directive, you must then expose the controls, etc. to which you want to allow access using public properties.


Lab1 Cross-Page Postback

In this lab, you will create an application that uses the new cross-page postback functionality of ASP.NET 2.0.

  1. Open Visual Studio 2005 and create a new ASP.NET Web site.
  2. Add a new Webform called page2.aspx.
  3. Open the Default.aspx in Design view and add a Button control and a TextBox control.
    1. Give the Button control an ID of SubmitButton and the TextBox control an ID of UserName.
    2. Set the PostBackUrl property of the Button to page2.aspx.
  4. Open page2.aspx in Source view.
  5. Add a @ PreviousPageType directive as shown below:
  6. Add the following code to the Page_Load of page2.aspx’s code-behind:
    Response.Write(PreviousPage.UserName.Text);
  7. Build the project by clicking on Build on the Build menu. .
  8. Add the following code to the code-behind for Default.aspx:
    public TextBox txtUserName {
        get { return this.UserName; }
    }
  9. Change the Page_Load in page2.aspx to the following:
    Response.Write(PreviousPage.txtUserName.Text);
  10. Build the project.
  11. Run the project.
  12. Enter your name in the TextBox and click the button.
  13. What is the result?

Asynchronous Pages in ASP.NET 2.0

Many contention problems in ASP.NET are caused by latency of external calls (such as Web service or database calls), file IO latency, etc. When a request is made against an ASP.NET application, ASP.NET uses one of its worker threads to service that request. That request owns that thread until the request is complete and the response has been sent. ASP.NET 2.0 seeks to resolve latency issues with these types of issues by adding the capability to execute pages asynchronously. That means that a worker thread can start the request and then hand off additional execution to another thread, thereby returning to the available thread pool quickly. When the file IO, database call, etc. has completed, a new thread is obtained from the thread pool to finish the request.

The first step in making a page execute asynchronously is to set the Async attribute of the page directive like so:

<%@ Page Async="true" %>

This attribute tells ASP.NET to implement the IHttpAsyncHandler for the page.

The next step is to call the AddOnPreRenderCompleteAsync method at a point in the lifecycle of the page prior to PreRender. (This method is typically called in Page_Load.) The AddOnPreRenderCompleteAsync method takes two parameters; a BeginEventHandler and an EndEventHandler. The BeginEventHandler returns an IAsyncResult which is then passed as a parameter to the EndEventHandler.

The video below is a walkthrough of an asynchronous page request.

preview

InitPlayer();

Download Video

Note: An async page does not render to the browser until the EndEventHandler has completed. No doubt but that some developers will think of async requests as being similar to async callbacks. It’s important to realize that they are not. The benefit to asynchronous requests is that the first worker thread can be returned to the thread pool to service new requests, thereby reducing contention due to being IO bound, etc.

Script Callbacks in ASP.NET 2.0

Web developers have always looked for ways to prevent the flickering associated with a callback. In ASP.NET 1.X, SmartNavigation was the most common method for avoiding flickering, but SmartNavigation caused problems for some developers because of the complexity of its implementation on the client.  ASP.NET 2.0 addresses this issue with script callbacks. Script callbacks utilize XMLHttp to make requests against the Web server via JavaScript. The XMLHttp request returns XML data that can then be manipulated via the browser’s DOM. XMLHttp code is hidden from the user by the new WebResource.axd handler.

There are several steps that are necessary in order to configure a script callback in ASP.NET 2.0.

Step 1 : Implement the ICallbackEventHandler Interface

In order for ASP.NET to recognize your page as participating in a script callback, you must implement the ICallbackEventHandler interface. You can do this in your code-behind file like so:

public partial class _Default : System.Web.UI.Page, ICallbackEventHandler

You can also do this using the @ Implements directive like so:

<%@ Implements Interface="System.Web.UI.ICallbackEventHandler" %>

You would typically use the @ Implements directive when using inline ASP.NET code.

Step 2 : Call GetCallbackEventReference

As mentioned previously, the XMLHttp call is encapsulated in the WebResource.axd handler. When your page is rendered, ASP.NET will add a call to WebForm_DoCallback, a client script that is provided by WebResource.axd. The WebForm_DoCallback function replaces the __doPostBack function for a callback. Remember that __doPostBack programmatically submits the form on the page. In a callback scenario, you want to prevent a postback, so __doPostBack will not suffice.

Note: __doPostBack is still rendered to the page in a client script callback scenario. However, it’s not used for the callback.

The arguments for the WebForm_DoCallback client-side function are provided via the server-side function GetCallbackEventReference which would normally be called in Page_Load. A typical call to GetCallbackEventReference might look like this:

// Set up the JavaScript callback
string cbRef = cm.GetCallbackEventReference(this,
  "document.getElementById('ddlCompany').value",
    "ShowCompanyName", "null", true);

Note: In this case, cm is an instance of ClientScriptManager. The ClientScriptManager class will be covered later in this module.

There are several overloaded versions of GetCallbackEventReference. In this case, the arguments are as follows:

this

A reference to the control where GetCallbackEventReference is being called. In this case, it’s the page itself.

document.getElementById(‘ddlCompany’).value

A string argument that will be passed from the client-side code to the server-side event. In this case, Im passing the value of a dropdown called ddlCompany.

ShowCompanyName

The name of the client-side function that will accept the return value (as string) from the server-side callback event. This function will only be called when the server-side callback is successful. Therefore, for the sake of robustness, it is generally recommended to use the overloaded version of GetCallbackEventReference that takes an additional string argument specifying the name of a client-side function to execute in the event of an error.

null

A string representing a client-side function that it initiated before the callback to the server. In this case, there is no such script, so the argument is null.

true

A Boolean specifying whether or not to conduct the callback asynchronously.

The call to WebForm_DoCallback on the client will pass these arguments. Therefore, when this page is rendered on the client, that code will look like so:

WebForm_DoCallback(‘__Page’,document.getElementById(‘ddlCompany’).value,

ShowCompanyName,null,null,true)

Notice that the signature of the function on the client is a bit different. The client-side function passes 5 strings and a Boolean. The additional string (which is null in the above example) contains the client-side function that will handle any errors from the server-side callback.

Step 3 : Hook the Client-Side Control Event

Notice that the return value of GetCallbackEventReference above was assigned to a string variable. That string is used to hook a client-side event for the control that initiates the callback. In this example, the callback is initiated by a dropdown on the page, so I want to hook the OnChange event.

To hook the client-side event, simply add a handler to the client-side markup as follows:

// Hook the JavaScript function to the onchange event of the dropdown
ddlCompany.Attributes["onchange"] =
    String.Format("javascript:{0}", cbRef);

Recall that cbRef is the return value from the call to GetCallbackEventReference. It contains the call to WebForm_DoCallback that was shown above.

Step 4 : Register the Client-Side Script

Recall that the call to GetCallbackEventReference specified that a client-side script called ShowCompanyName would be executed when the server-side callback succeeds. That script needs to be added to the page using a ClientScriptManager instance. (The ClientScriptManager class will be dicussed later in this module.) You do that like so:

System.Text.StringBuilder clientScript =
    new System.Text.StringBuilder("");
ClientScriptManager cm = Page.ClientScript;
// Create the client script
clientScript.Append("function ShowCompanyName(companyName)");
clientScript.Append("{");
clientScript.Append("document.getElementById('CoClicked').innerHTML =
    \"You chose \" + companyName + \".\";");
clientScript.Append("}");
cm.RegisterClientScriptBlock(this.GetType(),
    "showCo", clientScript.ToString(), true);

Step 5 : Call the Methods of the ICallbackEventHandler Interface

The ICallbackEventHandler contains two methods that you need to implement in your code. They are RaiseCallbackEvent and GetCallbackEvent.

RaiseCallbackEvent takes a string as an argument and returns nothing. The string argument is passed from the client-side call to WebForm_DoCallback. In this case, that value is the value attribute of the dropdown called ddlCompany. Your server-side code should be placed in the RaiseCallbackEvent method. For example, if your callback is making a WebRequest against an external resource, that code should be placed in RaiseCallbackEvent.

GetCallbackEvent is responsible for processing the return of the callback to the client. It takes no arguments and returns a string. The string that it returns will be passed as an argument to the client-side function, in this case ShowCompanyName.

Once you have completed the above steps, you are ready to perform a script callback in ASP.NET 2.0.

preview

InitPlayer();

Download Video

Script callbacks in ASP.NET are supported in any browser that supports making XMLHttp calls. That includes all of the modern browsers in use today. Internet Explorer uses the XMLHttp ActiveX object while other modern browsers (including the upcoming IE 7) use an intrinsic XMLHttp object. To programmatically determine if a browser supports callbacks, you can use the Request.Browser.SupportCallback property. This property will return true if the requesting client supports script callbacks.

Working with Client Script in ASP.NET 2.0

Client scripts in ASP.NET 2.0 are managed via the use of the ClientScriptManager class. The ClientScriptManager class keeps track of client scripts using a type and a name. This prevents the same script from being programmatically inserted on a page more than once.

Note: After a script has been successfully registered on a page, any subsequent attempt to register the same script will simply result in the script not being registered a second time. No duplicate scripts are added and no exception occurs. To avoid unnecessary computation, there are methods that you can use to determine if a script is already registered so that you do not attempt to register it more than once.

The methods of the ClientScriptManager should be familiar to all current ASP.NET developers:

RegisterClientScriptBlock

This method adds a script to the top of the rendered page. This is useful for adding functions that will be explicitly called on the client.

There are two overloaded versions of this method. Three of four arguments are common among them. They are:

type (string)

The type argument identifies a type for the script. It is generally a good idea to use the page’s type (this.GetType()) for the type.

key (string)

The key argument is a user-defined key for the script. This should be unique for each script. If you attempt to add a script with the same key and type of an already added script, it will not be added.

script (string)

The script argument is a string containing the actual script to add. It’s recommended that you use a StringBuilder to create the script and then use the ToString() method on the StringBuilder to assign the script argument.

If you use the overloaded RegisterClientScriptBlock that only takes three arguments, you must include script elements (<script> and </script>) in your script.

You may choose to use the overload of RegisterClientScriptBlock that takes a fourth argument. The fourth argument is a Boolean that specifies whether or not ASP.NET should add script elements for you. If this argument is true, your script should not include the script elements explicitly.

Use the IsClientScriptBlockRegistered method to determine if a script has already been registered. This allows you to avoid an attempt to re-register a script that has already been registered.

RegisterClientScriptInclude (New in 2.0)

The RegisterClientScriptInclude tag creates a script block that links to an external script file. It has two overloads. One takes a key and a URL. The second adds a third argument specifying the type.

For example, the following code generates a script block that links to jsfunctions.js in the root of the scripts folder of the application:

ClientScriptManager cm = Page.ClientScript;
if(!cm.IsClientScriptIncludeRegistered("jsfunc")) {
    cm.RegisterClientScriptInclude(this.GetType(),
        "jsfunc",   "/scripts/jsfunctions.js");
    }

This code produces the following code in the rendered page:

<script src="/scripts/jsfunctions.js"
                type="text/javascript"></script>

Note: The script block is rendered at the bottom of the page.

Use the IsClientScriptIncludeRegistered method to determine if a script has already been registered. This allows you to avoid an attempt to re-register a script.

RegisterStartupScript

The RegisterStartupScript method takes the same arguments as the RegisterClientScriptBlock method. A script registered with RegisterStartupScript executes after the page loads but before the OnLoad client-side event. In 1.X, scripts registered with RegisterStartupScript were placed just before the closing </form> tag while scripts registered with RegisterClientScriptBlock were placed immediately after the opening <form> tag. In ASP.NET 2.0, both are placed immediately before the closing </form> tag.

Note: If you register a function with RegisterStartupScript, that function will not execute until you explicitly call it in client-side code.

Use the IsStartupScriptRegistered method to determine if a script has already been registered and avoid an attempt to re-register a script.

Other ClientScriptManager Methods

Here are some of the other useful methods of the ClientScriptManager class.

GetCallbackEventReference See script callbacks earlier in this module.
GetPostBackClientHyperlink Gets a JavaScript reference (javascript:<call>) that can be used to post back from a client-side event.
GetPostBackEventReference Gets a string that can be used to initiate a post back from the client.
GetWebResourceUrl Returns a URL to a resource that is embedded in an assembly. Must be used in conjunction with RegisterClientScriptResource.
RegisterClientScriptResource Registers a Web resource with the page. These are resources embedded in an assembly and handled by the new WebResource.axd handler.
RegisterHiddenField Registers a hidden form field with the page.
RegisterOnSubmitStatement Registers client-side code that executes when the HTML form is submitted.

How To Send a Binary Stream by Using XMLHTTP

•April 13, 2007 • Leave a Comment

SUMMARY

loadTOCNode(1, ’summary’);

In some cases you may want to send a binary stream to a server. One way to do so is to use the IXMLHTTPRequest object. This article demonstrates how to retrieve an ADO recordset from a server, modify it, and send it back as a stream of binary data.

Back to the top

MORE INFORMATION

loadTOCNode(1, ‘moreinformation’); This example uses the ADODB.Stream object to hold the binary data that is to be sent back to the server. If a newer version of MSXML has been installed in Side-by-Side mode, then to run the sample code with that specific version, you must explicitly use the GUIDs or ProgIDs for that version. For example, MSXML version 4 only installs in side-by-side mode. Please refer to the following article in the Microsoft Knowledge Base to see what code changes required to run the sample code with the MSXML 4.0 parser: Q305019 INFO: MSXML 4.0 Specific GUIDs and ProgIds.

For example, in the code below, you would create objects with MSXML 4.0 with the following statements:

var xmlhttp = new ActiveXObject(“Msxml2.XMLHTTP.4.0″);
xmldoc = new ActiveXObject(“Msxml2.DOMDocument.4.0″);
var xmlhttp = new ActiveXObject(“Msxml2.XMLHTTP.4.0″);

To use XMLHTTP to send a binary stream to a server, follow these steps:

1. Paste the following code into a file in your default Web folder and name the file Receiver.asp.

<%
dim Connection
dim rs
Connection = "Provider=SQLOLEDB.1;Data Source=servername;User Id=username;Password=password;Initial Catalog=Northwind;"
sql =  "Select * from Customers"

set rs = server.CreateObject("ADODB.Recordset")

if Request.QueryString("getRecordset") = "YES" then
	rs.ActiveConnection = Connection
	rs.CursorLocation = 3 'Client Side
	rs.CursorType = 3 'Static Recordset
	rs.LockType = 4 'Batch Optimistic
	rs.Open sql
	rs.Save response, 1 'persist adPersistXML
	Response.End
else
	rs.open Request '.BinaryRead(Request.TotalBytes)
	rs.activeconnection = Connection 'Reconnect
	rs.updatebatch 'Update adAffectAll
	rs.close
	Response.Write "Recordset Saved" 'Send back response
	Response.End
end if

%>
2. Paste the following code into a file in your default Web folder and name the file Sender.asp

<SCRIPT ID=clientEventHandlersJS LANGUAGE=javascript>
<!--

var rs;
var xmldoc;
var xmlstream;

function SendRS_onclick() {
	xmlstream = new ActiveXObject("ADODB.Stream");
	xmlstream.Mode = 3; //read write
	xmlstream.Open();
	xmlstream.Type = 1; // adTypeBinary
	rs.Save(xmlstream,0); //adpersistadtg
   	var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
   	xmlhttp.Open("POST","http://localhost/Receiver.asp?getRecordset=NO",false);
	xmlhttp.setRequestHeader("Content-Length",xmlstream.Size); //set the length of the content
   	xmlhttp.send(xmlstream.Read(xmlstream.Size)); //Send the stream
   	alert(xmlhttp.responseText);
}

function getRS_onclick() {
	rs = new ActiveXObject("ADODB.Recordset");
	xmldoc = new ActiveXObject("Msxml2.DOMDocument");
   	var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
   	xmlhttp.Open("Get","http://localhost/Receiver.asp?getRecordset=YES",false);
   	xmlhttp.send();
   	xmldoc.loadXML(xmlhttp.responseText); //load the returned stream into the dom document
   	rs.Open(xmldoc); //load the dom document into the recordset
   	alert("Recordset Loaded");
}

function Update_onclick() {
	alert("before: " + rs.Fields(2).Value);
	rs.Fields(2).Value = rs.Fields(2).Value + "!";
	rs.Update();
	alert("after: " + rs.Fields(2).Value);
}

//-->
</SCRIPT>
<INPUT type="button" value="Get Recordset" id=getRS name=getRS LANGUAGE=javascript onclick="return getRS_onclick()">
<INPUT type="button" value="Update" id=Update name=Update LANGUAGE=javascript onclick="return Update_onclick()">
<INPUT type="button" value="Send Recordset" id=SendRS name=SendRS LANGUAGE=javascript onclick="return SendRS_onclick()">
3. Modify the Receiver.asp page so that the connection variable contains a Microsoft SQL Server name and a valid SQL userid and password.
4. Start Microsoft Internet Explorer and browse to http://localhost/sender.asp.
5. Click Get Recordset. A message box appears and tells you that the recordset was loaded successfully.
6. Click Update. A message box appears and shows you the value before the update. A second message box appears and shows you the value after the update.
7. Click Send Recordset. A message box appears and tells you that the recordset was updated.

Back to the top

Known Limitations and Recommendations

loadTOCNode(2, ‘moreinformation’);

Although this allows you to use the persist mechanism to pass the data back and forth to the client, it is recommended that you use UpdateGrams or OpenXML with SQL Server 2000 to pass and send recordset data in XML format.
There are limitations in shaped recordsets. Edited shaped recordsets cannot be persisted in XML format. Also, parameterized shaped commands cannot be persisted at all. For additional information on persisting and limitations, see the following Microsoft Developer Network (MSDN) Web site:

XML Persistence Format
http://msdn.microsoft.com/library/psdk/dasdk/xmli3vsk.htm

•April 11, 2007 • Leave a Comment

XML Extras

From MDC

The XML Extras module contains several features that allow developers to treat XML as data i.e. not as just another document format. The module is structured as a drop-in component and exposes its XML-as-data features both to JavaScript and C++/XPCOM users. The XML Extras module is built by default on all platforms, and is included in the browser installers so it is available in the nightly builds.

Contents

[hide]

if (window.showTocToggle) { var tocShowText = “show”; var tocHideText = “hide”; showTocToggle(); }

[edit]

Feature Status

Feature Status
XMLSerializer Available
XMLHttpRequest Available
DOMParser (string and stream input source) Available
Web Services with SOAP and WSDL Available since 1.4alpha. Moved to Web Services module during 1.4beta.
XML Persistence  
FIXptr and XPointer Available since 1.4alpha in the core Mozilla. Moved to XMLExtras during 1.4beta.

See also:

[edit]

QA and Testing

There are some online tests for mainly exercising the HTTP GET method via XMLHttpRequest.

Other test cases for each of the implemented components listed above exist in extensions/xmlextras/tests/. More exhaustive test suites need to be created, however. If you’d like to help out with QA, you can do one of the following:

  • Sign up as the QA owner for any of the implemented components. The QA owner will manage the tests associated with their component, act as QA contact for related bugs and help with regression testing.
  • Contribute a test suite or individual tests that use the implemented components. File bugs for new test you have, and/or check them into extensions/xmlextras/tests/.
  • File bugs against the implemented components. Bugs should be filed against the XML component in the Browser product.

[edit]

Documentation

Probably the best way to learn how to use these technologies is through examples. There are some in extensions/xmlextras/tests/. If you follow that link to look at the examples you will need to look at page source for the HTML documents.

For XMLHttpRequest object you can mostly rely on the Microsoft XMLHttpRequest documentation, with some caveats: all functions and property names begin with a lower case letter and the object creation is different. Some properties are not implemented.

Thad Hoffman has written a document that shows how you can mimic XML Data Islands in Mozilla. Edmond Woychowsky has also written articles on XML Data Islands in Mozilla: “Make XML data islands work in Mozilla“, “Build cross-browser XML paging code” and “Implement a flexible shopping cart with XML and ASP“. The Mozilla Developer Center has several pages for XMLHttpRequest.

Below are some key differencies in “XML Extras” between Mozilla and Microsoft software:

Difference Microsoft Mozilla
Member names Case insensitive? Begins with lower case letter
XMLHttpRequest Creation new ActiveXObject("Msxml2.XMLHTTP") new XMLHttpRequest()
XMLHttpRequest.send("some string") ok ok starting with milestone 0.9.7 (actually nightly 2001-11-28). With older builds, passing strings to send() works only in chrome, see post.html sample. The “workaround” is to use DOMParser object’s parseFromString() method to create a document from string, and pass the temporary document into send().
XMLHttpRequest.open("aHost") ok file:// documents can access http:// documents but you need to enable UniversalBrowserRead privilege in your scripts – see the JavaScript Security: Signed Scripts document for more details. Normally your files should reside on a webserver so this shouldn’t pose a problem (there you do not need that line either). Additionally, “foo.com:80″ and “foo.com:313″ are considered different hosts for security purposes. You cannot open a connection to a different host.
DOMParser Creation not available new DOMParser()
XMLSerializer Creation not available new XMLSerializer()

Minimal documentation for the components listed above can be found using Mozilla documentation generated by Doxygen. File new bugs for additional documentation contributions, either specifically aimed at JavaScript developers or to complete & clarify the JavaDoc-style comments in the IDL files.

  • nsIDOMSerializer (Currently, the JavaScript constructor is XMLSerializer())
  • nsIDOMParser (Currently, the JavaScript constructor is DOMParser())
  • nsIXMLHttpRequest

Please see the XML Linking and Pointing section in XML in Mozilla document for FIXptr and XPointer documentation.

XMLHttpRequest Object Methods

•April 5, 2007 • Leave a Comment

As deployment of XML data and web services becomes more widespread, you may occasionally find it convenient to connect an HTML presentation directly to XML data for interim updates without reloading the page. Thanks to the little-known XMLHttpRequest object, an increasing range of web clients can retrieve and submit XML data directly, all in the background. To convert retrieved XML data into renderable HTML content, rely on the client-side Document Object Model (DOM) to read the XML document node tree and compose HTML elements that the user sees.

History and Support

Microsoft first implemented the XMLHttpRequest object in Internet Explorer 5 for Windows as an ActiveX object. Engineers on the Mozilla project implemented a compatible native version for Mozilla 1.0 (and Netscape 7). Apple has done the same starting with Safari 1.2.

Similar functionality is covered in a proposed W3C standard, Document Object Model (DOM) Level 3 Load and Save Specification. In the meantime, growing support for the XMLHttpRequest object means that is has become a de facto standard that will likely be supported even after the W3C specification becomes final and starts being implemented in released browsers (whenever that might be).

Creating the Object

Creating an instance of the XMLHttpRequest object requires branching syntax to account for browser differences in the way instances of the object are generated. For Safari and Mozilla, a simple call to the object’s constructor function does the job:

var req = new XMLHttpRequest();

For the ActiveX branch, pass the name of the object to the ActiveX constructor:

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

The object reference returned by both constructors is to an abstract object that works entirely out of view of the user. Its methods control all operations, while its properties hold, among other things, various data pieces returned from the server.

Object Methods

Instances of the XMLHttpRequest object in all supported environments share a concise, but powerful, list of methods and properties. Table 1 shows the methods supported by Safari 1.2, Mozilla, and Windows IE 5 or later.

Table 1. Common XMLHttpRequest Object Methods

Method Description
abort() Stops the current request
getAllResponseHeaders() Returns complete set of headers (labels and values) as a string
getResponseHeader("headerLabel") Returns the string value of a single header label
open("method", "URL"[, asyncFlag[, "userName"[, "password"]]]) Assigns destination URL, method, and other optional attributes of a pending request
send(content) Transmits the request, optionally with postable string or DOM object data
setRequestHeader("label", "value") Assigns a label/value pair to the header to be sent with a request

Of the methods shown in Table 1, the open() and send() methods are the ones you’ll likely use most. The first, open(), sets the scene for an upcoming operation. Two required parameters are the HTTP method you intend for the request and the URL for the connection. For the method parameter, use "GET" on operations that are primarily data retrieval requests; use "POST" on operations that send data to the server, especially if the length of the outgoing data is potentially greater than 512 bytes. The URL may be either a complete or relative URL (but see security issues below).

An important optional third parameter is a Boolean value that controls whether the upcoming transaction should be handled asynchronously. The default behavior (true) is to act asynchronously, which means that script processing carries on immediately after the send() method is invoked, without waiting for a response. If you set this value to false, however, the script waits for the request to be sent and for a response to arrive from the server. While it might seem like a good idea to wait for a response before continuing processing, you run the risk of having your script hang if a network or server problem prevents completion of the transaction. It is safer to send asynchronously and design your code around the onreadystatechange event for the request object.

The following generic function includes branched object creation, event handler assignment, and submission of a GET request. A single function argument is a string containing the desired URL. The function assumes that a global variable, req, receives the value returned from the object constructors. Using a global variable here allows the response values to be accessed freely inside other functions elsewhere on the page. Also assumed in this example is the existence of a processReqChange() function that will handle changes to the state of the request object.

var req;

function loadXMLDoc(url) {
	req = false;
    // branch for native XMLHttpRequest object
    if(window.XMLHttpRequest && !(window.ActiveXObject)) {
    	try {
			req = new XMLHttpRequest();
        } catch(e) {
			req = false;
        }
    // branch for IE/Windows ActiveX version
    } else if(window.ActiveXObject) {
       	try {
        	req = new ActiveXObject("Msxml2.XMLHTTP");
      	} catch(e) {
        	try {
          		req = new ActiveXObject("Microsoft.XMLHTTP");
        	} catch(e) {
          		req = false;
        	}
		}
    }
	if(req) {
		req.onreadystatechange = processReqChange;
		req.open("GET", url, true);
		req.send("");
	}
}

Note: It is essential that the data returned from the server be sent with a Content-Type set to text/xml. Content that is sent as text/plain or text/html is accepted by the instance of the request object however it will only be available for use via the responseText property.

Object Properties

Once a request has been sent, scripts can look to several properties that all implementations have in common, shown in Table 2. All properties are read-only.

Table 2. Common XMLHttpRequest Object Properties

Property Description
onreadystatechange Event handler for an event that fires at every state change
readyState Object status integer:
0 = uninitialized
1 = loading
2 = loaded
3 = interactive
4 = complete
responseText String version of data returned from server process
responseXML DOM-compatible document object of data returned from server process
status Numeric code returned by server, such as 404 for “Not Found” or 200 for “OK”
statusText String message accompanying the status code

Use the readyState property inside the event handler function that processes request object state change events. While the object may undergo interim state changes during its creation and processing, the value that signals the completion of the transaction is 4.

You still need more confirmation that the transaction completed successfully before daring to operate on the results. Read the status or statusText properties to determine the success or failure of the operation. Respective property values of 200 and OK indicate success.

Access data returned from the server via the responseText or responseXML properties. The former provides only a string representation of the data. More powerful, however, is the XML document object in the responseXML property. This object is a full-fledged document node object (a DOM nodeType of 9), which can be examined and parsed using W3C Document Object Model (DOM) node tree methods and properties. Note, however, that this is an XML, rather than HTML, document, meaning that you cannot count on the DOM’s HTML module methods and properties. This is not really a restriction because the Core DOM module gives you ample ways of finding element nodes, element attribute values, and text nodes nested inside elements.

The following listing shows a skeletal onreadystatechange event handler function that allows processing of the response content only if all conditions are right.

function processReqChange() {
    // only if req shows "loaded"
    if (req.readyState == 4) {
        // only if "OK"
        if (req.status == 200) {
            // ...processing statements go here...
        } else {
            alert("There was a problem retrieving the XML data:\n" +
                req.statusText);
        }
    }
}

If you are concerned about possible timeouts of your server process, you can modify the loadXMLDoc() function to save a global time-stamp of the send() method, and then modify the event handler function to calculate the elapsed time with each firing of the event. If the time exceeds an acceptable limit, then invoke the req.abort() method to cancel the send operation, and alert the user about the failure.

Security Issues

When the XMLHttpRequest object operates within a browser, it adopts the same-domain security policies of typical JavaScript activity (sharing the same “sandbox,” as it were). This has some important implications that will impact your application of this feature.

First, on most browsers supporting this functionality, the page that bears scripts accessing the object needs to be retrieved via http: protocol, meaning that you won’t be able to test the pages from a local hard disk (file: protocol) without some extra security issues cropping up, especially in Mozilla and IE on Windows. In fact, Mozilla requires that you wrap access to the object inside UniversalBrowserRead security privileges. IE, on the other hand, simply displays an alert to the user that a potentially unsafe activity may be going on and offers a chance to cancel.

Second, the domain of the URL request destination must be the same as the one that serves up the page containing the script. This means, unfortunately, that client-side scripts cannot fetch web service data from other sources, and blend that data into a page. Everything must come from the same domain. Under these circumstances, you don’t have to worry about security alerts frightening your users.

An Example: Reading XML Data from iTunes RSS Feeds

You can play with an example that points to four static XML files for demonstration purposes. The data sources are snapshots of some iTunes Store-related RSS feeds. Because the actual feeds are hosted at a third-party domain, the mixed domains of the example file and live RSS sources prevents a truly dynamic example.

When you choose one of the four listing categories, the script loads the associated XML file for that category. Further scripts extract various element data from the XML file to modify the options in a second select element. A click on one of the items reads a different element within that item’s XML data. That data happens to be HTML content, which is displayed within the example page without reloading the page.

Note that the sample data includes some elements whose tag names contain namespace designations. Internet Explorer for Windows (at least through Version 6) does not implement the DOM getElementsByTagNameNS() function. Instead it treats namespace tag names literally. For example, the <content:encoded> element is treated as an element whose tag name is content:encoded, rather than a tag whose local name is encoded and whose prefix is content. The example includes a utility API function called getElementTextNS() which handles the object model disparities, while also retrieving the text node contained by the desired element.

If you download the examples (DMG 2.0MB), you can test it yourself by placing it in your personal web server’s Sites folder, and accessing the page via the http: protocol. Keep all files, including the XML samples, in the same directory.

A Cool Combo

For years, advanced client-side developers have frequently wanted a clean way to maintain a “connection” with the server so that transactions can occur in the background, and newly updated data gets inserted into the current page. Many have tortured themselves by using techniques such as hidden self-refreshing frames and “faceless” Java applets. In lieu of a W3C standard still under development, the Microsoft-born XMLHttpRequest object fills an important gap that should inspire application development creativity. The feature is a welcome addition to Safari.

Updated: 2005-06-24

XMLHttpRequest

•April 5, 2007 • Leave a Comment

I am using XMLHttpRequest to request an XML file and display the data in an HTML page. I would like to call upon multiple XML files in the same HTML document without writing a different loadXMLDoc() function for each file that I will need to request. This more of a question on Javascript fundamentals.

How can I request multiple XML files using XMLHttpRequest on the same page while using the same function (loadXMLDoc) to do it? Perhaps using ‘this’ keyword or creating a class? Both are new to me, so I’m not sure.

<html>
<head>
<script type=”text/javascript” >
var xmlhttp
function loadXMLDoc(url)
{
// code for Mozilla, etc.
if (window.XMLHttpRequest)
{
//alert(“mozilla”);
xmlhttp=new XMLHttpRequest()
xmlhttp.onreadystatechange=state_Change
xmlhttp.open(“GET”,url,true)
xmlhttp.send(null)
}
// code for IE
else if (window.ActiveXObject)
{
xmlhttp=new ActiveXObject(“Microsoft.XMLHTTP”)
if (xmlhttp)
{
xmlhttp.onreadystatechange=state_Change
xmlhttp.open(“GET”,url,true)
xmlhttp.send()
}
}
}

function state_Change()
{
// if xmlhttp shows “loaded”
if (xmlhttp.readyState==4)
{
// if “OK”
if (xmlhttp.status==200)
{
displayLibrary();
}
else
{
alert(“Problem retrieving XML data:” + xmlhttp.statusText)
}
}
}

function getElementTextNS(prefix, local, parentElem, index) {
var result = “”;
if (prefix && isIE) {
// IE/Windows way of handling namespaces
result = parentElem.getElementsByTagName(prefix + “:” + local)[index];
} else {

result = parentElem.getElementsByTagName(local)[index];
}
if (result) {
// get text, accounting for possible
// whitespace (carriage return) text nodes
if (result.childNodes.length > 1) {
return result.childNodes[1].nodeValue;
} else {
return result.firstChild.nodeValue;
}
} else {
return “n/a”;
}
}

function displayLibrary() {
//loops through xml, builds a table and inserts table into Library div
}

function displayCategories() {
//loops through xml, builds a table and inserts table into Categories div
}

loadXMLDoc(‘Library.xml’);
//loadXMLDoc(‘Categories.xml’);

</script>
</head>

<body>
<table width=”760″ align=”center”>
<tr>
<td colspan=”3″><H3>HEADER</H3></td>
</tr>
<tr>
<td valign=”top”><DIV id=”Categories”></DIV></td>
<td><DIV id=”Library”></DIV></td>
<td>Other Content</td>
</tr>
<tr>
<td colspan=”3″ align=”center”>FOOTER</td>
</tr>
</table>
</body>
</html>

AJAX Queue

•April 5, 2007 • Leave a Comment

I was thinking of doing a simple AJAX framework for myself using some concepts of GUI programming. Actually just one, the event queue. Please note I haven’t done the implementation yet, this is just an idea at the moment.

The advantange to performing this approach is that it allows a separation of event handling from the actual page. The development of the AJAX enabled page would be similar to that of a standard GUI application.

Components:

* one JMS queue that resides on the presentation tier.
* one servlet to retrieve the queue data from the JMS queue and convert it to XML
* one servlet to retrieve a secure random number.
* a Javascript API to retrieve the queue data from the servlet and process the queue events.
* a JavaScript API to send data to the Servlet tier
* a Java API to put things into the JMS queue.

JMS Queue
All the event information is stored in a JMS queue. A JMS queue is required in order to ensure clusterabilty. On my initial drafts I put the queue as part of the session. Once I started to type out some rough implementation, I realized it would not be thread safe, and putting in the synchronized block prevents it from being clusterable. So I ended up with using a JMS queue on the presentation tier.

For those that don’t understand the concept of “on the presentation tier,” the basic idea is you would have a separate set of resources (which might be cheaper alternatives) that is used only to support whatever presentation tasks you might have. This is to allow separation of business concerns from presentation concerns. For example, a presentation tier database stores things that are too big or cumbersome to let session management handle. In the same way a temp file is used to put information rather than store things in memory and let the virtual memory manager handle the data. The presentation tier resources tend to be cheaper and less persistent, i.e., on application restart, all the temporary runtime data stored in there are deleted.

In order to prevent queues from overflowing, each message in the queue should have an expiration set. The expiration should be no more than one minute depending on how long you expect clients to process the next event. The messages should also be mark as non-persisting, since we don’t need them to stay if the queues happen to restart (since the application might be restarted as well anyway).

QueueServlet
The QueueServlet is an HttpServlet that retrieves event data from the JMS queue and transforms the data into an XML stream (possibly via JDOM or manual StringBuffers). This is the only place for the AJAX side to get responses from the server side.

The servlet will implement the doPost() method and uses the following logic:

public void doPost(HttpServletRequest request, HttpServletResponse response) {
// requestId is set by the RequestIdServlet
String requestId = request.getHeader(“requestId”);
String sessionId = request.getSession(false).getId();
List queueData = new LinkedList(); // we don’t do random access to the list

do {
// get the message from the JMS queue non blocking
Message m =
jmsQueue.getMessage(“requestId = ‘” + requestId + “‘ and ” +
“sessionId = ‘” + sessionId + “‘”);
if (m == null) {
break;
}
queueData.add(new AjaxEvent(m));
}
// Write the queue data as XML
writeQueueDataXml(queueData,response);
}

This approach ensures that the largest possible chunk is sent for every request. This solves the issue of too many requests getting a small chunk of data.

RequestIdServlet
This servlet performs a SecureRandom call to get a random number to pass back to the browser. The purpose of the id is to allow multiple pages to the same website to be open at the same time. As the QueueServlet, it only supports the POST method.

AjaxQueue JavaScript
The AjaxQueue JavaScript API is a JS file provided by the framework. It is responsible for creating/managing the XmlHttpRequest object and dealing with infrastructure based tasks. The typical Ajax enabled page would look like this:

<script src=”ajaxQueue.js” type=”text/javascript”></script>
<script>
// define event handlers
function handleFooEvent(eventDomTree) {
// do some DOM manipulation
}

// register events
registerEventHandler(“Foo”, handleFooEvent);
registerEventHandler(“Bar”, handleBarEvent);
registerErrorEventHandler(handleErrorEvent);

// start up the queue
startQueue(“QueueHandlerUrl”, “RequestIdUrl”);
</script>

In earlier attempts of implementing this, I tried to use a more object oriented fashion. However, since the xmlHttpRequest.onreadystatechange function cannot have parameters passed into it, things just ended up in global variables.

The global variables in ajaxQueue.js are:

* xmlHttp – an XmlHttpRequest object built based on the browser
* eventHandlers – an associative array that maps event name to a handler
* errorEventHandler – a function reference that gets called when there is an error
* requestId – a unique number representing the requests made from the current page
* queueUrl – the URL to the QueueServlet
* queueTimeout – the time to sleep before the next queue query

The xmlHttp.onreadystatechange function is implemented something like this.

xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
var events = xmlHttp.responseXML.getElementsByTagName(“event”);
for (var i = 0; i < events.length; ++i) {
var eventName = events[i].name
if (eventName == “history”) {
// special event to create a virtual entry in
// the history to handle the back button
doHistoryEvent(events[i]);
}
eventHandler = eventHandlers[eventName];
if (eventHandler) {
eventHandler(events[i]);
}
}
window.setTimeout(“processQueue()”, queueTimeout);
} else {
errorEventHandler(xmlHttp.statusText);
}
}
}

The startQueue function would look like this:

function startQueue(url, requestIdUrl, timeout) {
if (xmlHttp == null) {
// don’t do anything if AJAX is not supported.
return;
}
requestId = getRequestId(requestIdUrl);
queueUrl = url;
queueTimeout = timeout
// create invisible iframe to handle history events
createHistoryIFrame();

processQueue();
}

The processQueue() function that sends the request to the servlet would look like this:

function processQueue() {
xmlHttp.open(“POST”, queueUrl, true);
xmlHttp.setRequestHeader(“requestId”, requestId);
xmlHttp.send(null);
}

One way to further reduce the load on the servers is to alter the queueTimeout with a more intelligent algorithm rather than a fixed amount. This would have to be application specific though.

Sending messages to the server
Requests to the server side always need to have the “requestId” so they know what to put into the queue. And there will be several pieces of information that is going to get passed into the backend for each request. So the following function is provided:

function sendMessage(url, messageData) {
if (xmlHttp == null) {
// ensure that nothing happens if AJAX is not supported.
return;
}
// create a new xmlHttpRequest for sending data
var sendXmlHttp = createXmlHttpRequest();
sendXmlHttp.open(“POST”, url);
sendXmlHttp.setRequestHeader(“requestId”, requestId);
sendXmlHttp.send(messageData);
// error handling goes here.
}

The requests for the message sends are synchronous rather than asynchronous. This ensures that errors are captured properly if there are any.

Putting events into the queue
To put a message into the queue, the following code gets invoked:

AjaxQueue queue = null;
try {
queue = new AjaxQueue(servletContext, request);
queue.putEvent(e);
} finally {
if (queue != null) {
queue.close();
}
}

Of course that code block is too big and there will be a lot of copy and paste if we just left it like that. So a utility class called AjaxQueueUtil with a method

AjaxQueueUtil.putEvent(ServletContext context,
HttpServletRequest request,
Event events…)

that sends a list of events into the queue. This is provided to shield users from copying and pasting so many lines of code.

Conclusion

As specified earlier the advtange to performing this approach is that it allows a separation of event handling from the actual page. The development of the AJAX enabled page would be similar to that of a standard GUI application.

If the browser does not support AJAX or even scripting, its okay since the pattern is non-invasive to HTML and developers can AJAXify things as needed.

This pattern takes advantage of facilities within the J2EE spec and supports clustered environments and multiple windows on the same session. A large chunk of the logic is hidden within the API implementation to make things easier for the developers.

However, there is no concrete implementation of this pattern yet.