Image or ImageButton without ImageUrl Causes HTTP GET for Default Document

I recently worked an issue with a customer who was seeing an error in his application due to a null reference. The error was perplexing because the object that was null was populated on the logon page of the application, but the error was occurring after the user logged in. The object should certainly not have been null. Even more perplexing was the fact that the error could be reproduced readily on a Windows 2003 Server, but the exact same code would never reproduce the problem on the development machine running Windows XP.

In order to troubleshoot this problem, I had the customer get a Time Travel Trace, something we often call an iDNA dump. An iDNA dump is analyzed like any other memory dump, but unlike a traditional user-mode dump that contains the contents of memory at a particular moment in time, an iDNA dump contains a “recording” of user-mode memory over a period of time. It’s kind of like Tivo for the debugger, and in situations where a problem is easily reproduced in short time, it’s a great way to dig into problems.

Using the iDNA dump, I was able to determine that the customer’s code was successfully creating the object that was causing the NullReferenceException. I was also able to determine that the customer never explicitly set the object to null and the only place where we entered the constructor for the object was in the logon page just as the customer said. However, I also found that Page_Load for the logon page was hit in a seemingly random place long after the user logged in.

Next, I got a network trace of the application. In that trace, I saw a GET for “/” which causes the web server to serve up the default document. In my customer’s case, login.aspx was in the default document list, so this GET caused the code in login.aspx to run. In that code, the customer re-initialized an object and stored it in Session. One of the members of that object was the object causing the NullReferenceException, and because the code in login.aspx reset the variable in Session state, it overwrote the valid member object with a null. (Whew! If you had a hard time following all of that, just think how difficult it was to follow it all by setting breakpoints in Windbg!)

The GET for the default document that we were seeing was a big mystery. I could find nothing in the customer’s code that was doing that. I started trying to narrow down where that was coming from. Eventually, we found that it originated with an <input> element in the rendered page that looked like this:

<input type="image" src="" … />

When the browser encountered this element, it performed a GET for the default document. That explained why Page_Load was running for logon.aspx and it explained why we never saw this happen in the browser window. It also explained why the problem didn’t happen on Windows XP. On Windows XP, the customer was using the ASP.NET Development Server. The dev server doesn’t have any concept of a default document list, so when the GET occurred for the default document, it tried to serve default.aspx. Since there wasn’t a default.aspx in the application, the dev server simply served up a directory listing, and because that didn’t actually run any code, it had no impact on the application.

The XHTML that caused this problem was caused by an ASP.NET ImageButton control without an ImageUrl property. If you don’t specify an ImageUrl property for an ImageButton control (or any control that derives from Image), it will cause ASP.NET to render the XHTML you see above, and that will result in the errant GET. As you can tell from reading about my experience, it’s possible for this issue to cause bizarre bugs that are extremely difficult to track down. What’s worse is that these bugs can occur long after the GET that caused them.

We thought about correcting this now in version 2, but we were concerned that any change in the ASP.NET code would break existing applications. Therefore, we have this on the slate to look at for the next version of ASP.NET. In the meantime, always make sure that you specify an ImageUrl property when using a control that derives from Image!

Sessions and Classes

Any programmer knows that logic errors are among the most difficult to troubleshoot. I was recently working with a developer who was encountering an obscure logic bug concerning session variables, and the case raised an interesting (and important) point regarding ASP.NET session state.

Consider the following code in page1.aspx.

public partial class Page1 : System.Web.UI.Page
{

    protected ArrayList al;

    protected void Page_Load(object sender, EventArgs e)
    {
        al = new ArrayList();
        al.Add("Apples");
        al.Add("Oranges");
        al.Add("Bananas");

        Session["list"] = al;

        Response.Redirect("page2.aspx");
    }

}

In this code, I create an ArrayList and then populate it with a few types of fruit. I then save that ArrayList to session and redirect to page2.aspx. Let’s look at several different code examples for page2.aspx and discuss how the session variable created in page1.aspx might be inadvertently changed.

First, consider this code snippet for page2.aspx.

public partial class Page2 : System.Web.UI.Page
{

