... until the collector arrives ...

This "blog" is really just a scratchpad of mine. There is not much of general interest here. Most of the content is scribbled down "live" as I discover things I want to remember. I rarely go back to correct mistakes in older entries. You have been warned :)

2004-11-30

IE XML and MSXML

IE has a habit of crashing randomly after certain XML operations fail.  For example, it is not unusual for IE to crash when attempting to apply an invalid XSLT against a large XML file.  The same appears to be true for invalid XSchema validations.  The solution is to close all running instances of IE and try again.  I have seen FrontPage exhibit 'weird' behaviour in these circumstances as well, but not crash (e.g. weird = unable to close a document).

I wrote a short WScript to perform XML validation:

if (WScript.Arguments.length != 1) {
  WScript.Echo("Usage: cscript validator.js ");
  WScript.Quit();
}

var url = WScript.Arguments(0);
var document = new ActiveXObject("Msxml2.DOMDocument.5.0");
if (document.load(url)) {
    WScript.Echo("The file is valid.\n" + url);
} else {
    WScript.Echo(
        "Unable to load the document.\n"
        + document.parseError.reason
        + "\n" + url);
}

When using it, I discovered that MSXML appears to ignore the XML Schema associated with a document when there is a DTD present.

2004-11-26

VS.NET and MSDN Library

Here's a neat trick to fix the "Help is not installed in Visual Studio .Net" problem.  Change the value of the registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.1\Help\0x0409\{some guid}\VS_Docs

from 'Not Supported' to '7.1'.  Black magic, but it works (at least for VS.NET 2003).

MSDE

I've been using sastrong as a decent default password for MSDE installations where security is not terribly important.

2004-11-17

ASP.NET

Server.MapPath resolves paths relative to the current page instead of the application base.  If you want something relative to the application base, use something like Server.MapPath("~/somedir").

GetType() doesn't work for ASPX classes.  Instead of returning the type of your class, it returns the type of some funky ASP.NET wrapper class in a system namespace.

2004-11-16

.NET System.Xml

It is pretty easy to write extension functions for XSLT under .NET.  The following code performs a transformation that uses an extension function:

XslTransform xslt = new XslTransform();
xslt.Load("test.xslt");

XsltArgumentList arguments = new XsltArgumentList();
arguments.AddExtensionObject("urn:x", new Extension());
XPathDocument document = new XPathDocument("test.xml");
XmlTextWriter writer = new XmlTextWriter(Console.Out);
xslt.Transform(document, arguments, writer, null);
writer.Close();

All of the public members of the extension class become available within the template as QNames whose prefix is mapped to the URI passed as the first argument to AddExtensionObject.  The following data types can be used as parameters or the return value:  String, Boolean, Double, XPathNavigator (for result tree fragments), and XPathNodeIterator (for node sets).

SQL Server 2000 XML

The simplest way to generate nested XML from SQL Server is to use the FOR XML AUTO syntax:

SELECT root.version, parent.id, child.name
FROM (SELECT 1 AS version) AS root
JOIN parent ON (1 = 1)
JOIN child ON (child.parent_id = parent.id)
FOR XML AUTO

This will produce output such as:

<root version="1"><parent id="..."><child name="..."/></parent></root>

If you use the FOR XML RAW syntax instead, then one row element will be generated for each result row, e.g.

<row version="1" id="..." name="..."/>

For complete, control of the result set shape, use FOR XML EXPLICIT:

SELECT
  1 AS Tag,
  null as Parent,
  1 as [Root!1!version!hide],
  null AS [Case!2!id],
  null AS [ClaimantData!3!id!hide],
  null AS [ClaimantData!3!first_name],
  null AS [ClaimantData!3!last_name],
  null AS [ClaimantData!3!!xml]
UNION ALL
SELECT
  2 AS Tag,
  1 AS Parent,
  1,
  CaseData.id,
  null,
  null,
  null,
  null
FROM CaseData
UNION ALL
SELECT
  3 AS Tag,
  2 AS Parent,
  1,
  ClaimantData.case_id,
  ClaimantData.id,
  ClaimantData.first_name,
  ClaimantData.last_name,
  ClaimantData.confirmation
  from ClaimantData
JOIN CaseData ON (ClaimantData.case_id = CaseData.id)
ORDER BY 3,4,5
FOR XML EXPLICIT

This last option uses a so-called 'universal table' to define the XML document.  This first two columns assign tag numbers and parent-child relationships, and must be named Tag and Parent.  The remaining columns must contain the join keys and data, and be sorted into the desired document order.  The key and data columns must be named according to the convention ElementName!TagNumber!AttributeName!Directive.  The last two components are optional.  All this is quite ugly, but it does allow finer control of the final product.  Note, for example, how certain columns do not appear in the output (e.g. ClaimantData!3!id!hide) and how columns that contain XML data can be included in place (e.g. ClaimantData!3!!xml).

None of this stuff conforms to the emerging SQL/XML standard which, by all accounts, Microsoft has no intention of supporting.

ASP.NET

Here is a gotcha:  if you attempt to protect the contents of a directory using a web.config file like:

<location path="data">
    <system.web>
      <authorization>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

... it won't work. ASP.NET only respects the configured permissions for files that it serves. Static directories, and most files in them, are served by IIS and must be protected using IIS settings.

2004-11-11

ASP.NET

A nasty gotcha: ASP.NET stores the session identifier as a global cookie.  This has adverse affects upon session state in circumstances such as:

  1. open your app in a browser window and browse to same page that carries session state
  2. open your app in a second browser window and browse to a different page that has noticably different session state
  3. return to the first browser and perform an action that relies upon the session state

You will notice that the first browser window has picked up state from the second.

This problem is not unique to ASP.NET, but affects any system that uses session cookies.  Depending upon the application, it might be safer to carry the session identifier in the URL or as variables on the page.

2004-11-10

ADO.NET and ODBC

There is a way to monitor the ADO.NET connection pool.  Open the administrator applet Performance and add counters from the .Net CLR Data performance object.  There are various SqlClient counters.

In a related note, you can enable ODBC connection pool counters on the ODBC Data Source Administrator applet.  Click on the Connection Pooling tab and use the Enable setting under PerfMon.  I had to exit PerfMon and re-enter it to see the change.

Blog Archive