Failure to load Report Manager due to truncated UserAgent string

We came across an issue when trying to load Report Manager.  We would get the following exception:

System.ArgumentException: Version string portion was too short or too long. at
System.Version..ctor(String version) at
System.Web.Configuration.HttpCapabilitiesBase.GetClrVersions() at
System.Web.Configuration.HttpCapabilitiesBase.get_ClrVersion() at
Microsoft.ReportingServices.Common.RBRequirements.get_ClientMeetsRequirements() at
Microsoft.ReportingServices.UI.FolderItems.GetReportBuilderLaunchUrl()

In turn, this prevented Report Manager from loading.  The exception itself is occuring within the .NET Framework, not from Reporting Services (System.Web.Configuration.HttpCapabilitiesBase.GetClrVersions).  GetClrVersions is essentially parsing the UserAgent and getting the latest .NET version available on the client side. 

You might be asking why would we care about the client side when I'm trying to load Report Manager which should be processed server side.  If we look at the callstack, we can see that we are building the URL for the Report Builder button.  Report Builder (RB) is a client side tool, hence we need to make sure that you have the proper .NET version on the client so that we can expose RB to you.

What do we do now?  We knew that we were failing when trying to build out the URL, and from the callstack we know it had something to do with the UserAgent.  Unfortunately, the logs don't tell me what the UserAgent was.  There are many ways to tell what the UserAgent is.  You could use a client side tool like Fiddler to get the HTTP Requests and Responses.  A network trace would also tell you what the HTTP Header information looked like in a Request.  A memory dump when the exception occurs would also show you what the UserAgent looked like as it related to the code.  I decided to go with the Memory Dump route.  You can do this as well by using the SOS extension that ships with the .NET Framework along with WinDBG which is part of the Debugging Tools for Windows.

When I opened the dump, I was immediately placed on the thread that caused the exception.  In this case it was Thread 37.  So, I dumped the Stack Objects for that thread.

0:037> !dso
OS Thread Id: 0x1ab4 (37)
ESP/REG Object Name
1110ef94 02817c74 System.ArgumentException
1110efe0 02817c74 System.ArgumentException
1110eff4 02817c74 System.ArgumentException
1110eff8 02817c60 System.Object[] (System.String[])
1110f008 02817c74 System.ArgumentException
1110f014 02817c74 System.ArgumentException
1110f024 02817c74 System.ArgumentException
1110f02c 02817c74 System.ArgumentException
1110f034 02817c60 System.Object[] (System.String[])
1110f080 0263534c System.String Arg_VersionString
1110f088 02817c74 System.ArgumentException
1110f0a4 02815a60 System.String Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; InfoPath.2; .NET CLR 1.0.3705; .NET CLR 3
1110f0a8 02817380 System.Text.RegularExpressions.Match

From this alone, I can see what the UserAgent string is.  You can also drill a little further into the string itself by Dumping the String Object.  We do this by way of the !do command (do = Dump Object)

0:037> !do 02815a60
Name: System.String
MethodTable: 793308ec
EEClass: 790ed64c
Size: 530(0x212) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; InfoPath.2; .NET CLR 1.0.3705; .NET CLR 3
Fields:
MT Field Offset Type VT Attr Value Name
79332b38 4000096 4 System.Int32 1 instance 257 m_arrayLength
79332b38 4000097 8 System.Int32 1 instance 256 m_stringLength
793315cc 4000098 c System.Char 1 instance 4d m_firstChar
793308ec 4000099 10 System.String 0 shared static Empty
>> Domain:Value 021c3728:063701d0 100d6880:063701d0 11596040:063701d0 12bad3a0:063701d0 <<
7933151c 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 021c3728:06370874 100d6880:023b880c 11596040:063a4558 12bad3a0:06462cf8 <<

Our string length is 256.  This happens to be length at which ASP.NET currently truncates the UserAgent string.  We can definately see that the UserAgent is being truncted.  So, how do I fix it.

The items within a UserAgent are stored within the following registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform

NOTE: Please use caution whenever modifying the registry. I also recommend you export the key before modifying it so that you have a backup if needed.

Here is what this looks like on my machine.

UserAgent

You can have multiple builds for the same version.  For example, I list two entries for the .NET Framework 3.5.  In reality, we only need the latest version.  We ultimately corrected the issue by removing the older builds and making sure we only had the latest build for each version.  With the example above, we would have everything that is listed except for ".NET CLR 3.5.21022".

The reason the exception was being thrown is because the Framework call is using Regular Expressions to pull out the versions (i.e. .NET CLR 3.5, .NET CLR 3.0, .NET CLR 2.0, etc...).  In the UserAgent in question, we had a entry that showed as ".NET CLR 3".  This is what caused the exception.

 

Adam W. Saxton | Microsoft SQL Server Escalation Services