    protected ArrayList al;
    protected ArrayList al1;
    protected void Page_Load(object sender, EventArgs e)
    {
        al = (ArrayList)Session["list"];
        al[2] = "Kiwi";

        al1 = (ArrayList)Session["list"];
        Response.Write(al1[2]);
    }
}

When page2.aspx loads, what is written to the browser window? You may think that you’d see “Oranges”, but in fact, you’d see “Kiwi” written to the screen. Why? When you store an instance of a reference type (an ArrayList, in this case) in session and then assign a variable to the session variable, what you are doing is saying “Point my variable to the address of the session variable.” Therefore, if you manipulate the member variable that was assigned the session variable, you are also directly manipulating the session variable. In other words, it is not necessary for me to save the modified ArrayList back to session in page2.aspx.

Here’s another snippet of code for page2.aspx.

public partial class Page2 : System.Web.UI.Page
{

    protected ArrayList al;
    protected void Page_Load(object sender, EventArgs e)
    {
        al = (ArrayList)Session["list"];
        al = new ArrayList();

        Response.Write(((ArrayList)Session["list"])[0]);
    }
}

When this code runs, what happens? If you said that you’d see “Apples”, you’re right. Obviously, assigning the al variable to a new instance of ArrayList doesn’t impact the session at all. It simply says “Create a new ArrayList and point al at the new ArrayList instead of to the session variable.”

Now consider the following code for page2.aspx.

public partial class Page2 : System.Web.UI.Page
{

    protected ArrayList al;
    protected ArrayList al2;
    protected void Page_Load(object sender, EventArgs e)
    {
        al = (ArrayList)Session["list"];
        al2 = al;

        al2.Clear();

        Response.Write(((ArrayList)Session["list"])[0]);
    }
}

When this code runs, what do you see? If you said that you’d see an exception, you’re right. This code will produce an ArgumentOutOfRangeException because the session variable, al, and al2 all point to the same object. When you call Clear() on al2, it clears the session variable.

Obviously, this situation doesn’t apply to primitive types such as int or to value types. It also doesn’t apply to string even though string is a reference type. Why? Because the equality operators for string are designed to compare the value of the string and not the string itself. This situation also doesn’t apply to structs because a struct is a value type.

Windows Home Server Data Corruption Fix

Windows Home Server is a great product, but it's been plagued by an infamous bug known as the Data Corruption Bug. Yesterday, the Windows Home Server team released a public beta of Power Pack 1. In addition to some new features and enhancements, Power Pack 1 also fixes the data corruption bug.

I've been involved in small team of internal testers for Power Pack 1. We've been testing this fix for a few months and are confident that the data corruption bug is fixed. In fact, I have been editing files against my Windows Home Server for a while now, and I've not encountered a single occurrence of corruption. (We use an internal tool to test for corruption against our WHS box, so corruption doesn't go unnoticed if it happens.)

You can access the public beta of Power Pack 1 by going to the Windows Home Server Connect site.

Spread the word!

Jim

Third Party ASP.NET Controls and Visual Studio 2008

We've had a few cases recently where customers are using third-party ASP.NET server controls (either written by a third-party company or by the customer) and finding that the controls are not rendering correctly in the Visual Studio 2008 design surface. Most recently, we had an issue where a popular third-party control company's custom property editor was not working correctly in Visual Studio 2008.

In all of these cases, we've investigated the issue and found the problem to be that as the third-party was developing their controls in Visual Studio 2005, they relied on our implementation in the Visual Studio design surface. What they did not anticipate was that our implementation would change with Visual Studio 2008.

The HTML design surface in Visual Studio 2008 is completely new. In order to get a much better representation of page rendering and to add new features, we incorporated the Expression Web design surface into Visual Studio 2008. (That decision also gives you the great new CSS features in Visual Studio 2008.) In almost all cases, controls that were developed against Visual Studio 2005 will work without any problems, but there are cases where the change in the designer causes undesirable behavior for server controls built against Visual Studio 2005. For example, one company found that the hierarchy of the control tree in the Visual Studio 2008 designer differed slightly from Visual Studio 2005. This change caused their control's code to incorrectly parse the page.

It is highly unlikely that you will encounter a problem with any controls in the Visual Studio 2008 designer. If you do, it's very likely that a change will be required in the control itself in order to take into account any implementation changes in the new designer.

