Long Delay on First Request to ASP.NET 2.0 Application

I have worked several issues recently regarding long delays on the first request to an ASP.NET application. These delays are much longer than typical app domain startups and JIT compiles. To troubleshoot these issues, I get hang dumps of the process to see what's going on. In those dumps, I can see that we are calling the LsaLookupNames2 API and we're waiting on that call. In almost all of the cases, we're waiting on an account lookup for an account named ProcessIdentity.

The source of this is a call we make in webengine.dll during the startup of the application domain. Because the ProcessIdentity account doesn't exist, we sit and wait on name resolution from trusted domains, etc. A workaround is to add a local account called ProcessIdentity to the web server, but many customers don't like that workaround.

We currently have a hotfix in the works for this issue. Once that hotfix is available, I will post information on it. In the meantime, you can use the workaround mentioned above. Please don't contact me or PSS asking for the fix for this. We haven't finished the fix yet and you won't be able to get it, but I thought it was an important enough issue to let you know about it now.

If you have a question, please post a comment here instead of calling PSS.

Thanks!

Jim

Posted 25 October 07 11:00 by jamesche | 22 Comments   
Filed under
Running ASP.NET in a Shared Hosting Environment

I was recently working on an issue with a large international hosting company. This company hosts many websites in a shared hosting environment, and one of their customers had uploaded a page that performed some tasks using ASP.NET that greatly concerned them.

The ASP.NET page allowed the following when it was browsed:

  • Browsing of files in the Windows directory using the System.IO namespace.
  • Browsing of folders in the Program Files directory using the System.IO namespace.
  • Browsing of files in the System32 directory using the System.IO namespace.
  • Output of the OS name and version number using the Environment class.
  • Output of the physical disk path (including one on an external file server) for the website's content using Server.MapPath.
  • Output of the server's local IP address using server variables.

These capabilities are not unique to ASP.NET. Most server-side programming technologies allow for the same functionality. However, my customer was concerned over exposing this much information about his internal environment and he wanted me to do something about it!

As you certainly know, ASP.NET runs inside of the CLR (Common Language Runtime), and because of that, ASP.NET is able to take advantage of the CLR's capabilities. One of those capabilities is a powerful security architecture that makes it easy to define the capabilities of a .NET Framework application.

By default, ASP.NET runs under full trust. That means that an ASP.NET application has a lot of powerful functionality, some of which might not be desirable in a shared hosting environment. The solution to my customer's problem was to change ASP.NET to run under medium trust. When running under medium trust, an ASP.NET application runs in a much more restricted environment. Among other restrictions, running under medium trust prevents an ASP.NET application from accessing any directories outside of the application's own directory structure.

To run ASP.NET under medium trust, a simple change is made to the default web.config file located in the Microsoft.NET\Framework\v2.0.50727\Config folder. The specific change you should make is in the following section.

<location allowOverride="true"> 
<system.web> 
  <securityPolicy> 
    <trustLevel name="Full" policyFile="internal"/> 
    <trustLevel name="High"
        policyFile="web_hightrust.config"/> 
    <trustLevel name="Medium" 
        policyFile="web_mediumtrust.config"/> 
    <trustLevel name="Low"
        policyFile="web_lowtrust.config"/> 
    <trustLevel name="Minimal" 
        policyFile="web_minimaltrust.config"/> 
   </securityPolicy> 
   <trust level="Full" originUrl=""/> 
</system.web> 
</location>

The first change you'll want to make is to set the allowOverride attribute to false. By making that change, you prevent an ASP.NET developer from overriding your change in his or her own web.config file. After making that change, you'll need to change the trust level from Full to Medium. Once you'd made those changes, the new section looks like the following. Changes appear in bold text.

<location allowOverride="false"
<system.web> 
  <securityPolicy> 
    <trustLevel name="Full" policyFile="internal"/> 
    <trustLevel name="High"
        policyFile="web_hightrust.config"/> 
    <trustLevel name="Medium" 
        policyFile="web_mediumtrust.config"/> 
    <trustLevel name="Low"
        policyFile="web_lowtrust.config"/> 
    <trustLevel name="Minimal" 
        policyFile="web_minimaltrust.config"/> 
   </securityPolicy> 
   <trust level="Medium" originUrl=""/> 
</system.web> 
</location>

Notice that the <trustLevel> element defines which configuration file contains the specific configuration settings for the specific trust level. The configuration for medium trust is contained a file called web_mediumtrust.config which is also located in the Config folder.

You can modify the web_mediumtrust.config file if you want more precise control over your security model. For example, my customer was concerned that ASP.NET developers were able to use the Environment class to access the OS name and the computer's netbios name. I was able to resolve that for him by making a modification to the ASP.NET permission set in the web_mediumtrust.config file.

