Issues with WCF service when the ASP.NET website is deployed using the Web Deployment Project and as non-updatable project
I have been thinking to start writing blog since long. So here it goes!
Recently I got a chance to work with a customer who was trying to deploy an ASP.NET web site using WDP (Web Deployment Project which was shipped with Visual Studio 2008 SP1). This web site had WCF (.NET 3.5) services as a part of it as well. For deployment we were using below options in WDP -
o "Merge all output to single Assembly" was selected
o “Allow this precompiled site to be updatable” wasn't selected
After deploying the site we started getting below exception while trying to browse the .svc files –
Server Error in '/MyWebSite' Application.
Could not load file or assembly 'App_global.asax, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Exception Details: System.IO.FileNotFoundException: Could not load file or assembly 'App_global.asax, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below. |
Assembly Load Trace: The following information can be helpful to determine why the assembly 'App_global.asax, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' could not be loaded.
WRN: Assembly binding logging is turned OFF. To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1. Note: There is some performance penalty associated with assembly bind failure logging. To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog]. |
Stack Trace:
[FileNotFoundException: Could not load file or assembly 'App_global.asax, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.] System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) +0 System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) +43 System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +127 System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +142 System.Reflection.Assembly.Load(String assemblyString) +28 System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(String constructorString, Uri[] baseAddresses) +162 System.ServiceModel.HostingManager.CreateService(String normalizedVirtualPath) +11656092 System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +42 System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +479 [ServiceActivationException: The service '/MyWebSite/service.svc' cannot be activated due to an exception during compilation. The exception message is: Could not load file or assembly 'App_global.asax, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified..] System.ServiceModel.AsyncResult.End(IAsyncResult result) +11527290 System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +194 System.ServiceModel.Activation.HostedHttpRequestAsyncResult.ExecuteSynchronous(HttpApplication context, Boolean flowContext) +176 System.ServiceModel.Activation.HttpModule.ProcessRequest(Object sender, EventArgs e) +278 System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +68 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75 |
Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053
I was able to reproduce the same issue with sample application as well. After digging in further, I found that after the compilation step, WCF stores the list of referenced assemblies into the customString attribute in the build result (service.svc.cdcab7d2.compiled), including App_Global. It seems there is an incorrect assumption here that those assemblies will always be there, which is not necessarily the case in Web Deployment Projects (aspnet_merge) where assemblies will be merged. After the merge step, the assemblies are actually all merged into a single assembly (let us say MyWebSite.dll) as we selected that option in WDP. ASP.NET only updates the .compiled files it knows about, so App_Global.asax.compiled actually has a correct reference to MyWebSite_Deploy.dll instead of App_Global.dll. Original assemblies are removed after the merge step. WCF reads the list of assemblies previously stored, and throws when it cannot find App_Global.
This behavior is something which by design and getting around it there are few options as below –
1. Manually update .complied file for WCF and remove the following reference like below –
'App_global.asax, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
'App_ GlobalResources.asax, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
'App_ WebReferences.asax, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
'App_ Code.asax, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
OR
2. Add fully qualified name for the service/factory in .svc file. The .svc buildprovider adds the list of referenced assemblies to the asp.net temporary file (as CompiledCustomString) during compilation. In the case of not-assembly-fully-qualified name is used, WCF hosting layer will use the compiled custom string to load assemblies and resolve the type of service/factory.
OR
3. In the properties of Web Deployment project, check ‘Allow this precompiled site to be updatable’ option. With this setting, the assembly App_Global.dll will not be built during the build/merge step.
OR
4. In the properties of Web Deployment project, choose merge option OTHER than “Merge All outputs to a single assembly”. The difference is that App_Global will not be merged and removed for the other options. And to get the assembly versions as needed, use compilerOptions in addition to this. Refer http://msdn.microsoft.com/en-us/library/ms228042.aspx
Hope this helps!!!
Comments
- Anonymous
April 03, 2009
PingBack from http://culture.linkablez.info/2009/04/04/issues-with-wcf-service-when-the-aspnet-website-is-deployed-using/