Jim

Posted 28 February 08 03:36 by jamesche | 1 Comments   
Filed under ,
New IIS.NET Website for the Windows Server 2008 Launch

We've just launched a completely revamped and overhauled IIS 7 website with new content. Visit the premiere IIS 7 resource at www.iis.net.

Jim

Error When Opening ASP.NET Site on IIS 7 Using Visual Studio 2005

Now that Windows Server 2008 is out the door, we're starting to see more customers using IIS 7. I recently worked on a case where one of our engineers was dealing with a customer using Visual Studio 2005 and IIS 7. He was encountering an error message when attempting to open his ASP.NET 2.0 application running on his local instance of IIS that displayed the following message:

The site is currently configured for use with ASP.NET 1.1 error.

When we checked the application pool in IIS, it was configured correctly for the 2.0 Framework, so what exactly is the problem here?

The problem is that Visual Studio 2005 came out prior to IIS 7. Therefore, it doesn't deal well with the way that the handler mappings work in IIS 7. As it turns out, the .aspx file extension is mapped to both the ASPNET-ISAPI-1.1-PageHandlerFactory (for 1.1) and to the PageHandlerFactory-ISAPI-2.0. When Visual Studio 2005 hits the site to check for ASP.NET, it is fooled into thinking that the site is configured for ASP.NET 1.1 by the mapping for the ASPNET-ISAPI-1.1-PageHandlerFactory.