<IPermission
     class="EnvironmentPermission"
     version="1"
     Read="TEMP;TMP;USERNAME;OS;COMPUTERNAME"
/>

By removing OS and COMPUTERNAME from the Read attribute of this element, I was able to prevent ASP.NET developers from accessing the information that concerned my customer.

You can read more about other limitations that this method imposes along with many more details in the following MSDN article.

http://msdn2.microsoft.com/en-us/library/ms998341.aspx

If you're interested in performing these same steps in ASP.NET 1.1, you can get details on doing so by watching the following video.

http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20050317ASPNETSS/manifest.xml

Jim

Posted 30 September 07 04:04 by jamesche | 11 Comments   
Filed under
Automating aspnet_compiler in Visual Web Developer

Visual Studio has a cool user interface for publishing a website using the Publish Web Site dialog, accessible by selecting Build, Publish Web Site. You can use this dialog to pre-compile your website and avoid having to deploy source code.

Visual Web Developer Express doesn't offer this dialog, but because the Publish Web Site dialog is just a front-end for aspnet_compiler.exe, you can use aspnet_compiler.exe from a command prompt to accomplish the same thing if you are a VWD user. While using aspnet_compiler.exe from a command prompt gives you the same functionality, using a menu option is a lot more user-friendly and avoids possibly typos that can be frustrating.

In this post, I'm going to show you how you can add some menu options to VWD that will automate the user of aspnet_compiler. It won't give you the same flexibility and convenience you get with the full-blown Visual Studio, but it will come darn close.

Note: While I will show these steps in Visual Web Developer 2005 Express Edition, you can use the same steps for Visual Web Developer 2008 Express Edition.

To add the new menu item, I'll use the External Tools option on the Tools menu in VWD. (This menu option is also available in Visual Studio.) Using the External Tools dialog, you can add menu items that will execute external applications, and you can also control command line arguments that are passed to your external application and more.

Note: I also explain how to do this in my book, The Expression Web Developer's Guide to ASP.NET 3.5.

We'll create two menu items; one for pre-compiling an updatable application and another for a non-updatable application.

  1. Launch Visual Web Developer Express.
  2. Select Tools, External Tools to display the External Tools dialog.
  3. In the Title box, enter Pre-&Compile (non-updatable).
  4. Click the browse button next to the Command box and browse to aspnet_compiler.exe located in c:\Windows\Microsoft.NET\Framework\v2.0.50727.
  5. Click Open to add the command line for aspnet_compiler.exe.

Now that you've got the correct command line for the aspnet_compiler.exe, it's time to add the arguments that will correctly pre-compile your application. This is where you'll see the true power of the External Tools dialog.

  1. Type -p " in the Arguments box. (That's an opening double-quote after the p.)
  2. Click the right-facing arrow next to the Arguments box and select Project Directory.
  3. Add a trailing double-quote to the Arguments box.
  4. Press the spacebar to add a space at the end of the existing arguments.
  5. Type -v / " after the space you just entered.
  6. Click the right-facing arrow next to the Arguments box and select Project Directory.
  7. Type \..\CompiledApp" after the existing arguments.

At this point, the Arguments box should contain the following:

-p "$(ProjectDir)" -v / "$(ProjectDir)\..\CompiledApp"

Now check the Close on Exit checkbox and click OK to add the new command to your Tools menu.

You can create another menu item that will compile the application and allow it to be updated by creating another entry using Pre-Co&mpile (updatable) as the Title and by appending -u to the arguments.

After you complete these steps, your pre-compiled application will be saved at the same level as your application's folder. For example, if your website exists in the c:\MyWebsites\WebApplication1, the pre-compiled application will be saved to c:\MyWebsites\CompiledApp. If that folder structure doesn't suit you, you can alter the steps above for your own purposes.

Posted 27 September 07 02:39 by jamesche | 61 Comments   
Filed under ,
ASP.NET Version Madness

With the impending release of Visual Studio 2008 and Visual Web Developer 2008, along with the .NET Framework 3.5, there is a bit of confusion around version numbers for ASP.NET. Before I get too far into this, let me just say right now that this post has little hope for clarifying things too much, but at least you won't feel so alone in your confusion.

If you've already installed one of the betas of the 3.5 Framework, you may have noticed that the C:\Windows\Microsoft.NET\Framework\v3.5 directory doesn't contain all of the files you would normally see in a .NET Framework release. In fact, the .NET Framework 3.5 is not a full release like version 2.0 was, or even like 1.1 was for that matter. Instead, version 3.5 kind of sits on top of version 2.0 and adds new features (significant new features) to the existing Framework.

