ASP.NET application high CPU utilization caused by “System.NotSupportedException”
Background:
==========
Customer experienced the high CPU utilization with their ASP.NET application and the CPU will fluctuate.
Analysis:
==========
We found a lot of exceptions generated and this could severely impact the application performance. We got the crash dump which signified the “GetManifestResourceNamesForAssembly” throws “System.NotSupportedException”.
The following is the call stack:
0:024> !clrstack
OS Thread Id: 0x25dc (24)
ESP EIP
1ca6e990 7c80bee7 [HelperMethodFrame: 1ca6e990]
1ca6ea34 7983a771 System.Reflection.Emit.AssemblyBuilder.GetManifestResourceNames()
1ca6ea40 6ca781b4 System.Data.Metadata.Edm.MetadataArtifactLoaderCompositeResource.GetManifestResourceNamesForAssembly(System.Reflection.Assembly)
1ca6ea6c 6ca785d2 System.Data.Metadata.Edm.MetadataArtifactLoaderCompositeResource.AssemblyContainsResource(System.Reflection.Assembly, System.String ByRef)
1ca6ea84 6ca77cf1 System.Data.Metadata.Edm.MetadataArtifactLoaderCompositeResource.LoadResources(System.String, System.String, System.Collections.Generic.ICollection`1<System.String>, System.Data.Metadata.Edm.MetadataArtifactAssemblyResolver)
1ca6eac0 6ca782ea System.Data.Metadata.Edm.MetadataArtifactLoaderCompositeResource.CreateResourceLoader(System.String, ExtensionCheck, System.String, System.Collections.Generic.ICollection`1<System.String>, System.Data.Metadata.Edm.MetadataArtifactAssemblyResolver)
1ca6eae8 6ca59488 System.Data.Metadata.Edm.MetadataArtifactLoader.Create(System.String, ExtensionCheck, System.String, System.Collections.Generic.ICollection`1<System.String>, System.Data.Metadata.Edm.MetadataArtifactAssemblyResolver)
1ca6eb04 6cb06474 System.Data.EntityClient.EntityConnection.SplitPaths(System.String)
1ca6eb44 6cb077c1 System.Data.EntityClient.EntityConnection.GetMetadataWorkspace(Boolean)
1ca6eb78 6caa339b System.Data.Objects.ObjectContext.RetrieveMetadataWorkspaceFromConnection()
1ca6eb80 6caa45bd System.Data.Objects.ObjectContext..ctor(System.Data.EntityClient.EntityConnection, Boolean)
1ca6ebb0 6caa46b0 System.Data.Objects.ObjectContext..ctor(System.String, System.String)
1ca6ebc4 1f6e2739 JGB.Qy.EntityModel.JGBQyDBEntities..ctor()
1ca6edf0 79e71b4c [GCFrame: 1ca6edf0]
0:024> kb 10
ChildEBP RetAddr Args to Child
1ca6e908 79eda99c e0434f4d 00000001 00000001 kernel32!RaiseException+0x53 [d:\nt\base\win32\client\thread.c @ 1540]
1ca6e968 79fb48f8 0b1fa198 00000000 00000000 mscorwks!RaiseTheExceptionInternalOnly+0x2a8 [f:\dd\ndp\clr\src\vm\excep.cpp @ 2735]
1ca6ea2c 7983a771 0b1fa198 1ca6ea64 6ca781b4 mscorwks!JIT_Throw+0xfc [f:\dd\ndp\clr\src\vm\jithelpers.cpp @ 4777]
1ca6ea38 6ca781b4 0b1f9e60 00000000 00000000 mscorlib_ni+0x77a771 --- PARAMETERS DUMPED BELOW.
WARNING: Stack unwind information not available. Following frames may be wrong.
1ca6ea64 6ca785d2 1ca6ea8c 0b1ea300 06a5fc8c System_Data_Entity_ni+0x4d81b4
1ca6ea7c 6ca77cf1 0b1ec7ec 0b1ea4d8 0b1f075c System_Data_Entity_ni+0x4d85d2
1ca6eab0 6ca782ea 0b1ea300 0b1e9e9c 0b1ea46c System_Data_Entity_ni+0x4d7cf1
1ca6ead4 6ca59488 0b1ea300 0b1e9e9c 00000000 System_Data_Entity_ni+0x4d82ea
1ca6eaf0 6cb06474 0b1ea300 0b1e9e9c 00000000 System_Data_Entity_ni+0x4b9488
1ca6eb3c 6cb077c1 0b1e919c 00000000 0b1e9148 System_Data_Entity_ni+0x566474
Connection String: Data Source=xxxx;Initial Catalog=xxxxx;Persist Security Info=True;User ID=xxxxx;Password=xxxxxxx;MultipleActiveResultSets=True
Related CODE
=============
We check the top call stack functions with reflector:
Private Shared Function AssemblyContainsResource(ByVal [assembly] As Assembly, ByRef resourceName As String) As Boolean
If (resourceName Is Nothing) Then
Return True
End If
Dim str As String
For Each str In MetadataArtifactLoaderCompositeResource.GetManifestResourceNamesForAssembly([assembly])
If String.Equals(resourceName, str, StringComparison.OrdinalIgnoreCase) Then
resourceName = str
Return True
End If
Next
Return False
End Function
Friend Shared Function GetManifestResourceNamesForAssembly(ByVal [assembly] As Assembly) As String()
Try
Return [assembly].GetManifestResourceNames
Catch exception1 As NotSupportedException
Return New String(0 - 1) {}
End Try
End Function
Explaination on NotSupportedException:
The exception that is thrown when an invoked method is not supported, or when there is an attempt to read, seek, or write to a stream that does not support the invoked functionality.
Since the “NotSupportedException” will be thrown frequently, it imposed heavy load to system resources and CPU utilization is pretty high.
Solution:
======
Based on our discussion with product team of Entity Framework, the issue can be identified to be a bug which will be fixed in the next version of .NET framework (4.0). I searched through internet and found several issues rose without a solution/workaround. I hence would like to share with you guys our outputs which have been proved to be helpful:
· By default, the EF designer creates a connection string that looks like below :
o connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl; provider=System.Data.SqlClient;provider connection string="Data Source=.\sqlexpress;Initial Catalog=PeopleBlogs;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
o The “res://*” in the metadata keyword means that the Entity framework will go through the calling assembly, all the referenced assemblies of the calling assembly and the loaded assemblies in the current app domain to find the specified metadata resource( in the above case, Model1.csdl, Mode11.ssdl and Model1.msl).
· The problem that you are hitting is that we use GetmanifestResourceNames method to see what resources are present in an Assembly but this method will throw a Not Supported exception in case of dynamic assemblies. In .Net 3.5, CLR did not provide any way to check if an assembly was dynamic, so we caught the exception and continued. In .Net 4.0, CLR added a Assembly.IsDynamic property which we now use so that the exception is not thrown.
· There are a couple of ways to work around the problem in .Net 3.5 SP1:
o If you know the full name of the assembly, you can provide a connection string as follows( the text in red is full name of assembly that contains the metadata resources):
§ connectionString="metadata=res://EFResAPP, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null/ ;provider=System.Data.SqlClient;provider connection string="Data Source=.\sqlexpress;Initial Catalog=PeopleBlogs;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
o You can also specify the path to the metadata folder( or all the files) on the disk:
§ connectionString="metadata= c:\metadatafolderpath\ ;provider=System.Data.SqlClient;provider connection string="Data Source=.\sqlexpress;Initial Catalog=PeopleBlogs;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
§ connectionString="metadata= c:\metadatapath\Model1.csdl|c:\metadatapath\Model1.ssdl|c:\metadatapath\model1.msl; provider=System.Data.SqlClient;provider connection string="Data Source=.\sqlexpress;Initial Catalog=PeopleBlogs;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
Regards,
Yawei Wang