Cloud Services roles recycling with the error “System.IO.FileLoadException: Could not load file or assembly”

You may be facing an issue where after a deploy, your Cloud Service role gets stuck in “starting” or “recycling” states. In this case, as the initial troubleshooting steps, we have to remote access the instance, start checking the logs and try to find out evidences about what can be causing the issue. For an excellent guidance about what logs to look, please refer to this excellent Kevin Williamson’s article.
If you get into the same situation above, one of the common causes may be the following exception:

 
1044
WaIISHost
Role entrypoint could not be created: System.TypeLoadException: Unable to load the role entry point due to the following exceptions:
-- System.IO.FileLoadException: Could not load file or assembly 'System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
 
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].
 
---> System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
   at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
   at System.Reflection.RuntimeModule.GetTypes()
   at System.Reflection.Assembly.GetTypes()
   at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetRoleEntryPoint(Assembly entryPointAssembly)
   --- End of inner exception stack trace ---
   at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetRoleEntryPoint(Assembly entryPointAssembly)
   at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.CreateRoleEntryPoint(RoleType roleTypeEnum)
   at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.InitializeRoleInternal(RoleType roleTypeEnum)
 
the message resource is present but the message is not found in the string/message table

 

This exception is usually recorded in the Azure event log (see the next image) and it means that something in your project is referencing a wrong version of the assembly. In this case, it is failing to load the version 3.0.0.0 of System.Web.Mvc which is not the current version of the assembly (the current one in this case is 5.0.0.0) so that is where the exception happens.

 

 

The best way to fix this issue is to fix the wrong references inside your project. However, it can take some time if you are not sure what exactly is making the wrong references. In this case, the faster way is to use the bindingRedirect in the configuration files.
Usually, when a new assembly is added to your project, Visual Studio will automatically create a bindingRedirect entry in your web.config (Web Role) or app.config (Worker Role) just to avoid the wrong assembly version issue.

 

 

However, in Azure Cloud Services, the assembly bindings from web.config and app.config does not have effect, due to the fact that WaIISHost (Web Role) and WaWorkerHost (Worker Role) are not able to read these two configuration files, instead, they read the <role name>.dll.config file, and this is the file where the assembly binding configuration need to be. Please, refer to this article for more details.
The problem is, the <role name>.dll.config file is not added to Solution by default, and even if it is there, it may happen that it does not have the assembly binding configuration like in web.config or app.config.

 

Solution:

1) Open the <role name>.dll.config located in your project bin folder.
2) Check if there is the BindingRedirect entry that you need. If not, follow one of the two options below:
     a) Copy the web.config or app.config content (considering one of these two configuration files has the information that you need) and paste it into the <role name>.dll.config file.
     b) Manually create an Assembly Binding entry:
 

 <runtime>
 <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
 <dependentAssembly>
 <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
 <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
 </dependentAssembly>
 </assemblyBinding>
</runtime>
 

NOTE: In order to discover the publicKeyToken, execute the following PowerShell command:

 PS C:\Windows\Syetem32>([system.reflection.assembly]::loadfile("dll full path")).FullName

Where “dll Full path” is the dll location path. Example:

 PS C:\WINDOWS\system32> ([system.reflection.assembly]::loadfile("C:\logs\Newtonsoft.Json.dll")).FullName

You will have the following output:

Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed

 

3) Add the <role name>.dll.config file to your Solution (same level as the web.config or app.config) and set the Copy to Output Directory property to “Copy Always”.

 

 

4) Redeploy to your Cloud Service.

 

NOTE: As a quick test in case you are not able to make a new deploy, you can copy the <role name>dll.config file to the bin folder of your package into the instance in Azure (<application drive>:\approot\bin) and wait some minutes until the WaHostBootstrapper.exe process restart the WaIISHost.exe or WaWorkerHost.exe processes then the role will initiate normally. However, do not forget to redeploy, since all the manual change inside the Cloud Services instances will be lost in some time.