How exactly does the 3.5 version affect ASP.NET developers? You'll get new features (like the AJAX Extensions built-in and LINQ features) and you'll get some fixes that we rolled up into the 3.5 Framework. Technically, however, you don't have a new version of ASP.NET. In fact, if you look at a standard ASP.NET error message after installing the 3.5 Framework, you'll see the ASP.NET version reported as 2.0.50727.xxxx.

Here's a bulleted list of some facts that apply after an install of the 3.5 Framework that may not seem intuitive:

  • You won't find ASP.NET 3.5 listed in the ASP.NET configuration dialogs for IIS. Application pools will still be configured to run ASP.NET 2.0.50727.
  • If you need to run aspnet_regiis, aspnet_compiler, etc., you'll still run them from the C:\Windows\Microsoft.NET\Framework\v2.0.50727 folder.
  • In order to use AJAX Extensions and the new LinqDataSource control in Visual Studio or Visual Web Developer 2008, you'll need to configure your project to target the .NET Framework 3.5. (See the docs that ship with your respective product for details.)
  • ASP.NET error pages (non-custom) will still report the ASP.NET version as v2.0.50727.xxxx.
  • Script maps in IIS will still be mapped to the 2.0.50727.xxxx version of the aspnet_isapi.dll.

With that in mind, you're probably thinking that we will continue to refer to ASP.NET as ASP.NET 2.0 after Visual Studio 2008 and Visual Web Developer 2008 release, right? Wrong! The official name for ASP.NET will be "ASP.NET in the .NET Framework 3.5", but the shorthand name is simply ASP.NET 3.5. But don't be confused. ASP.NET 3.5 is really ASP.NET 2.0 with the .NET Framework 3.5 installed running ASP.NET 2.0 binaries, even if your ASP.NET project in Visual Studio is targeting the .NET Framework 3.5. :)

Hopefully that clears up some of the confusion for ASP.NET developers. If it doesn't, there's always therapy.

Jim

 

Posted 25 September 07 04:22 by jamesche | 8 Comments   
Filed under ,
Why don't my .NET Framework patches install?

I recently worked an issue with a customer who was rolling out some patches to over 50,000 computers across his enterprise using SMS. SMS reported that the patches successfully installed on all workstations, but my customer noticed a strange anomoly that he couldn't explain. Even though SMS reported a successful installation on all of his workstations, it also reported many of these same workstations as unpatched on successive scans. Something was obviously awry.

Upon investigation, we found a log file in the customer's temp directory that contained the following:

[2007-09-22 01:00:00] ProcessFiles completed.
[2007-09-22 01:00:06] PatchExec: Unhandled Exception Microsoft.WindowsInstaller.InstallerException: The configuration data for this product is corrupt. Contact your support personnel. 
    at Microsoft.WindowsInstaller.Installer.get_Products() 
    at Microsoft.DDPatch.PatchInstallation.ApplyPatchToInstalledProducts(String mspFile, String target, TargetProduct[] targetProducts, Boolean quiet, String logfile, String& lastPatchedProductName) 
    at Microsoft.DDPatch.PatchInstallation.Install(String targetProduct, Boolean quiet, String logfile) 
    at Microsoft.DDPatch.PatchExec.Main(String[] args)
[2007-09-22 01:00:15] Process returned: 0

This sure doesn't look right. Obviously something didn't go well during the patch installation, but the return code we see here is 0. No wonder SMS believed that the patch successfully installed.

What happened? This particular patch (and some other .NET Framework patches) consists of a Windows Installer patch file (a .msp file) along with some wrappers around some APIs for the Windows Installer. These wrappers provide, among other things, support for rollback and for proper installation of the patch. In this particular case, one wrapper called an API that enumerated products installed by the Windows Installer. That API enumerated the HKEY_CLASSES_ROOT/Installer/Products registry key which contains a GUID for each product that's installed, but in my customer's case, it also contained some textual string values that were written to it by a bad installer from a third-party company.

When the API encountered this bad registry key, it returned an error code to our wrapper. Our wrapper then wrote out the failure to the log file and returned 0 because it had successfully done its job and logged the failure. Unfortunately, the other wrapper got the return code of 0 and believed that the install was successful.

It's worth pointing out that this is an extremely uncommon scenario. The keys written to the HKEY_CLASSES_ROOT/Installer/Products registry key should be added using the Windows Installer API. The Windows Installer API will create valid GUID keys and all will be fine. However, not all installation packages play by the rules, and in this case, we got bit.

