PCL Retargetable Assembly not redirected inside MS CRM Plugin - dynamics-crm-2011

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.

Related

Why can't my Azure Function find Microsoft.Xrm.Sdk assembly dependencies?

I'm using Azure Functions and want to write code that reads/writes to Dynamics CRM Online. I added the CRM 2015 SDK DLLs (all of them) to a bin folder under where the function.json file resides per Microsoft's documentation.
The function compiles fine.
When running the function I get this error:
Exception while executing function: Functions.CrmTest1. mscorlib: Exception has been thrown by the target of an invocation. Could not load file or assembly 'Microsoft.Xrm.Sdk, Version=7.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
Here's the function body (just a small test sample):
#r "Microsoft.Xrm.Sdk.dll"
#r "Microsoft.Xrm.Client.dll"
using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
public static void Run(string input, TraceWriter log)
{
var connectionString = "AuthType=Office365;Username=me#contoso.com; Password=MyPassword;Url=https://contoso.crm.dynamics.com";
CrmConnection connection = CrmConnection.Parse (connectionString);
using ( OrganizationService orgService = new OrganizationService(connection))
{
var query = new QueryExpression("account");
query.ColumnSet.AddColumns("name");
var ec = orgService.RetrieveMultiple(query);
log.Verbose(ec[0].GetAttributeValue<string>("name"));
}
}
There's no indication in the log files what needed assembly can't be found.
What am I missing with getting this to work? How can I find out what DLL is needed but is not found?
Tim,
The latest deployment that went live today contains the fix to address the issue you ran into. Please try again (you may need to restart your site to pick up the latest version if you had functions running) and let me know if you have any problems.
Thanks again for reporting this! I'm looking forward to seeing what you'll put together with Functions and Dynamics CRM.

Why doesn't Azure load properly the Interop?

I have a WebApp on Azure that uses a dll. This library needs Interop libraries x86 and x64.
Sometimes, at the restart of the App (I suppose), the App fails due to an exception:
System.EntryPointNotFoundException: Unable to find an entry point named 'sqlite3_config' in DLL 'SQLite.Interop.dll'. at System.Data.SQLite.UnsafeNativeMethods.sqlite3_config_none(SQLiteConfigOpsEnum op) at System.Data.SQLite.SQLite3.StaticIsInitialized() at System.Data.SQLite.SQLiteLog.Initialize() at System.Data.SQLite.SQLiteConnection..ctor(String connectionString, Boolean parseViaFramework) at T_Dox.WebService.SQLiteDb.CreateConnection() at WebService.CeDb.Connect()
The SQLite used is the SQLCipher's one.
What am I missing here? I don't understand why the app stops working suddenly even if I don't make any changes.
The App is a Web Service (.asmx file) that uses a data access layer to perform some business logic.
It was under a web site project, then we moved it into another project, a webapi\mvc project.
The routing bypasses this extension, so it works as before, a simple web service call.
The called web method initializes a business class loaded from another .net library (a VB.Net library).
Inside, this class uses a wrapper to a sqlConnection, in this case the SQLiteConnection.
In its constructor it starts an SQLiteConnection, and normally it works.
Then it performs some CRUD operations ...
So I can represent the operation this way:
[WebService(Namespace = "...")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class SampleService : System.Web.Services.WebService
{
[WebMethod]
public ServerInfo Test()
{
var sampleBusinessClass = new SampleBusinessCLass();
sampleBusinessClass.DoSomething();
using(var connection = new SQLiteConnection()) //the constructor is the parameterless one
{
//...
}
}
}
And the stack will be this (this is not the real one):
System.EntryPointNotFoundException: Unable to find an entry point named 'sqlite3_config' in DLL 'SQLite.Interop.dll'.
at System.Data.SQLite.UnsafeNativeMethods.sqlite3_config_none(SQLiteConfigOpsEnum op)
at System.Data.SQLite.SQLite3.StaticIsInitialized()
at System.Data.SQLite.SQLiteLog.Initialize()
at System.Data.SQLite.SQLiteConnection..ctor(String connectionString, Boolean parseViaFramework)
at xxx.WebService.SampleService.Test()
It always works, but sometimes it starts to launch this error until the stop and start of the web application on iss (in our case: Azure).
Inspecting the System.Data.SQlite.dll I can clearly see the entry point and actually it always passes this internal code (no conditions that can bypass this part) and it generally works.
The System.Data.SQlite.dll (1.0.96.0 version) is provided by SqlCypher product. I think it is the original System.Data.SQLite one because at first sight I can see the same assembly manifest and content.
The interop System.Data.SQLite uses is probably modified by SqlCypher team to give their features.
To avoid possible issues we put the interop in the path /bin/x64, then we compile our web app ONLY in x64 and it runs on a x64 environment.

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...
}

Web role failing to start because dependent assembly cannot be loaded

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

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