Web role failing to start because dependent assembly cannot be loaded - azure

I encountered a strange issue with the startup of web roles.
The full repro is quite complex, but I managed to find the root cause so I will put the simplified steps.
My webrole project depends on AssmeblyA which in turn depends on AssemblyB, Version=1.0.
The webrole also depends directly on AssemblyB, but Version=2.0.
(this all comes from different NuGet packages over which I don't have any control).
In the end, AssemblyB, Version=2.0 is getting copied to the \Bin folder.
The website itself is working correctly because in the Web.config there is a binding redirect for AssemblyB to Version=2.0 (which is automatically being put there by nuget client).
However, when webrole is deployed to Azure, it fails to start because AssemblyB, Version=1.0 cannot be loaded.
I suspect this is because web role is first loaded from the Approot directory where web.config has no effect. I also found that I can workaround this problem by generating an app.config for the web-role as well and duplicating all binding redirects there. While this works, it's not very convenient to maintain such setup.
Does anyone know if this is a known issue with Azure web roles?
Tried with Azure SDk 2.4 and 2.5.1, all azure nuget packages up to date, no custom startup code whatsoever.
Update:
Here is the exception obtained through IntelliTrace:
Unable to load the role entry point due to the following exceptions:
-- System.IO.FileLoadException:
Could not load file or assembly 'Microsoft.Owin, 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: 'Microsoft.Owin, Version=3.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35'
And here is the stack trace:
CommonLanguageRuntimeLibrary!System.Reflection.RuntimeModule.GetTypes()
CommonLanguageRuntimeLibrary!System.Reflection.Assembly.GetTypes()
Microsoft.WindowsAzure.ServiceRuntime.dll!Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetRoleEntryPoint(System.Reflection.Assembly entryPointAssembly = {System.Reflection.RuntimeAssembly})
Microsoft.WindowsAzure.ServiceRuntime.dll!Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.CreateRoleEntryPoint(Microsoft.WindowsAzure.ServiceRuntime.Implementation.Loader.RoleType roleTypeEnum = IISWeb)
Microsoft.WindowsAzure.ServiceRuntime.dll!Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.InitializeRoleInternal(Microsoft.WindowsAzure.ServiceRuntime.Implementation.Loader.RoleType roleTypeEnum = IISWeb)
Microsoft.WindowsAzure.ServiceRuntime.dll!Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.InitializeRole(Microsoft.WindowsAzure.ServiceRuntime.Implementation.Loader.RoleType roleType = IISWeb)
Microsoft.WindowsAzure.ServiceRuntime.dll!Microsoft.WindowsAzure.ServiceRuntime.Implementation.Loader.RoleRuntimeBridge.AnonymousMethod()
CommonLanguageRuntimeLibrary!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext = {unknown}, System.Threading.ContextCallback callback = {unknown}, object state = {unknown}, bool preserveSyncCtx = {unknown})
CommonLanguageRuntimeLibrary!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext = {unknown}, System.Threading.ContextCallback callback = {unknown}, object state = {unknown}, bool preserveSyncCtx = {unknown})
CommonLanguageRuntimeLibrary!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext = {unknown}, System.Threading.ContextCallback callback = {unknown}, object state = {unknown})
CommonLanguageRuntimeLibrary!System.Threading.ThreadHelper.ThreadStart()
The error occurs because my web role project depends on Owin Version=3.0.1.0, but another DLL (which I get through nuget) depends on Owin Version=3.0.0.0. Hence the manifest mismatch.
So it seems like service runtime is still loading my assemblies in WaIISHost.exe just to check whether I do have RoleEntryPoint or not (I don't).
Just as before, as soon as I put myassembly.dll.config with binding redirects copied from web.config into E:\approot\bin, everything starts correctly.

Can you clarify what exactly you are looking for? You provide the answer in your question (add the redirects to app.config), and you provide a link to the explanation in one of your comments (http://blogs.msdn.com/b/avkashchauhan/archive/2011/01/24/dissection-of-a-windows-azure-sdk-1-3-based-asp-net-web-role-in-full-iis-mode-amp-hwc.aspx).
I can confirm that what you are seeing is the expected behavior and your solution of adding the binding redirects to app.config is correct.
The other potential solution would be to change your RoleEntrypoint code (ie. WebRole.cs) so that it does not depend on AssemblyB, Version=1.0. Whatever you are doing in the RoleEntrypoint class, can it be done from Application_Start so that it runs within IIS?

Azure support team provide AzureTools for help this kind of problem.
AzureTools have Fusion Logging on/off and easy to collect azure logs.
Once you enable Fusion Logging then you can get more information about missing assembly.
http://blogs.msdn.com/b/kwill/archive/2013/08/26/azuretools-the-diagnostic-utility-used-by-the-windows-azure-developer-support-team.aspx

Related

Azure App Service Application Settings Ignored, Using web.config Instead

I recently deployed an ASP.Net Web API project to our Azure App Service test slot but started receiving an error when making requests to the API endpoints. Through remote debugging, it became clear that the app was extracting my dev connection strings from the deployed web.config file.
The connection strings are supposed to come from the Application Settings we set up via the Azure Portal - and, in previous deployments, they were - but that's not the case.
Why would this happen and what can be done to ensure the correct behaviour occurs? We absolutely don't want our production database secrets being put into GIT via the web.config...
I recently experienced the same problem and fixed it:
In Azure App Services, the machine-wide web.config file is located at D:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config.
This file differs to a normal machine-wide web.config file because it has this extra element:
<system.web>
...
<compilation>
<assemblies>
<add assembly="EnvSettings, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
...
</assemblies>
</compilation>
</system.web>
The EnvSettings.dll assembly is located inside D:\Program Files\IIS\Microsoft Web Hosting Framework (unfortunately this directory is access-controlled and I can't get into it).
But EnvSettings.dll is mirrored in the GAC, so I was able to copy it from there.
Inside EnvSettings.dll is an [assembly: PreApplicationStartMethod] attribute that runs a method in EnvSettings.dll which copiesthe APPSETTING_ and database connection-string settings from Environment Variables into the .NET Framework ConfigurationManager.AppSettings and ConfigurationManager.ConnectionStrings collections.
Note this copying only happens once (during application startup), and only in the first AppDomain - so if you have other AppDomain instances in your application they won't see the updated ConfigurationManager.
Therefore, if you see that your Azure Portal configuration settings for your App Service are not being used when you dump your ConfigurationManager, then the following is likely happening:
You used <clear /> in your <compilation><assemblies> element, which stops EnvSettings.dll from being loaded at all.
In which case you need to either add back the <add assembly="EnvSettings... element from above to your own web.config, or find some other way to load it.
I don't recommend saving EnvSettings.dll locally and adding an assembly reference to your project, as EnvSettings.dll is part of the Microsoft Web Hosting Framework.
Or you have code that is clearing or resetting ConfigurationManager after EnvSettings populates it for you.
Or something else is going on that I have no idea about!
As an alternative to having EnvSettings.dll copy your settings over, another option is to copy the environment-variables over yourself - and as you control the code that does this it means you can call it whenever you need to (e.g. if you ever reset them).
Here's the code I used:
public static class AzureAppSettingsConfigurationLoader
{
public static void Apply()
{
foreach( DictionaryEntry environmentVariable in Environment.GetEnvironmentVariables() )
{
String name = (String)environmentVariable.Key;
String value = (String)environmentVariable.Value;
if( name.StartsWith( "APPSETTING_", StringComparison.OrdinalIgnoreCase ) )
{
String appSettingName = name.Substring( "APPSETTING_".Length );
ConfigurationManager.AppSettings[ appSettingName ] = value;
}
else if( name.StartsWith( "SQLAZURECONNSTR_", StringComparison.OrdinalIgnoreCase ) )
{
String csName = name.Substring( "SQLAZURECONNSTR_".Length );
ConfigurationManager.ConnectionStrings.Add( new ConnectionStringSettings( csName, value, providerName: ""System.Data.SqlClient" ) );
}
}
}
}
See my sample here: http://mvc5appsettings.azurewebsites.net/
// My web.config also has a "HERO_TEXT" key in
// that reads "Value from web.config"
string hero = ConfigurationManager.AppSettings["HERO_TEXT"];
Wiki page on App Settings for .NET:
https://github.com/projectkudu/kudu/wiki/Managing-settings-and-secrets
As already mentioned here, make sure you have that App Setting in the right slot.
As I know, the settings in Azure portal will override existing setting in Web.config. So If you want to ignore the Azure Application settings in portal and use Web.config instead. I am afraid you need to configure the settings in web.config, and remove the same key/pair in Azure portal.

Unable to find assembly on Azure Mobile Service

I have an Azure Mobile Service project which has a dependency to another (persistence) project which is referencing FluentNHibernate. Locally everything is running correctly in Release and Debug mode. Publishing the project seems to be successful (blue smiley). The problems starts when I make a request, where FluentNHibernate is used. I get the following error message:
Unable to find assembly 'FluentNHibernate, Version=2.0.3.0, Culture=neutral, PublicKeyToken=null'.
I already tried a lot of things:
Reinstalling packages
A new plain vanilla Mobile Service
Adding dependentAssembly in Web.config in the main project and App.config in the persistence project.
A little confusing for me is following fact: When I change the version of the FluentNHibernate package, I can see in the publish preview window that this dll will not be updated.
I am really not sure if this problem is depended to this specific package (FluentNHibernate). For example, what means: PublicKeyToken=null?
What else can I try to make the service running in the cloud?
The code below worked for my solution. It wires up a handler to the AppDomain's AssemblyResolve event, which is raised if an assembly cannot be found. In this case, I tell it to check the currently loaded assemblies and return one if there is a match, which there should be for FluentNHibernate. Try sticking this as the first line in WebApiConfig.Register
public static void Register()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
return AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.FullName == args.Name).FirstOrDefault();
};
// the rest of WebApiConfig.Register...
}

Creating OrganizationServiceProxy in CRM2011 Plugin

I have created a plugin and it was registered successfully (Sandbox Isolation Mode).
Inside Plugin execution, I want to create an object of OrganizationServiceProxy, which is using another CRM details. Using the code below:
Uri oUri = new Uri("https://yourorg.api.crm5.dynamics.com/XRMServices/2011/Organization.svc");
//** Your client credentials
ClientCredentials clientCredentials = new ClientCredentials();
clientCredentials.UserName.UserName = "YourAccount.onmicrosoft.com";
clientCredentials.UserName.Password = "YourAdminPassword";
//Create your Organization Service Proxy
OrganizationServiceProxy _serviceProxy = new OrganizationServiceProxy(
oUri,
null,
clientCredentials,
null);
I am getting Security Exception:
System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
Searched for the same issue but not working, Please suggest.
What version of .NET are you building this in ?
check out these links:
link 1
link 2
This error is usually caused by some process that doesn't have enough permissions to run. I had this issue before and it solved my problem.
I basically used the new AddFullTrustModuleInSandboxAppDomain method. (check links for more info)
Where exactly do you get this error? When trying to create the proxy ? Or when the plugin is trying to do something (create a report, .. ) ?
I have searched a lot but the plugin is registered in sandbox mode so it, doesn't allow to access external services.
Found the best way to use it.
Created Azure web service and use the service in Plugin, it works.

PCL Retargetable Assembly not redirected inside MS CRM Plugin

Calling
Assembly.Load("System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes");
inside a .net 4.03 application should redirect to the correct 4.0.0.0 System.Core
It works on my machine for a Console App and inside an ASPX page.
However calling it from inside a Dynamics MS CRM Plugin fails with
System.IO.FileNotFoundException: Could not load file or assembly 'System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes' or one of its dependencies. The system cannot find the file specified.
There are no FUSION errors either.
What is special about the way plugins are executed that the redirects are skipped?
I think I know what's happening. CRM very likely calling Assembly.LoadFile on your plug-in assembly. This is telling the CLR binder that it wants to handle all the logic that Fusion would normally handle (including the understanding of portable libraries, binding redirects, publisher policy, etc).
As you can see this is problematic - and calling this API is almost always the wrong thing to do, unless you really know what you are doing. Instead, they should probably be calling Assembly.LoadFrom which automatically applies this logic.
What can you do it about?
Without getting them to change, you should be able to hook up to AppDomain.Current.AssemblyResolve and apply the logic yourself that fusion would normally apply:
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string name = AppDomain.CurrentDomain.ApplyPolicy(args.Name);
try
{
return Assembly.Load(name);
}
catch (FileNotFoundException)
{
}
catch (FileLoadException)
{
}
catch (BadImageFormatException)
{
}
return null;
}
The problem with above is that you aren't going to be able to do this from a portable library. Either you need to this dynamically using Reflection, or have some sort of .NET Framework-specific entry point that runs before your portable assembly is loaded.

Sharepoint 2010 - web.config modification

We have a farm with 2 servers.
I have applied some changes to the web.config on both servers. (I have a specific web application i.e. I have applied the changes in the web.config of my sharepoint web application and NOT the default Sharepoint site or the central admin site)
But it seems that Sharepoint does not take into consideration these changes!
For example I added an assembly reference .... but sharepoint was still throwing an assembly reference exception. i had to add the assembly reference to each and every control.
I have also increased the execution timeout but it still gives timeouts.
This happens in the production environment only.
In the test (where there is a single server) I update the web.config and all changes work.
Is it because I should not be updating the web config. I have noticed there is an SPWebConfigModification class. Do I have to use this ? won't it do the same changes as I would have done manually.
Update ....
I have now used the SPWebConfigModification and also did an iisreset ... but the changes were simply ignored!
Update 2...
Some more details on my web.config updates
I had added an assembly reference under assemmblies sectuion, somethign like this:
This did not work as Sharepoint was still throwing an exception that the assembly cannot be found.
This problem only happens in the production environment. In dev and test, I was also receiving the exception but when I added the assembly reference above, the error disappeared.
Another thing which did not work is the executionTimeout. I have added this to the production environment but sharepoint is still giving timeouts an a long request wich we have. Again, this entry solved the problem in the test and development environments.
I wrote this for this for Sharepoint 2007, I think you need to modify the impersonation (RunWithElevatedPrivileges) but the rest should work:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate() {
try
{
Trace.WriteLine("Try to modify web.config");
SPWebApplication myWebApp = ((SPWeb)properties.Feature.Parent).Site.WebApplication;
WebConfigModifier mod = new WebConfigModifier(myWebApp, OwnerString);
mod.AddModification(
"SafeControl[#Assembly='Elsni.WorldsBestProgram, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e7639c2c71f2f003']",
"configuration/SharePoint/SafeControls",
"<SafeControl Assembly='Elsni.WorldsBestProgram, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e7639c2c71f2f003' Namespace='GFA.UniversalListSyncSolution' TypeName='*' Safe='True' />"
);
mod.AddModification(
"add[#key='PropertiesSiteUrl']",
"configuration/appSettings",
"<add key=\"PropertiesSiteUrl\" value=\"http://iei-developersy/sites/gfaadmin/\" />"
);
mod.Update();
Trace.WriteLine("Done.");
}
catch (Exception ex)
{
Trace.WriteLine("ERROR while activating feature: " + ex.Message);
}
}
});
}
As you have pointed out, you need to make these changes using the SPWebConfigModification class. It is possible to make the changes manually, however, this usually results in random issues caused by replication issues etc ....
The SPWebConfigModification class will ensure the change is stored in the SP database and amend the web.config files on your behalf.

Resources