WARNING: If you encounter a problem like this, it's important that you not just extract the .msp file out of the patch and install it manually. If you do that, you'll lose the ability to fully roll back the patch. Instead, you should try and locate the offending registry key and remove it.

In the long term, you won't have to worry about this. We've fixed this problem in our wrappers in order to provide a more fail-safe installation experience. The new wrappers should be incorporated into our .NET Framework patches soon.

 

 

Posted 25 September 07 03:43 by jamesche | 1 Comments   
Filed under ,
Visual Studio 2008 Beta 2 Available - Now with VWD 2008

We recently announced the RTW of Visual Studio 2008 beta 2. What you might not know is that beta 2 also introduces the new Visual Web Developer Express Edition 2008. ASP.NET developers should be pretty excited about the new features, and this product will be available free once it RTMs.

You can download the beta 2 build of VWD 2008 from the following URL:

 http://msdn2.microsoft.com/en-us/express/future/bb421473.aspx

If you're new to ASP.NET and want a great introduction to architecture and building web applications using VWD 2008 without a focus on writing a lot of server-side code, you might want to pre-order my book, The Expression Web Developer's Guide to ASP.NET 3.5. While the title does mention Expression Web, this isn't an Expression Web book. My publisher wanted to target Expression Web users because many of them are feeling the push to ASP.NET and we wanted to give them a strong foundation book.

You can pre-order my book on Amazon right now.

Jim

 

Posted 29 July 07 09:44 by jamesche | 0 Comments   
Filed under ,
Get Hotfixes Without Calling PSS

You can now get a hotfix from Microsoft without having to call PSS! Just browse the the following site.

https://support.microsoft.com/contactus2/emailcontact.aspx?scid=sw;en;1410&WS=hotfix

 

When you get there, enter the requested information and we'll send the hotfix to you automatically.

 

Jim

 

Posted 27 July 07 09:40 by jamesche | 4 Comments   
Filed under
Please listen carefully as our menus have changed.

I recently had to call Samsung customer service due to a broken TV set. (It's actually a very long story that involved many calls over a 2-month period, but I won't bore you.) Shortly after that debacle, my Xbox went belly up with the dreaded three-red-light syndrome. That prompted a call to Microsoft Xbox support, and despite what many Microsoft outsiders think, Microsoft employees have no special access to such assistance. Both of these experiences required me to listen to a long menu of choices (and for some reason, all of these services have menus that have "recently changed" so you are encouraged to "listen carefully" to the entire, drawn out thing.)

Wouldn't it be nice if you had a way to look up a company's number along with the "secret" codes to punch in to get directly to a real, live human being? If only there were a massive network with information such as this that any person with a computer could access. It just so happens that there is just such a thing! It's called gethuman, and it includes a database of hundreds of companies and how to get straight to a real person. Very cool!

 

Posted 09 March 07 11:05 by jamesche | 1 Comments   
Filed under
WPF Provides the Best of Times

New York Times publisher Pinchy Suzberger recently told Haaretz Daily Newspaper Israel, "I don't know if we will be printing in five years, and you know what, I don't care." My dad was in the newspaper business for many decades and worked for a few very large papers. I have a little experience with the publishers of these papers, and I wouldn't prop them up as technical visionaries, but in this case, Pinchy might just be right!

If you haven't already checked out the beta of the Times Reader, you should. It uses Windows Presentation Foundation (WPF) to display the Times in a very readable format. WPF is part of the 3.0 version of the .NET Framework, and it's darned impressive!

When you install the Times Reader on Windows XP SP2, you'll have to install the .NET Framework 3.0 as well. If you're on Vista, you're set and the download will be small. When you run the Times Reader, it downloads all of the content to your machine, so you can read offline if you want. However, if you stay online, the Times Reader will run in your system tray and keep your news updated on the fly.

While the Times Reader is in beta, you'll be able to read the paper free of charge.

Posted 09 March 07 10:24 by jamesche | 0 Comments   
Filed under
Free VWD and SQL Server 2005 Express Hosting (For 30 Days)

If you're just getting around to checking out Visual Web Developer (whether as part of Visual Studio or by using the free Visual Web Developer Express Edition,) you might want to test out your application in a real-world hosting environment. Then again, most developers don't ever test anything, so why bother? :)

Assuming you do want to test things out without having to pay for ASP.NET 2.0 hosting, you can use Microsoft's VWDHosting.NET site to get a free Visual Web Developer and SQL Server 2005 Express hosting account good for 30 days. You'll get 50MB of disk space and 30MB of database space as well. This is a great way for new ASP.NET developers to test out how all of this works in a real-world hosting environment.

