Last week I came to see one interesting issue related to WPF calling WCF services. One of my colleague asked me to look into his machine as he is not able to call WCF service from WPF application. When I looked into the issue, I could see that the error message at client side is
The requested service, 'http://<host>/<Service>.svc' could not be activated. See the server's diagnostic trace logs for more information
Diagnose step 1
When ever we see this exception we could understand that the service instance creation got error. If we browse the service url, it internally creates the service object and fail with more error details. So the next step was to browse the WCF service in browser by right click on IIS and browse or give the URL directly, if its known.
That turned out to be more informative
Could not load file or assembly '<assembly name>' or one of its dependencies. An attempt was made to load a program with an incorrect format
Could not load file or assembly '<assembly name>' or one of its dependencies. An attempt was made to load a program with an incorrect format
If we are not seeing the details we can enable the exception flag.
<serviceDebug includeExceptionDetailInFaults="true"/>
Diagnose step 2
Reset IIS and clear the temporary Asp.Net files. Sometime the temporary Asp.net files will be holding a wring dll.
Location of temporary ASP.Net files for 64 bit .Net 4.0 applications is - %Windir%\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files
Location of temporary ASP.Net files for 32 bit .Net 4.0 applications is - %Windir%\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files
Tried this step but no luck.
Diagnose step 3
This leads to the situation where one assembly file present in the bin folder is not getting loaded due to some exception. There are chances that it depends on another dll and that is causing issue. Also chances are that it might be loading the dll from some other location such as GAC.
So better idea is to see the assembly binding fusion log using the fuslogvw tool .Tried that and got more detail. Basically enabled the registry key, then we can see the fusion log in the browser itself. It says
=== LOG: This bind starts in default load context. LOG: Using application configuration file: D:\TFS\TestDotNet\WcfService1\web.config LOG: Using host configuration file: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet.config LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config. LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind). LOG: Attempting download of new URL file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/wcfservice1/63540997/f07fffe5/ClassLibrary20.DLL. LOG: Attempting download of new URL file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/Temporary ASP.NET Files/wcfservice1/63540997/f07fffe5/ClassLibrary20/ClassLibrary20.DLL. LOG: Attempting download of new URL file:///D:/TFS/TestDotNet/WcfService1/bin/ClassLibrary20.DLL. ERR: Failed to complete setup of assembly (hr = 0x8007000b). Probing terminated
This means the dll is loaded from proper location. So need to go next step.
Diagnose step 4
Need to have closer look at the exceptions and their call stack to understand how far its reaching and where its failing. The exception call stack is given below which was present in the browser when service is browsed.
[BadImageFormatException: Could not load file or assembly '<assembly name>' or one of its dependencies. An attempt was made to load a program with an incorrect format.]
System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +0
System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +210
System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection) +242
System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +17
System.Reflection.Assembly.Load(String assemblyString) +35
System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +122
[ConfigurationErrorsException: Could not load file or assembly '<assembly name>' or one of its dependencies. An attempt was made to load a program with an incorrect format.]
System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +12761078
System.Web.Configuration.CompilationSection.LoadAllAssembliesFromAppDomainBinDirectory() +503
System.Web.Configuration.AssemblyInfo.get_AssemblyInternal() +142
System.Web.Compilation.BuildManager.GetReferencedAssemblies(CompilationSection compConfig) +334
System.Web.Compilation.BuildManager.CallPreStartInitMethods(String preStartInitListPath) +203
System.Web.Compilation.BuildManager.ExecutePreAppStart() +152
System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException) +1151
[HttpException (0x80004005): Could not load file or assembly '<assembly name>' or one of its dependencies. An attempt was made to load a program with an incorrect format.]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +12881540
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +159
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +12722601
There were 3 exception one after another. Configuration exception and HttpExceptions are the outer ones and the real problem is stated in the very inner exception which is nothing but BadImageException.
BadImageException usually happens when we try to load 32 bit assembly in 64-bit applications or when the assembly is corrupted.
Diagnose step 5
We can check whether the assembly is corrupted by opening it in reflector or any other decompilation software. If reflector is able to load the dll, there is no issue. In this case, I was able to open the file in reflector.
Diagnose step 6
Next we need to make sure all the assemblies are marked as 64 bit / AnyCPU when compiled. The ASP.Net hosting mechanism loads all the dlls when its started. Based on the application pool setting "Enable 32-Bit Applications" flag, it decide the processor architecture of web application. If there is any dll which is not matching with bit size, it will throw this bad image exception. We could see that the assembly which was causing, is built using x86 mode where the app pool is exclusive for 64bit applications.
Recompiled using 'AnyCPU' setting. Reset IIS and cleared the Temporary ASP.Net Files. Everything worked.
No comments:
Post a Comment