Web Q&A

JScript Leaks, Getting the XmlDataDocument, and ASPX Includes

Edited by Nancy Michell

Q I have built a Web application that has a rich GUI and functionality to match. The application building blocks are XML, XSLT, and JScript®. I have had huge problems with the application consuming lots of memory, but I have no idea why this occurs. I use closures to implement event handlers and am wondering if this is contributing to leaks.

Q I have built a Web application that has a rich GUI and functionality to match. The application building blocks are XML, XSLT, and JScript®. I have had huge problems with the application consuming lots of memory, but I have no idea why this occurs. I use closures to implement event handlers and am wondering if this is contributing to leaks.

A The use of closures as event handlers is a very common cause of memory leaks. Closures allow inner functions to always have access to the variables and parameters of its outer function.

A The use of closures as event handlers is a very common cause of memory leaks. Closures allow inner functions to always have access to the variables and parameters of its outer function.

There's a blog entry by Eric Lippert about closures and memory leaks at What are closures?. Note, however, that this article contains an error that has not been corrected as of press time. It is not true that the circular reference is passivated when Microsoft® Internet Explorer navigates the page. That was briefly the case when this issue first cropped up a few years ago, but the Internet Explorer team discovered that this passivation broke too many existing pages, so they turned it off.

As far as building a Web app that has rich GUI functionality, as you stated, that's a bad idea in the first place— it leads to bloated software that leaks memory, for one thing (see Thin To My Chagrin).

The prudent use of closure semantics depends on whether the function is dynamically generated or not. If the function is dynamically generated, say via the new operator, you should find a way not to dynamically generate it. The expression new Function is just another way of saying eval, and eval is bad for performance. Eval starts a compiler. If the function needs to be dynamically generated, and it does not use closure semantics, then move the generator to a helper function that does not take arguments that form a circular reference. That way the generated function will be closed over the scope of something that does not refer back to the Internet Explorer object model. If the function is static and does not need closure semantics, then just don't nest it. If the function is static and does need closure semantics—well, rearchitect your application until you're out of this situation.

With all that said, remember that all of this is basically "enabling" advice—and not a good idea. Thin clients are thin for a reason—they are designed for running thin programs, not rich programs. In the long run it would be better to get away from this development paradigm altogether, and into the rich-client world of the .NET common language runtime (CLR).

Q How can I determine the XmlDataDocument associated with a DataSet? If I create an XmlDataDocument from the DataSet in the following line of code

XmlDataDocument xmlData = new XmlDataDocument(dataset);

it is easy to get the DataSet corresponding to the XmlDataDocument that is shown here:

DataSet dataset = xmlData.DataSet;

Q How can I determine the XmlDataDocument associated with a DataSet? If I create an XmlDataDocument from the DataSet in the following line of code

XmlDataDocument xmlData = new XmlDataDocument(dataset);

it is easy to get the DataSet corresponding to the XmlDataDocument that is shown here:

DataSet dataset = xmlData.DataSet;

However, once the association has been made between a DataSet and XmlDataDocument, how can I determine the XmlDataDocument from the DataSet? This is important because if I try to create a second XmlDataDocument from the Dataset, an exception is thrown. I am relying on the DataSet. In many processes, I operate on the data in XML format. When the DataSet is passed between methods I now need implicit knowledge about the calling method, whether an XmlDataDocument has been created, and what its reference is.

A There is no simple way out. Unfortunately, the DataSet does not provide any public API to check if an XmlDataDocument is attached or provide a reference to one. However, as a workaround, you can choose to do one of the following:

  1. Always instantiate XmlDataDocument in a try block and catch the argument exception that gets thrown if the DataSet is already attached to an XmlDataDocument.
  2. Programmatically keep track of whether the DataSet instance has an associated XmlDataDocument.

A There is no simple way out. Unfortunately, the DataSet does not provide any public API to check if an XmlDataDocument is attached or provide a reference to one. However, as a workaround, you can choose to do one of the following:

  1. Always instantiate XmlDataDocument in a try block and catch the argument exception that gets thrown if the DataSet is already attached to an XmlDataDocument.
  2. Programmatically keep track of whether the DataSet instance has an associated XmlDataDocument.

Then you can use DataSet.ExtendedProperty in order to create a user-defined property for keeping track of an attached/unattached XmlDataDocument.

For instance, register an attach operation using this code:

DataSet.ExtendedProperty.Add("XmlDataDocumentAttached", "1")

This extended property can be checked prior to instantiating the XmlDataDocument instance.