You can sign up right here.

Posted 08 March 07 02:52 by jamesche | 0 Comments   
Filed under
Love, Hate, and Barenaked Ladies

I hate DRM. Absolutely hate it. I love Barenaked Ladies. (It's a music group, Mom. I'm not opening any closets.) Barenaked Ladies have always been great about making their music available for download without being burdened by DRM. A buddy at work recently pointed me to this article regarding Barenaked Ladies's latest album, Barenaked Ladies are Men, which is available FREE right now. The bad news? I just bought this album a few days ago, but you can still take advantage of this great deal on great music. Unfortunately, you'll have to wait until Aimie Street (the provider of the download) gets their site back up and running. (Maybe they should be using Windows Server 2003 and ASP.NET instead of the free OS, free web server, and PHP.)

This is just one of the cool ways you can enjoy Barenaked Ladies. If you visit their bootleg web site, you can download concert shows they've done and enjoy much more of this great group. Albums are affordable and high quality.

Lastly, you can join eMusic and get free MP3s as you try them out. If you like it, pay a little and get more non-DRM music. If you don't like it, cancel and keep the music you already have. eMusic has a lot of indie music (which is great,) but they're also starting to gain ground in the mainstream music area. Of course, bands like Barenaked Ladies who want people to actually buy their music are available on eMusic.

Thank goodness for an 80GB iPod. ;)

Posted 06 March 07 11:50 by jamesche | 1 Comments   
Filed under
March CTP of Orcas Has Arrived

A short while back, I blogged about the great new features in Orcas that ASP.NET developers will enjoy thanks to the incorporation of the Expression Web designer into Visual Studio. At that time, these features were set to debut in the February CTP version of Orcas which was slated to release in March. In our great wisdom, we've renamed that CTP to the March CTP, and you can get it right now by visiting the Microsoft download site.

I should clarify that statement. You can start downloading it right now, but because it comes in a set of many very large files, you'll be downloading for a very long time. So go ahead, kick off your download, run off and have lunch, dinner, a little nap, a good night's sleep, and you'll be about halfway to experiencing the next evolution in ASP.NET development. (Yeah, there's plenty for you old-school Windows developers, too!)

Speaking of ASP.NET, you should know that Orcas uses version 2.0 of ASP.NET. We aren't shipping a new version of ASP.NET with the next version of Visual Studio, so don't worry about going through those growing pains all over again.

Incidentally, I am working on a book right now that will focus on teaching the ins and outs of the new designer in Orcas. It will be targeted primarily at web designers who aren't interested in getting deep into ASP.NET. Even so, the book will walk you through the development of an ASP.NET application from start to finish in order to delve into all of the great new features that Orcas brings to web design. If you want to keep up to date with my book, check out my public web site.

 

Posted 01 March 07 11:21 by jamesche | 0 Comments   
Filed under ,
Getting to the Root Cause of SqlExceptions

It's pretty common for me to work cases where something bad happens when an ASP.NET application is accessing a database. The nature of my job dictates that troubleshooting on these applications is most often performed in a production environment via post mortem debugging. Fortunately, our toolset for doing that kind of work is really great.

If you aren't familiar with how to load up a dump in Windbg, set up symbols, etc., check out my post on that topic.

Finding out exactly what errors occurred when hitting a database is easy to do, but it's time consuming. Let's have a look at a particular SqlException that occurred when accessing a database.

0:000> !do 106fd670
Name: System.Data.SqlClient.SqlException
MethodTable 0x0343232c
EEClass 0x034ffef4
Size 68(0x44) bytes
GC Generation: 0
mdToken: 0x020001c4 (c:\windows\assembly\gac\system.data\1.0.5000.0__b77a5c561934e089\system.data.dll)
FieldDesc*: 0x03432228
MT Field Offset Type Attr Value Name
0x79b96824 0x400001d 0x4 CLASS instance 0x00000000 _className
0x79b96824 0x400001e 0x8 CLASS instance 0x00000000 _exceptionMethod
0x79b96824 0x400001f 0xc CLASS instance 0x00000000 _exceptionMethodString
0x79b96824 0x4000020 0x10 CLASS instance 0x1c2ef88c _message
0x79b96824 0x4000021 0x14 CLASS instance 0x00000000 _innerException
0x79b96824 0x4000022 0x18 CLASS instance 0x00000000 _helpURL
0x79b96824 0x4000023 0x1c CLASS instance 0x106fd8c8 _stackTrace
0x79b96824 0x4000024 0x20 CLASS instance 0x00000000 _stackTraceString
0x79b96824 0x4000025 0x24 CLASS instance 0x00000000 _remoteStackTraceString
0x79b96824 0x4000026 0x2c System.Int32 instance 0 _remoteStackIndex
0x79b96824 0x4000027 0x30 System.Int32 instance -2146232060 _HResult
0x79b96824 0x4000028 0x28 CLASS instance 0x00000000 _source
0x79b96824 0x4000029 0x34 System.Int32 instance 0 _xptrs
0x79b96824 0x400002a 0x38 System.Int32 instance -532459699 _xcode
0x0343232c 0x4000fb6 0x3c CLASS instance 0x106fd6b4 _errors