To correct this problem, you can either click Yes to the dialog shown above (and you'll have to do that each time you open the project) or you can change the order of the handlers mapped to your application.

To change the order of the handlers, follow these steps:

  1. Select your application in the IIS Manager.
  2. Double-click on the Handler Mappings feature as shown below.

handlermappings

  1.   Click the View Ordered List link on the right side of the IIS Manager as shown below.

ordered

  1. Select the PageHandlerFactory-ISAPI-2.0 (or PageHandlerFactory-ISAPI-2.0-64 on 64-bit Windows).
  2. Click the Move Up link as shown below until the handler appears above the ASPNET-ISAPI-1.1-PageHandlerFactory handler.

movehandler

 

You should now be able to open the project without any issues.

By the way, this issue does not occur in Visual Studio 2008.

Jim

Posted 25 February 08 12:46 by jamesche | 3 Comments   
Filed under ,
Hotfix Rollup for Visual Studio / Visual Web Developer Express Edition 2008

We recently released a hotfix rollup that fixes numerous issues in Visual Web Developer 2008, both the Visual Studio release and the Express edition. News of this rollup has circulated through many blogs and websites, but we're still seeing a fair number of people who are unaware of it.

The rollup can be downloaded from the link in Scott's blog.

Jim

The Power of !dumpmodule

Scenario: My customer is experiencing a hang and I see many threads with an identical stack. I also see that the customer has one thread that is running a component that is an OCX. What I want to find out is whether that component is referenced in the page that is executing on these numerous threads, but Reflector chokes on the module when I try to open it there.

Fortunately, you can use !dumpmodule in SOS to get that information. Not only will this tell you what types are defined in that module, but it will also tell you what references there are in the module. This can be especially useful if you see an unknown module in a dump. (An unknown module is often a dynamic assembly that is not serialized to disk.)

In this scenario, suppose I look at thread 68 and I see this:

0:068> !clrstack
Thread 68
ESP EIP
0x21d3e9a8 0x77f82870 [FRAME: GCFrame]
0x21d3ea68 0x77f82870 [FRAME: HelperMethodFrame]
0x21d3ea9c 0x0cb9eb92 [DEFAULT] [hasThis] Void JC.Business.Spec.ProcessPDF(Object) 
0x21d3ead4 0x0d12b933 [DEFAULT] [hasThis] Void JCC.Export.GoSpec()
0x21d3eb10 0x0d12b41f [DEFAULT] [hasThis] Void JCC.Export.Page_Load(Object,Class System.EventArgs)
0x21d3eb28 0x0ca2752c [DEFAULT] [hasThis] Void System.Web.UI.Control.OnLoad(Class System.EventArgs)

I believe that there is a problem in the JCC.Export page and I want to see what that references. The first thing I need to do is find out what assembly it lives in. I do that by dumping out the stack objects and getting the address of that type:

0:068> !dumpstackobjects
Thread 68
ESP/REG Object Name
0x21d3e4f8 0x27c8f84 System.String Project_Titl
0x21d3eaac 0x15144c4 System.Object[]
0x21d3eae0 0x536b4c8 System.String pdf
0x21d3eae4 0x1513e44 System.String \\netshare\webshare$\Temp\spec\
0x21d3eaf0 0x5a1b4b0 _ASP.Export_aspx

Now that I know the name of the type (_ASP.Export_aspx), I can find out what module it’s in by first using the !name2ee command to search all loaded modules for this type:

0:068> !name2ee * _ASP.Export_aspx
Searching all modules, this may take a while.
Loading all modules
Searching modules...
Module: 0c490220 (lbtrt0sh.dl )
MethodTable: 0x0d27002c
EEClass: 0x0d04f334
Name: _ASP.Export_aspx
----------------------------------- -------

The asterisk after the command tells it to search all modules. Note that the type name is case-sensitive

Now I’ve got the address of the module as reported by name2ee. To get the address to pass to !dumpdomain, you need to subtract 0x1d8 from that

0:068> ? 0c490220 -0x1d8
Evaluate expression: 206110792 = 0c490048

There’s the address we use to get the module information via !dumpmodule:

0:068> !dumpmodule -mt 0c490048
Name c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\root\b6f74a28\3807bf05\lbtrt0sh.dll
dwFlags 0x00200080
Attribute PEFile
Assembly 0x0bad89d0
LoaderHeap* 0x0017299c
TypeDefToMethodTableMap* 0x0c6b6618
TypeRefToMethodTableMap* 0x0c6b6664
MethodDefToDescMap* 0x0c6b67d4
FieldDefToDescMap* 0x0c6b6e18
MemberRefToDescMap* 0x0c6b6f78
FileReferencesMap* 0x0c6b786c
AssemblyReferencesMap* 0x0c6b7870
Types defined in this module
MT TypeDef Name
-----------------------------------------------------------------
0x17be8fbc 0x02000002 _ASP.MailMerge_aspx
0x1ee2ab4c 0x02000004 _ASP.AddPhone_aspx
0x0b9435d4 0x02000005 _ASP.AddEmail_aspx
0x21381254 0x02000007 _ASP.Calendar_aspx
0x17bef57c 0x02000009 _ASP.AddURL_aspx
0x0b9405f4 0x0200000b _ASP.AddAddress_aspx
0x25ef6cfc 0x0200000d _ASP.AssignProject_aspx
0x25ef2794 0x02000011 _ASP.MailMergeDownload_aspx
0x0b941244 0x02000012 _ASP.AssignCompany_aspx
Types referenced in this module
MT TypeRef Name
0x17be8c2c 0x02000001 JCC.MailMerge
0x0c7431ec 0x02000002 System.Web.SessionState.IRequiresSessionState
0x0ca193dc 0x02000003 System.Web.UI.WebControls.Literal
0x0ca19b5c 0x02000004 System.Web.UI.HtmlControls.HtmlForm
0x79ba0d74 0x02000005 System.Collections.ArrayList
0x0b97faac 0x02000007 System.Web.UI.Control
0x0ca1c944 0x02000008 System.Web.UI.HtmlTextWriter
0x1ee2a6e4 0x0200000e JCC.AddPhone
0x0b94322c 0x0200000f JCC.AddEmail
0x21380e64 0x02000011 JCC.Calendar
0x0d05fc0c 0x02000012 JCC.Export

I don't really see what’m interested in here. Because the JC.Business.Spec class is at the top of the stack I'm working with, I want to find out what is in that class. First I need to find out what module that lives in, so I'll use !name2ee again.

0:068> !name2ee * JC.Business.Spec
Searching all modules, this may take a while.
Loading all modules.
Searching modules...
Module: 0ba77100 (planspec.dll)
MethodTable: 0x0d2706bc
EEClass: 0x0d04fa7c
Name: JC.Business.Spec
----------------------------------- -------

Instead of evaluating the module address and subtracting 0x1d8 before dumping it, I'll now just pass the expression straight to !dumpmodule:

0:068> !dumpmodule -mt 0ba77100 -0x1d8
Name c:\winnt\microsoft.net\framework\v1.1.4322\temporary asp.net files\root\b6f74a28\3807bf05\assembly\dl2\2fb2768b\c0e90b4e_3b3cc501\planspec.dll
dwFlags 0x00200080
Attribute PEFile
Assembly 0x0ba76de8
LoaderHeap* 0x0017299c
TypeDefToMethodTableMap* 0x0c2622e4
TypeRefToMethodTableMap* 0x0c2622f8
MethodDefToDescMap* 0x0c262410
FieldDefToDescMap* 0x0c262490
MemberRefToDescMap* 0x0c2624e8
FileReferencesMap* 0x0c262644
AssemblyReferencesMap* 0x0c262648
MetaData starts at 0x0c273d30 (0x221c bytes)
Types defined in this module
MT TypeDef Name
-----------------------------------------------------------------
0x145f2630 0x02000002 PlanSpecFileType
0x145f283c 0x02000003 JC.PlanSpecBiz.GroupList
0x0d2706bc 0x02000004 JC.Business.Spec
Types referenced in this module
MT TypeRef Name
-----------------------------------------------------------------
0x0cb25a70 0x02000021 OCXLib.OCXClass
0x0cb22718 0x02000024 OCXLib._DOCX
0x0d2772c8 0x02000029 RasterIO.LRIOClass
0x0d27bc24 0x0200002a RasterLib.LRasterClass
0x0d272ca8 0x0200002b LRIOLib.ILRasterIO

Look at those OCX classes. If I look to see where they are, I find an interop component:

0:068> !name2ee * OCXLib.OCXClass
Searching all modules, this may take a while.
Loading all modules.
Searching modules...
Module: 0bad99a8 (interop.ocxlib.dll)
MethodTable: 0x0cb25a70
EEClass: 0x0d28c8b0
Name: OCXLib.OCXClass
----------------------------------- -------

I now know that the stacks that are hanging are sitting on a function call in a class that references the interop component that's using the OCX that I found on another thread. This doesn't get me to root cause, but it does give me a clear indicator of where I need to start looking.

Jim

Cool Things You Can Do with AppCMD in IIS 7

If you haven't had a chance yet to mess around with IIS 7, you should take the time. One of the changes that will impact everyone is configuration. Not only have we changed where configuration settings are stored, but we've also released a very cool command-line tool for examining and changing configuration called appcmd.exe. However, appcmd.exe is not just about configuration. There are some really cool things that you can do with it.

 

Wildcard Mapping

You can use wildcard characters with appcmd using the following syntax:

appcmd list apppool /name:"$=*2007"

This command will list all application pools with a name ending in "2007". Using a variation on the same method, you can find all application pools running under the identify of users in a particular domain.

appcmd list apppool /processModel.userName:"$=MyDomain\*"

This will list all application pools with running with an identity of users in the "MyDomain" domain.

Tip: You can find out all of the attributes that can be used with appcmd by querying for help after using an attribute. For example:

appcmd list apppools /name:DefaultAppPool -?

ERROR ( message:-name
-queueLength
-autoStart
-enable32BitAppOnWin64
-managedRuntimeVersion
-enableConfigurationOverride
-managedPipelineMode
-passAnonymousToken
-processModel.identityType
-processModel.userName
-processModel.password
-processModel.loadUserProfile
-processModel.manualGroupMembership
-processModel.idleTimeout
-processModel.maxProcesses
-processModel.shutdownTimeLimit
-processModel.startupTimeLimit
-processModel.pingingEnabled
-processModel.pingInterval
-processModel.pingResponseTime
-recycling.disallowOverlappingRotation
-recycling.disallowRotationOnConfigChange
-recycling.logEventOnRecycle
-recycling.periodicRestart.memory
-recycling.periodicRestart.privateMemory
-recycling.periodicRestart.requests
-recycling.periodicRestart.time
-recycling.periodicRestart.schedule.[value='timespan'].value
-failure.loadBalancerCapabilities
-failure.orphanWorkerProcess
-failure.orphanActionExe
-failure.orphanActionParams
-failure.rapidFailProtection
-failure.rapidFailProtectionInterval
-failure.rapidFailProtectionMaxCrashes
-failure.autoShutdownExe
-failure.autoShutdownParams
-cpu.limit
-cpu.action
-cpu.resetInterval
-cpu.smpAffinitized
-cpu.smpProcessorAffinityMask
-cpu.smpProcessorAffinityMask2
)

By appending "-?" to the command above, appcmd generates an error that lists all of the attributes that can be used with application pools.

Piping Output

You can pipe appcmd output to another appcmd command. Having this capability is extremely powerful, especially in the area of scripting functionality around appcmd.

The following command will find all application pools with names ending in "2007" and will then recycle each of them.

appcmd apppool list /name:"$=*2007" /xml | appcmd apppool recycle /in

(The "/in" switch causes the output from the first command to be sent to stdin.)

A more useful example might be to restart all application pools serving requests that have been executing for longer than a particular amount of time. The following command will recycle all application pools serving requests that have been executing for more than 30 seconds.

Appcmd list request /xml /time:"$>30000" | appcmd recycle apppool /in

In such situations, you might want to also obtain a list of the application pools. You can use multiple pipes to achieve that result.

Appcmd list request /xml /time:"$>30000" | appcmd list apppool /in /xml | appcmd recycle apppool /in

 

AppcmdUI

These examples only touch on the capabilities of appcmd.exe. One of the best ways to discover the capabilities of this tool is to use AppcmdUI. AppcmdUI is an interface into appcmd.exe. It gives you auto-completion for appcmd.exe commands and nicely formatted documentation so that you can more easily learn this powerful tool.

AppcmdUI is available from the IIS.net website.

By the way, those of you familiar with PowerShell might think that appcmd.exe uses PowerShell for some of its functionality. It doesn't. Therefore, appcmd.exe can be used with Windows 2008 Server Core as well.

Jim

Posted 16 January 08 12:43 by jamesche | 3 Comments   
Filed under ,
Update on Slow Startup Fix

A while back, I wrote a post regarding slow startup of ASP.NET 2.0 applications due to a lookup on a bad account. The hotfix for that issue is now available. The KB number is 944157. You can get the fix by calling PSS or by using our online automated system.

Jim

Having Network Problems on Win2003 SP2?

We've seen quite a few issues recently from customers having network problems on Windows Server 2003 SP2. These issue range from connections being reset to seeing things like database mirroring issues, etc. In other words, anything involving network traffic. In many of these issues, the problem is a new setting in Windows Server 2003 SP2 called TCP Chimney.

TCP Chimney is a new feature that improves network performance by offloading handling of TCP packets to the hardware layer, specifically to the network interface card (NIC). It works great if your NIC and NIC driver are capable. If they aren't, you will see strange network issues such as I described in above.

If you're experiencing problems with your network on SP2, the first step is to look for a new driver for your NIC. A new driver will sometimes correct the problem. In cases where it doesn't, disabling TCP Chimney is a good idea. If that resolves the issue, you can chalk your issue up to a NIC and/or NIC driver that just doesn't work correctly with this new feature.

1. To disable TCP Chimney, follow these steps:

2. Click Start, click Run, type cmd, and then click OK.

3. At the command prompt, type:

Netsh int ip set chimney DISABLED

4. Press the ENTER key.

No reboot or restart is required for this to take effect. It will take effect immediately.

Jim

Posted 19 December 07 08:14 by jamesche | 3 Comments   
Filed under
Creating Strings - A Case Study

I recently worked an issue with a customer who was experiencing high CPU. Performance Monitor data showed that the % of Time in GC was 46%. We generally recommend that you not be in GC more than 5% of the time, so this was a point of interest.

One of the common causes of very frequent GC is GC.Collect() being called. I checked the # of Induced GC Perfmon counter and it was greater than 8,000 with a process uptime of only a few hours. This was obviously a clear sign that someone was calling GC.Collect() a lot! ASP.NET will call GC.Collect() at times, but not nearly this often.

We found a DLL that was causing that problem and fixed it. Good news. Induced GC was now 0. Bad news. CPU and Time in GC were both still high.

Many issues that we work are like this; like peeling an onion. We resolve one part of the issue only to discover other problems coming to the surface. This was just such an issue. Once we resolved induced GCs, a pattern became clear.

Have a look at the Perfmon data shown below. The color-key appears below the image:

Perf

Red: % of Time in GC
Blue: % Processor Time
Tan: # of Bytes in All Heaps
Black: Large Object Heap Size

 

The first thing to notice is that things started out okay and then went bad very quickly. One of the things that can cause that pattern is a problem call stack. (In fact, that's the issue here. More soon.) We can also see that something is creating a lot of objects and that's causing considerable memory pressure. That's causing us to go into GC often, but even when we're not in GC, you can see that CPU remains high.

The first thing I decided to do was to check the Large Object Heap to see what we had there.

0:046> !dumpheap -min 85000 -stat

Statistics:

        MT      Count     TotalSize Class Name

0x000f3198         69    87,714,456      Free

0x03084300        123   158,192,160 System.String

Total 192 objects, Total size: 245,906,616

 

This tells me that the memory we see in the LOH is taken up by strings. In fact, when I looked at some of these strings in the debugger, they turned out to be XML data generated by the customer.

I then checked to see where one of these big strings was rooted. It was rooted in a thread, so I checked that stack and saw this:

0:053> kL

ChildEBP RetAddr 

0635b890 791c134c mscorsvr!wstrcopy+0x26

0635b8a4 035ac67c mscorsvr!COMString::FillStringChecked+0x37

 

This tells me that we're making a copy of a string, so I checked the managed stack. When I did, I found a couple of interesting problems. First of all, the customer had a function call that was recursive and had hundreds of iterations already. Secondly, I could tell that each iteration of that function created more strings via wstrcopy. This is a clear sign of string concatenation, and indeed, in another dump I could see concat being called.

In the end, the customer's allocation pattern caused memory pressure and caused us to go into GC much more often than we should have. (In particular, the customer was creating a large number of objects on almost a per-request basis.) Because of this, the customer experienced high CPU and poor application performance.

I hope this helps others who might see the same kind of thing in production applications.

Jim

Posted 11 December 07 01:45 by jamesche | 2 Comments   
Filed under
Purchase My Books in the Microsoft Company Store

I received notification today that Microsoft has decided to carry a small number of non-Microsoft Press books in the Microsoft Company Store in Redmond. One of those books will be mine, most likely my latest book on ASP.NET 3.5.

If you're a Microsoft employee or otherwise have access to the Company Store in Redmond, please drop by and buy my book! At this time, the book will not be available at other Microsoft campuses, nor will it will be available on the online Company Store. That may change if this pilot is successful.

Jim

My New Zune : Thoughts from an iPod Junkie

Yesterday morning I replaced my iPod with a new Zune 2. I've owned 4 iPods over the years, and I've always loved them. When the first Zunes released, I wasn't tempted at all to replace my trusty iPod. That all changed when I heard of the new features in Zune 2, and after using the new Zune for a day, I am convinced that it's hands-down better than what Apple offers.

The Hardware

My 80GB Zune feels smaller than my 80GB iPod, but the screen on it seems HUGE in comparison. I'd love to see a higher resolution screen on the Zune for video (you can see pixels if you look closely enough), but it's not a big deal to me. Video looks great and the colors are incredibly vibrant. The huge, widescreen display is perfect for watching my video podcasts. (Yes, the Zune has podcast support now.)

Another great thing about the Zune 2 is that it's extremely scratch-resistant. The screen is glass, so it's just about impervious to scratches. The rest of the front of the case is a matte finish that resists fingerprints. The rear of the case is a matte aluminum that doesn't show fingerprints and doesn't scratch. It also provides a great feel when holding the Zune.

The new controller on the Zune is called a ZunePad. It's one of those things that you can't truly appreciate until you use it. It's touch-sensitive so that you can swipe your thumb across it for fast scrolling, but it's also a tactile clicker. I've often been frustrated by the iPod wheel because it's sometimes hard to select an item with it. Because the ZunePad can be swiped with the thumb as well as clicked for precise selection, it's a perfect solution.

The new Zunes also offer WiFi sync. It works well and is a huge convenience. Users of first-version Zunes get all of the new software features in a firmware update, including the ability to sync via WiFi.

The Software (on the device and on the PC)

The Zune 2 software flashed onto the device is nice for someone coming from the utilitarian iPod. My favorite feature is the full-screen album art. I'm not a big fan of the huge letters on the home screen. It would be nice to have the option of making them smaller.

Navigation is easy and very attractive. I played with a friend's first-generation Zune when they first released and I found it confusing and a little awkward. The Zune 2 is a huge improvement and I find it to be very intuitive. It also has nice touches that you don't appreciate at first. For example, when you select an album for a particular artist, you get the typical screen showing the tracks where you can select to play all tracks or an individual track. However, you also get a horizontally-scrolling thumbnail view of all of that artist's albums along the top of the screen. If you're trying to find a particular song but you're not sure which album it's on, you can swipe your thumb left and right until you find the track. That same operation on the iPod requires you to select an album, scroll through the track list, click Menu to go back, scroll to a new album, select it, etc. The Zune's interface feels more polished to me.

The Zune software that installs on your PC is equally nice, and it solves some of the frustrations I have with iTunes. Podcast support is certainly not an afterthought (as I thought it would be) and unlike iTunes, you can control how many episodes are kept, etc. for individual podcasts. In other words, I have some podcasts that release daily, and I want to keep the latest 4 episodes. Another podcast might release weekly and I might only want to keep the latest episode of that one. The Zune software makes configuring that easy. You can't do it at all in iTunes.

Another enormous advantage is being able to add as many folders as I want for my music collection. I like to keep my music separated from video and podcasts. Using the Zune software, I can add as many folders as I want (on any drive) and Zune software will watch those folders. With iTunes, you have one folder and that's it.

When I first set up my Zune, I pointed it to the music on my external firewire hard drive. After using it for a few hours, I decided that I wanted to put all of my music on my laptop hard drive, so I copied it all over and reconfigured the Zune software to point to the new folder on my hard drive. When I synced my Zune, it was smart enough to accept the new configuration without requiring me to resync the entire device. Making that same change in iTunes often requires a resync of your iPod, a process that can take a considerable amount of time.

Another huge plus with the Zune is the Zune Pass. For $15 per month, I can download anything I want. I can use that music on up to three computers and three Zunes, and I can keep it as long as I keep my subscription active. The iPod doesn't offer any subscription services.

The Zune Marketplace doesn't have as much music as iTunes yet, but it does offer more music than many other music services. (James Taylor's new album released yesterday and I was able to download it immediately!) You can also purchase DRM-free MP3 music from the Zune Marketplace. (Yes, MP3 format, not WMA.)

I could go on and on, but you get the idea. I'm sure you think that I'm a Zune fan because I work for Microsoft. Not true! I've been an iPod junkie for years. I am a fan of the Zune 2 because it truly is a superior device in my opinion, is a joy to use, sounds great, and "fixes" many of the annoyances I have with iTunes/iPod.

Great job, Zune team! This one's a winner.

Jim

 [In order to avoid prolonging the debate of iPod vs. Zune, I've decided to close comments on this post. I think the existing comments sufficiently represent both sides of the debate.]

 

Posted 14 November 07 07:19 by jamesche | 26 Comments   
Filed under
New Hotfix: Run ASP.NET Without Full Trust in My_Computer_Zone

I have been working with the product group on a new hotfix that allows you to run ASP.NET 2.0 applications without associating the My_Computer_Zone code group with the Full Trust permission set in Code Access Security. The new hotfix is available now under KB article 943598.

Pay careful attention to the KB article because it gives you the specific CASPOL commands that you need to run after installing the hotfix.

Keep in mind that the configuration changes made after you install this hotfix will affect anything running ASP.NET 2.0. For example, SQL Server Reporting Service will not work after you change CAS settings for the My_Computer_Zone. (A solution for that is available in the KB article.) SharePoint will also likely be impacted by reconfiguring CAS and we have not tested this hotfix configuration with SharePoint.

Simply installing the hotfix will not impact your applications.

Posted 12 November 07 09:27 by jamesche | 0 Comments   
Filed under
More Posts Next page »

Search

This Blog

Syndication

Page view tracker