If you can ensure that the DataSet would not be serialized using Web services or remoting, then you can even register the attached XmlDataDocument instance as the property value (serialization would break if an object is attached to DataSet's ExtendedProperty). Otherwise, an alternative would be to construct an XmlDocument from the return of GetXml, but then you should make all changes through the DataSet.

Q I have a two-year-old Web app that has a standard menu header used by all pages. It's invoked in each ASP page, like so:

#include file="../Include/UDBMenuAccess.asp"

I'm now adding a new .aspx page to the site, and I want to include this menu. However, my new page either won't recognize the include, or produces errors later in the code. Isn't it possible to include an .asp page in an .aspx file? What's the workaround?

Q I have a two-year-old Web app that has a standard menu header used by all pages. It's invoked in each ASP page, like so:

#include file="../Include/UDBMenuAccess.asp"

I'm now adding a new .aspx page to the site, and I want to include this menu. However, my new page either won't recognize the include, or produces errors later in the code. Isn't it possible to include an .asp page in an .aspx file? What's the workaround?

A Convert the old include file to an .ascx file and then include that file in your .aspx page. Includes haven't gone away; they are simply called custom controls now and they are quite powerful. Bear in mind that these controls must be written in the same language as your project. If you choose to go the C# route and have some old Visual Basic® includes, they will need to be converted to C#. See an example, the copy control, in Figure 1.

A Convert the old include file to an .ascx file and then include that file in your .aspx page. Includes haven't gone away; they are simply called custom controls now and they are quite powerful. Bear in mind that these controls must be written in the same language as your project. If you choose to go the C# route and have some old Visual Basic® includes, they will need to be converted to C#. See an example, the copy control, in Figure 1.

Figure 1 A Custom Control

<%@ Control Language="c#" AutoEventWireup="false" Codebehind="cr.ascx.cs" 
Inherits="thisSite.includes.cr_B" 
TargetSchema="https://schemas.microsoft.com/intellisense/ie5"%>
<img height="16" src="https://thisSite/images/bar2003.gif" width="748" 
border="0"><br>
<table class="betaBorder" width="748" bgColor="#eef1f4">
  <tr>
    <td class="CenterSmall">© thisSite 2003 - 
    <a tabIndex="40" href="https:// thisSite /default.aspx"> Home</a> -
    <a tabIndex="41" href="https://thisSite/info/contacts.aspx"
    target="_parent"> Contacts</a> - 
    <a tabIndex="42" 
    href="https://thisSite/info/disclaimer.aspx" target="_blank">
    Disclaimer</a>
    </td>
  </tr>
</table>

Now in the .aspx you should include it in the following manner. At the top of the .aspx page declare it using:

<%@ Register TagPrefix="thisSite" TagName="copyright"
 src="includes/cr.ascx" %>

Then when you want to place your control in your page, use the following element to call it:

<thisSite:copyright id="copyright1" runat="server">
</thisSite:copyright>

Q I have a piece of code that looks like this:

SqlConnection sqlConnection;
CloseConnection()
{
    sqlConnection.Close();
    sqlConnection.Dispose();
    sqlConnection = null; 
}

Does calling Dispose on the SqlConnection object remove it from the connection pool? Also, must I call both Dispose and Close? I am using the .NET Framework 1.1.

Q I have a piece of code that looks like this:

SqlConnection sqlConnection;
CloseConnection()
{
    sqlConnection.Close();
    sqlConnection.Dispose();
    sqlConnection = null; 
}

Does calling Dispose on the SqlConnection object remove it from the connection pool? Also, must I call both Dispose and Close? I am using the .NET Framework 1.1.

I read an article which said that calling Dispose in the .NET Framework 1.0 removes the connection from the pool, whereas the .NET Framework 1.1 does not. Is this true?

A Dispose does not remove the connection from the pool, it puts it back into the pool if that has not already been done. For the .NET Framework versions 1.0 and 1.1, you can basically consider Close and Dispose to be equivalent.

A Dispose does not remove the connection from the pool, it puts it back into the pool if that has not already been done. For the .NET Framework versions 1.0 and 1.1, you can basically consider Close and Dispose to be equivalent.

In response to your other question, Dispose is the same for .NET Framework versions 1.0 and 1.1. Always Close or Dispose a SqlConnection and you will avoid many SqlConnection finalizer/garbage collection-based problems.

If you want to be even smarter, you can also use the using keyword, as shown in the following code:

using ( SqlConnection conn = new SqlConnection(CONNECT_STRING) )
{
    try
    {
        conn.Open();
        // Use conn in here...
    }
    catch ( SqlException sqlEX )
    {
        // Log errors here...
    }
} // Once the scope of this brace is complete, Dispose will be 
  // called on SqlConnection object.

For more programming best practices for SqlConnection, see Data Access Application Block for .NET.

Q Is there a built-in way of extracting XML schema namespace URI information from an XSD? Or do I need to parse through a schema file manually? I want to ask a user to select a whole bunch of XSD files and load the schema namespace URIs of all the files automatically without asking that user for further input.

Q Is there a built-in way of extracting XML schema namespace URI information from an XSD? Or do I need to parse through a schema file manually? I want to ask a user to select a whole bunch of XSD files and load the schema namespace URIs of all the files automatically without asking that user for further input.

A To achieve what you're asking, you have at least three choices. First, you can load the schema into a DOM and use XPath to select the /xs:schema/@targetNamespace node (where xs maps to https://www.w3.org/2001/XMLSchema). Second, you can load the schema into a schema object model (SOM) by calling System.Xml.Schema.XmlSchema.Read and read the TargetNamespace property. Your final choice is to use an XmlTextReader to parse the first element in the schema, check that it is {https://www.w3.org/2001/XMLSchema}schema, and read the targetNamespace property.

A To achieve what you're asking, you have at least three choices. First, you can load the schema into a DOM and use XPath to select the /xs:schema/@targetNamespace node (where xs maps to https://www.w3.org/2001/XMLSchema). Second, you can load the schema into a schema object model (SOM) by calling System.Xml.Schema.XmlSchema.Read and read the TargetNamespace property. Your final choice is to use an XmlTextReader to parse the first element in the schema, check that it is {https://www.w3.org/2001/XMLSchema}schema, and read the targetNamespace property.

All of these options are pretty simple to implement. However, the last one is by far the most efficient in terms of both space and time, since the first and second options require performing the third option anyway, plus a lot more overhead.

Q How does System.Data.SqlClient handle semicolon-delimited statements in a batch? Such batches appear to work just fine; however, I haven't seen any documentation on the semicolon in the .NET Framework documents.

Q How does System.Data.SqlClient handle semicolon-delimited statements in a batch? Such batches appear to work just fine; however, I haven't seen any documentation on the semicolon in the .NET Framework documents.

Is a normally formatted code block like this

DECLARE @val int
SET @val=10

UPDATE dbo.Foo
SET val=@val
IF (@@ERROR <> 0) GOTO EXIT_SCRIPT

SET @val=20
UPDATE b
SET b.val=@val
FROM dbo.Foo AS f INNER JOIN dbo.Bar AS b ON f.id = b.id

IF (@@ERROR <> 0) GOTO EXIT_SCRIPT

EXIT_SCRIPT:

processed differently than this?

DECLARE @val int;SET @val=10;UPDATE dbo.Foo SET val=@val;IF (@@ERROR <> 0)
GOTO EXIT_SCRIPT;SET @val=20;UPDATE b SET b.val=@val FROM dbo.Foo AS f
INNER JOIN dbo.Bar AS b ON f.id = b.id;IF (@@ERROR <> 0)
GOTO EXIT_SCRIPT;EXIT_SCRIPT:;

Does it make any difference what kind of statements are called in such a batch (transaction statements, stored procedures)?

A SqlClient passes all the statements directly to SQL Server™ without making any modifications on the client side. SQL Server accepts semicolons as valid delimiters, so it just works. As far as SQL Server is concerned, there is no difference between the two batches.

A SqlClient passes all the statements directly to SQL Server™ without making any modifications on the client side. SQL Server accepts semicolons as valid delimiters, so it just works. As far as SQL Server is concerned, there is no difference between the two batches.

Q I have a question regarding ADO.NET relationships and deleted rows. When I do something like this

parentRow.GetChildRows( "relationship name" ) ;

I get no DataRows returned where the RowState is Deleted.

Q I have a question regarding ADO.NET relationships and deleted rows. When I do something like this

parentRow.GetChildRows( "relationship name" ) ;

I get no DataRows returned where the RowState is Deleted.

However, the problem is that I really need that information. I need to be able to get all the related rows that have been added, modified, or deleted. GetChildRows returns only the added and modified rows, but doesn't return any of the deleted ones.

I tried passing the optional DataRowVersion parameter

parentRow.GetChildRows("relationship name", DataRowVersion.Original);

to see if that would return the deleted rows, but it doesn't pass the deleted rows either. How can I accomplish this?

A The second parameter on GetChildRows controls the version of the data you'll receive (current, original, or proposed). It is not a row state (added, modified, deleted, unchanged) filter.

A The second parameter on GetChildRows controls the version of the data you'll receive (current, original, or proposed). It is not a row state (added, modified, deleted, unchanged) filter.

To access the child rows that contain pending changes, you could use DataTable.Select, then create a filter that looks for the desired rows (such as FKColumn = Value) and supply the desired row states to search (Added, ModifiedCurrent, Deleted). There's some sample code shown in Figure 2.

If you don't mind using DataViews, you could also use DataRowView.CreateChildView and set the RowStateFilter accordingly, as shown in the following code:

DataView vueCustomers = ds.Tables["Customers"].DefaultView;
    vueCustomers.Sort = "CustomerID";
DataView vuePendingOrders = 
    vueCustomers[vueCustomers.Find("ALFKI")].CreateChildView
    ("Customers_Orders");
vuePendingOrders.RowStateFilter = DesiredRowStates;
Console.WriteLine("ALFKI has {0} pending modified orders", 
    vuePendingOrders.Count);

Got a question? Send questions and comments to  webqa@microsoft.com.

Thanks to the following Microsoft developers for their technical expertise: Jeff Abrams, Kawarjit Bedi, Jeffrey Brendecke, Lale Divringi, Blaine Dockter, Yves Dolce, Tim Ewald, Michael Hestness, Eric Lippert, Matt Neerincx, Carl Nolan, Thomas Rahm, David Sceppa, Larry Sun, Vinayak Tadas