If you look at the _message field, you'll see this:

0:000> !do 0x1c2ef88c
Name: System.String
MethodTable 0x79b94638
EEClass 0x79b94984
Size 44(0x2c) bytes
GC Generation: 2
mdToken: 0x0200000f (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)
String: System error.

This is a generic error that tells you absolutely nothing. Essentially, it's telling you that there was an error. The key to finding out what that error actually was is the _errors field in the exception. (It's the last field listed in the exception above.) The _errors field is a SqlErrorsCollection as shown here:

0:000> !do 0x106fd6b4
Name: System.Data.SqlClient.SqlErrorCollection
MethodTable 0x0343249c
EEClass 0x034fff58
Size 12(0xc) bytes
GC Generation: 0
mdToken: 0x020001c3 (c:\windows\assembly\gac\system.data\1.0.5000.0__b77a5c561934e089\system.data.dll)
FieldDesc*: 0x034323bc
MT Field Offset Type Attr Value Name
0x0343249c 0x4000fb5 0x4 CLASS instance 0x106fd6c0 errors

The errors field here is an ArrayList of SqlError objects. Let's have a look at that.

0:000> !do 0x106fd6c0
Name: System.Collections.ArrayList
MethodTable 0x79ba2ee4
EEClass 0x79ba3020
Size 24(0x18) bytes
GC Generation: 0
mdToken: 0x02000100 (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)
FieldDesc*: 0x79ba3084
MT Field Offset Type Attr Value Name
0x79ba2ee4 0x4000362 0x4 CLASS instance 0x106fd6d8 _items
0x79ba2ee4 0x4000363 0xc System.Int32 instance 1 _size
0x79ba2ee4 0x4000364 0x10 System.Int32 instance 1 _version
0x79ba2ee4 0x4000365 0x8 CLASS instance 0x00000000 _syncRoot

Now, to get to the actual errors in that ArrayList, you need to dump the _items field, and to do that, you need to use the -v switch as follows:

0:000> !do -v 0x106fd6d8
Name: System.Object[]
MethodTable 0x020a209c
EEClass 0x020a2018
Size 80(0x50) bytes
GC Generation: 0
Array: Rank 1, Type CLASS
Element Type: System.Object
Content: 16 items
------ Will only dump out valid managed objects ----
Address MT Class Name
0x106fd780 0x0343263c System.Data.SqlClient.SqlError
----------

Alright, now we're getting somewhere. We have the specific SqlError instance that is associated with the SqlException that occurred. Let's dump that.

0:000> !do 0x106fd780
Name: System.Data.SqlClient.SqlError
MethodTable 0x0343263c
EEClass 0x03710010
Size 36(0x24) bytes
GC Generation: 0
mdToken: 0x020001c2 (c:\windows\assembly\gac\system.data\1.0.5000.0__b77a5c561934e089\system.data.dll)
FieldDesc*: 0x03432520
MT Field Offset Type Attr Value Name
0x0343263c 0x4000fad 0x4 CLASS instance 0x182f7d34 source
0x0343263c 0x4000fae 0x14 System.Int32 instance -2 number
0x0343263c 0x4000faf 0x1c System.Byte instance 0 state
0x0343263c 0x4000fb0 0x1d System.Byte instance 10 errorClass
0x0343263c 0x4000fb1 0x8 CLASS instance 0x1c2eb298 server
0x0343263c 0x4000fb2 0xc CLASS instance 0x14384218 message
0x0343263c 0x4000fb3 0x10 CLASS instance 0x106fd73c procedure
0x0343263c 0x4000fb4 0x18 System.Int32 instance 0 lineNumber

Now we have something we can use. We have the server, the error message, and the procedure. If we look at the error message, here's what we see:

0:000> !do 0x14384218
Name: System.String
MethodTable 0x79b94638
EEClass 0x79b94984
Size 248(0xf8) bytes
GC Generation: 2
mdToken: 0x0200000f (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)
String: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

That's a heck of a lot more useful than "System error," but it was a lot of work! You can save yourself some effort by scripting this. Each dump of an object contains an offset for each field. The field exists at that offset. In the SqlError above, the message field is at an offset of 0xc.

0x0343263c 0x4000fb2 0xc CLASS instance 0x14384218 message

Therefore, you can get the message of this exception by dumping the address located at an offset of 0xc from the address of the SqlError itself. You can do that like this:

0:000> !do poi(0x106fd780+c)
Name: System.String
MethodTable 0x79b94638
EEClass 0x79b94984
Size 248(0xf8) bytes
GC Generation: 2
mdToken: 0x0200000f (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)
String: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

Look familiar? This is an important concept because it means that you can take the original SqlException object and follow the trail all the way to the actual error message.

What if you want to just dump out details of all SQL errors that are on the heap? That's easy to, and the easiest way to do it is to write a script that you can then run inside of Windbg. What appears below is just such a script:

.logopen ${$CurrentDumpPath}\SqlErrors.txt
.printf "Dumping all SqlError objects on the heap..."
.printf "\n\n"

.foreach (se {!dumpheap -short -mt 0x0343263c})
{

.echo "=============================================================="
.echo "SqlError : ${se}"
.printf "Server Instance: "
du poi(${se}+8)+c
.printf "Procedure: "
du poi(${se}+10)+c
.printf "Error Message: "
du poi(${se}+c)+c
.printf "\n\n"

}
.logclose

The first thing this script does is open a log file in the location where the dump file exists. That way, you'll automatically have a text file containing all of the errors. It then uses a .foreach token to loop through all of the System.Data.SqlClient.SqlError objects. (In other words, all objects in MethodTable 0x0343263c.) For each one of those suckers, it dumps out the different fields using the offsets we looked at before.

All of these fields are text values, and text in the Framework is represented using Unicode. That's why I use the du command (dump Unicode) to dump that out. You'll also notice that each one is dumping out the address+c. Unicode strings are at an offset of 12 from the address of the string, so you have to dump out the string starting at address+c.

If you save the above into a text file and then copy it into the same folder where the debuggers are installed, you can then run it from within Windbg like this:

$><dumpsqlerrors.txt

That will give you output similar to this:

0:000> $><dumpsqlerrors.txt
Opened log file 'C:\Users\jamesche\Desktop\SqlErrors.txt'
Dumping all SqlError objects on the heap...

==============================================================
SqlError : 0x106fd780
Server Instance: 1c2eb2a4 "DBASESVR"
Procedure: 106fd748 "ConnectionRead (recv())."
Error Message: 14384224 "Timeout expired. The timeout pe"
14384264 "riod elapsed prior to completion"
143842a4 " of the operation or the server "
143842e4 "is not responding."


==============================================================
SqlError : 0x10721d38
Server Instance: 1c2eb2a4 "DBASESVR"
Procedure: 10721d00 "ConnectionRead (recv())."
Error Message: 14384224 "Timeout expired. The timeout pe"
14384264 "riod elapsed prior to completion"
143842a4 " of the operation or the server "
143842e4 "is not responding."


==============================================================
SqlError : 0x185266a8
Server Instance: 1c2eb2a4 "DBASESVR"
Procedure: 18526670 "ConnectionRead (recv())."
Error Message: 14384224 "Timeout expired. The timeout pe"
14384264 "riod elapsed prior to completion"
143842a4 " of the operation or the server "
143842e4 "is not responding."


==============================================================
SqlError : 0x18549968
Server Instance: 18549948 "SQL-01"
Procedure: 1c2d0230 ""
Error Message: 185498d0 "Changed language setting to us_e"
18549910 "nglish."


==============================================================
SqlError : 0x1c42e894
Server Instance: 1c2eb2a4 "DBASESVR"
Procedure: 1c42e85c "ConnectionRead (recv())."
Error Message: 14384224 "Timeout expired. The timeout pe"
14384264 "riod elapsed prior to completion"
143842a4 " of the operation or the server "
143842e4 "is not responding."


==============================================================
SqlError : 0x1c47faa8
Server Instance: 1c2eb2a4 "DBASESVR"
Procedure: 1c47fa70 "ConnectionRead (recv())."
Error Message: 14384224 "Timeout expired. The timeout pe"
14384264 "riod elapsed prior to completion"
143842a4 " of the operation or the server "
143842e4 "is not responding."


Closing open log file C:\Users\jamesche\Desktop\DumpSqlErrors.txt

The layout of the SqlError object isn't static. I wrote this script for ASP.NET 1.1 SP1.

 

Posted 28 February 07 05:18 by jamesche | 1 Comments   
Filed under ,
A Train or a Beast

Expression Web is Microsoft's latest web design tool. It should be no surprise to you that we put a lot of effort into making sure that Expression Web supported the design-time elements of ASP.NET 2.0. Doing so has proven to be a double-edged sword. On the one hand, a lot of ASP.NET developers who have been frustrated by Visual Studio's lackluster designer are excited to have a standards-compliant design tool that supports ASP.NET in the designer. On the other hand, web designers who don't bring a vested interest in ASP.NET to the table quickly begin to feel that something's missing. That "something" is support for writing ASP.NET server-side code, support for using 3rd party controls in the toolbox, etc.

The next version of Visual Studio (code-named "Orcas") will use the designer from Expression Web, so ASP.NET developers will have great new tools inside of Visual Studio. See my earlier post for more information.

When the ramblings of discontent first began over the limited ASP.NET support in Expression Web, I was clinging to the mantra of "designer vs. developer." Expression Web is, after all, a design tool. Therefore, it only makes sense that its development features would be limited. As time has gone by, I've found myself deviating from that position, and it's my love for ASP.NET that is pushing me off of my post.

Expression Web is being adopted (or at least looked at) by a huge number of FrontPage users who are reacting to the warnings that FrontPage is going away. The exodus of FrontPage users is placing a huge number of people smack in front of the ASP.NET train and we have two options available; squash them like pennies or invite them onboard. Unfortunately, the partial implementation of ASP.NET support in Expression Web is turning these early adopters into slivers of copper. (Okay, enough of that analogy.)

Let's be fair. Expression Web is a version 1 product, and features are usually still being fleshed out when version 1 products release. Even so, I think we've missed a real opportunity. One of our shortcomings at Microsoft is that we often don't see the lions chasing us until we feel the warm breath on our neck. In this case, the lion is PHP (coupled with MySQL), and because it's not burdened by a reliance on any particular platform, the lion is flat-out fast. Personally, I think ASP.NET is a much better technology (there's no doubt about it being more feature-rich) and Visual Web Developer makes using ASP.NET easy and cost effective. Even so, many web designers are already using PHP and our goal should be to take very opportunity to move them to a better beast.

What's my point? Primarily, it's to let folks outside of Microsoft know that we do think about such things. After all, you can bet that if an ASP.NET escalation engineer like myself is mulling this over, the product group is way farther down the track. (Geez, there I go with the train analogy again even after I promised to stop. Sorry.) I think that future versions of Expression Web will beef up this feature-set. The release of the next Visual Studio version will also change the landscape because it will be accompanied by a new (and free) release of Visual Web Developer Express and it offers many of the enticing features of Expression Web without any limitations on ASP.NET development.

One thing's for sure; it's a great time to be a web developer!

Neatly Tied Together with a Ribbon
 

My Microsoft roots are in Office. My first job here was supporting Word 6.0. In fact, I remember interviewing for that job the day that Windows 95 released. When the interviewer asked me if I was going to upgrade to Windows 95, I replied that I'd like to, but I couldn't afford to upgrade from 4MB to 8MB of memory because it would cost me $400.

Times sure have changed! Speaking of change, anyone who's looked at the new interface in Office 2007 knows what a radical UI change took place with the current release. (How'd you like that segue?) When I first saw the Office ribbon, my first thought was that we were nuts! I predicted that no one would like it and people would run from it in frustration after spending hours trying to find a simple feature that had been subverted to a big button somewhere on the Ribbon. I was completely wrong. The Ribbon is widely considered user-interface genius now (by many people outside of Microsoft) which clearly illustrates why Microsoft isn't stupid enough to put someone like me in charge of UI design.

I recently listened to the latest edition (as of this writing) of the Windows Weekly podcast.  It featured an interview with Jensen Harris and Jacob Jaffe of the Office 2007 team, and it offered remarkable insight into the development of this radical change in Office. In a particularly amusing passage, Jensen references the common belief that Microsoft screws everything up until version 3.0, and he points out that the Office team built 3 versions of the new user-interface into the development phase.

If you're an Office 2007 user and you are frustrated trying to find a particular feature, the interactive guides on the Office Web site will let you select a feature in the Office 2003 interface and it will then dynamically transition to the Office 2007 interface and show you where that feature or command is located in the new interface. Now that's really cool!

These days, I spend most of my time in Visual Studio and Expression Web. I think it would be very interesting to see how the Ribbon interface could be incorporated into those products to expose existing features and make the interface less cluttered. What do you think?

If you want to read more on the Office interface from the inside, read Jensen's blog.

Posted 28 February 07 10:03 by jamesche | 6 Comments   
Filed under ,

Search

This Blog

Syndication

Page view tracker