System.Security.VerificationException: Operation could destabilize the runtime. (Subsonic 2.2) - c#

I recently tried to upgrade a .net 2.0 project which had its DAL generated by SubSonic 2.2 to .NET 4.0 under Visual Studio 2010.
The projects converted without error but now I am getting a rather vile error message when I try to launch it.
System.Security.VerificationException: Operation could destabilize the runtime.
at SubSonic.DataProvider.ApplyConfig(NameValueCollection config, Boolean& parameterValue, String configName) in C:\Documents and Settings\Desktop\4.0 Production\rel_1.0\server\Server.DAL\Server.DAL.SubSonic\DataProviders\DataProvider.cs:line 955
at SubSonic.DataProvider.Initialize(String name, NameValueCollection config) in C:\Documents and Settings\Desktop\4.0 Production\rel_1.0\server\Server.DAL\Server.DAL.SubSonic\DataProviders\DataProvider.cs:line 916
at System.Web.Configuration.ProvidersHelper.InstantiateProvider(ProviderSettings providerSettings, Type providerType)
The code where it is throwing the exception:
ApplyConfig(config, ref extractClassNameFromSPName, ConfigurationPropertyName.EXTRACT_CLASS_NAME_FROM_SP_NAME);
private static void ApplyConfig(System.Collections.Specialized.NameValueCollection config, ref bool parameterValue, string configName)
{
if(config[configName] != null)
{
parameterValue = Convert.ToBoolean(config[configName]);
}
}
It performs similar calls to here, the only difference being it is strictly a string and not a boolean it is manipulating.
private static void ApplyConfig(System.Collections.Specialized.NameValueCollection config, ref string parameterValue, string configName)
{
if(config[configName] != null)
{
parameterValue = config[configName];
}
}
config is defined as a System.Collections.Specialized.NameValueCollection with 3 keys
generateNullableProperties, connectionStringName, generatedNamespace
extractClassNameFromSPName == false
EDIT1: The code that kicks off the error is in the Application_Start() method of the Global.asax
System.Data.SqlClient.SqlDependency.Start(SystemSetting.Schema.Provider.DefaultConnectionString);
EDIT2: The error bubbles out to thowing a targetinvocation error referening my web.config
<SubSonicService defaultProvider="appPlan">
<providers>
<clear/>
<add name="appPlan" type="SubSonic.SqlDataProvider, appPlan.Server.DAL.SubSonic" generateNullableProperties="false" connectionStringName="appPlan" generatedNamespace="appPlan.Server.DAL"/>
</providers>
</SubSonicService>
has anybody else ever run across such an issue? I could upgrade to SubSonic3.x but it would be a much greater undertaking I believe.
thanks.

I have seen this exception before when generating assemblies directly from hand-crafted IL. The .NET runtime verifies the raw instructions in an assembly for correctness, especially when loading the assembly into restricted contexts. For example, there is a check to ensure that the required number of arguments are loaded onto the call-stack before executing a method.
An assembly can still be loaded even if verification fails; but it can only be run in full trust. In partial trust scenarios you get this "operation could destabilize the runtime" error. The reason being that the runtime cannot guarantee safe operation of assemblies in partial trust if they do not "behave correctly".
You can manually check an assembly using the PEVERIFY tool (available via a Visual Studio Command Prompt). Try verifying all of the referenced assemblies to see what is reported. I suspect there was a change in the verification rules between .NET 2.0 and .NET 4.0 that is now causing verification to fail for one of the SubSonic 2.2 assemblies.
Your cheat you mention in response to Fun Mun Pieng also suggests verification is the issue.

Does this fix the problem?
private static void ApplyConfig(System.Collections.Specialized.NameValueCollection config, ref bool parameterValue, string configName)
{
if(config[configName] != null)
{
string val = config[configName];
parameterValue = Convert.ToBoolean(val);
}
}
If not, then try
string val = config[configName];
if (val.ToLower() == "false")
parameterValue = false;
else
parameterValue = true;
There may be 2 reasons why the original code fails. First, earlier version of .NET (probably 1.1) had some type issue. I don't know what exactly, but I suspect it might have failed to identify the type of the value passed straight from the NameValueCollection into ToBoolean. The second possibility is that the value is not "true" or "false", but something else. Again, these 2 may or may not be the reason. I can't know for sure because I don't have SubSonic 2.2.

Related

MissingFieldException (AmbientTransactionWarning) using EF Core in Revit addin

I'm using Pomelo.EntityFrameworkCore.MySql (3.1.1) to save some data to MySql. When the context is first configured I'm getting this exception:
Exception thrown: 'System.MissingFieldException' in Pomelo.EntityFrameworkCore.MySql.dll
Field not found: 'Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.AmbientTransactionWarning'
Here's my OnConfiguring:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
// This works just fine, even though that type is then not available in `UseMySql`.
var test = Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.AmbientTransactionWarning;
// Exception thrown here.
optionsBuilder.UseMySql("server=localhost;database=test;uid=user;pwd=<password>;TreatTinyAsBoolean=true;", x => x.ServerVersion(new Version(5, 7, 29), ServerType.MySql));
}
}
Possible complicating factor: The app is an addin for Autodesk Revit. I've had some dll loading issues which I believe I've worked out, but it is a non-standard environment which could be causing issues. I've verified that Microsoft.EntityFrameworkCore.Relational, the dll that provides AmbientTransactionWarning, is loaded when UseMySql is called. Also, while VS is paused on the exception, if I enter Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.AmbientTransactionWarning in the Immediate window, I don't get an error. I also have another stand-alone WPF app that uses the same database model and DbContext object, which communicates with the database just fine.
I'm not sure how to proceed in debugging this. Thanks!
Edit
Both the addin and Revit (2020) are using .NET Framework 4.7.2.
Stacktrace:
Field not found: 'Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.AmbientTransactionWarning'.
at Microsoft.EntityFrameworkCore.MySqlDbContextOptionsExtensions.ConfigureWarnings(DbContextOptionsBuilder optionsBuilder)
at Microsoft.EntityFrameworkCore.MySqlDbContextOptionsExtensions.UseMySql(DbContextOptionsBuilder optionsBuilder, String connectionString, Action`1 mySqlOptionsAction)
at <MyAssembly>.DatabaseContext.OnConfiguring(DbContextOptionsBuilder optionsBuilder)
Library Loading
Typically Revit addins load their dependencies automatically as needed. Occasionally not, though, so I have added the following resolver which manually loads assemblies which in past runs have failed to load automatically:
// Executed on first run of addin.
AppDomain.CurrentDomain.AssemblyResolve += ResolveMissingAssemblies;
...
private System.Reflection.Assembly ResolveMissingAssemblies(object sender, ResolveEventArgs args)
{
string[] dlls = new[]
{
"System.Memory",
"System.Buffers",
"System.Threading.Tasks.Extensions",
"System.Runtime.CompilerServices.Unsafe",
"Microsoft.EntityFrameworkCore.Relational",
"Microsoft.EntityFrameworkCore",
"MySqlConnector",
};
string dll = dlls.FirstOrDefault(name => args.Name.Contains(name));
if (!string.IsNullOrEmpty(dll))
{
string filename = Path.Combine(
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
$"{dll}.dll");
if (File.Exists(filename))
{
return System.Reflection.Assembly.LoadFrom(filename);
}
}
return null;
}
The more I look at this the more it seems that somehow the field in question is available in my main assembly but not in EntityFrameworkCore. I'm not sure why or how that would be the case. I've also tried using IlMerge to combine various parts of the addin, but haven't been able to get anything working in that direction.
This is likely an issue in resolving dependent assemblies.
You probably want to debug your ResolveMissingAssemblies() method (or log all assemblies that your event handler is unable to resolve).
Also output/take a look at the ResolveEventArgs.RequestingAssembly property, that tells you what assembly the current one is a dependency of (to understand the dependency tree).
The Microsoft.EntityFrameworkCore.Relational assembly e.g. depends on Microsoft.EntityFrameworkCore, which depends on 10 other libraries (some of which depend on other libraries again).
A simple way to ensure they are all being loaded, is to make your event handler a bit more generic:
private System.Reflection.Assembly ResolveMissingAssemblies(object sender, ResolveEventArgs args)
{
string filename = Path.Combine(
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
$"{args.Name}.dll");
return File.Exists(filename))
? System.Reflection.Assembly.LoadFrom(filename)
: null;
}

Executable fails with weird exception

I am using ILMerge and Quartz.NET in a C# .NET 4.0 Windows Service application. The app runs fine without using ILMerge, but now that we're nearing shipping release, I wanted to combine all DLLs into a single executable.
Problem is, that ILMerge seems to work fine, but when I run the combined executable, it throws this exception:
Unhandled Exception: Quartz.SchedulerException: ThreadPool type 'Quartz.Simpl.SimpleThreadPool' could not be instantiated. ---> System.InvalidCastException: Unable to cast object of type 'Quartz.Simpl.SimpleThreadPool' to type 'Quartz.Spi.IThreadPool'.
at Quartz.Util.ObjectUtils.InstantiateType[T](Type type) in :line 0
at Quartz.Impl.StdSchedulerFactory.Instantiate() in :line 0
--- End of inner exception stack trace ---
at Quartz.Impl.StdSchedulerFactory.Instantiate() in :line 0
at Quartz.Impl.StdSchedulerFactory.GetScheduler() in :line 0
Does anyone have any idea why this is? I have been wasting over 4 hours already and I can't figure it out. If I don't combine with ILMerge, then everything runs fine (with the Quartz.dll and Common.Logging.dll in the same directory).
I'm sure someone must have tried packaging Quartz.net up like this before, any ideas?
Disclaimer: I don't know Quartz.NET at all, although I spent some time struggling with ILMerge. When I finally understood its limitations... I stopped using it.
ILMerge'd application tends to have problems with everything which contains the word "reflection".
I can guess (I've never used Quartz.NET) that some classes are resolved using reflection and driven by configuration files.
Class is not only identified by its name (with namespace) but also by assembly it is coming from (unfortunatelly it doesn't get displayed in exception message).
So, let's assume you had (before ILMerging) two assemblies A (for you Application) and Q (for Quartz.NET).
Assembly 'A' was referencing assembly 'Q' and was using a class 'Q:QClass' which was implementing 'Q:QIntf'.
After merging, those classes became 'A:QClass' and 'A:QIntf' (they were moved from assembly Q to A) and all the references in code has been replaced to use those (completely) new classes/interfaces, so "A:QClass" is implementing "A:QIntf" now.
But, it did not change any config files/embedded strings which may still reference "Q:QClass".
So when application is reading those not-updated config files it still loads "Q:QClass" (why it CAN find it is a different question, maybe you left assembly 'Q' in current folder or maybe it is in GAC - see 1).
Anyway, "Q:QClass" DOES NOT implement "A:QIntf", it still implements "Q:QIntf" even if they are binary identical - so you can't cast 'Q:QClass' to 'A:QIntf'.
The not-ideal-but-working solution is to "embed" assemblies instead of "merging" them. I wrote a open-source tool which does it (embedding instead of merging) but it is not related to this question. So if you decide to embed just ask me.
You can test it by removing (hiding, whatever works for you) every single instance of Q.dll on your PC. If I'm right, the exception should say now 'FileNotFound'.
You could try creating your own ISchedulerFactory and avoid using reflection to load all of your types.
The StdSchedulerFactory uses this code to creat a threadpool. It's where your error is happening and would be the place to start looking at making changes:
Type tpType = loadHelper.LoadType(cfg.GetStringProperty(PropertyThreadPoolType)) ?? typeof(SimpleThreadPool);
try
{
tp = ObjectUtils.InstantiateType<IThreadPool>(tpType);
}
catch (Exception e)
{
initException = new SchedulerException("ThreadPool type '{0}' could not be instantiated.".FormatInvariant(tpType), e);
throw initException;
}
The ObjectUtils.InstantiateType method that is called is this one, and the last line is the one throwing your exception:
public static T InstantiateType<T>(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type", "Cannot instantiate null");
}
ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);
if (ci == null)
{
throw new ArgumentException("Cannot instantiate type which has no empty constructor", type.Name);
}
return (T) ci.Invoke(new object[0]);
}
Right after this section in the factory, datasources are loaded using the same pattern and then the jobs themselves are also loaded dynamically which means you'd also have to write your own JobFactory. Since Quartz.Net loads a bunch of bits and pieces dynamically at runtime going down this road means you might end up rewriting a fair amount of things.

How to execute different statements based on the file version of a referenced dll?

I have a C# dll that references a 3rd party dll. There are different versions of the 3rd party dll.
As you might expect if the latest 3rd Party dll is present I want to use the new functionality if not I want to execute the old functionality.
I wasn't sure how to achieve this but I thought the first thing to try would be a simple if statement that decides which function to call.
So I find the assembly, get its location and hence its version info. (I need the file version as the product versions are the same).
Then a simple
if (version >= 3) do x() else do y()
When I execute the code on a machine with version 2 installed I get a MissingMethodException regarding x(). I thought I had made a stupid mistake but the logic was correct. The version is 2 so x(); should not be executed. I decided to remove the offending method and replace it with a throw new Exception(). The exception is not thrown and the code completes successfully.
Here is the danger - I am thinking that this is due to branch prediction. This is dangerous because it is not an area I have any knowledge of and therefore making assumptions is a dangerous thing.
So my questions are:
Am I tacking this problem the wrong way - is there a more obvious solution that I am missing?
or
Is there a way to disable branch prediction (if that is the cause) or to somehow enforce/flag the if condition as a point that must be executed before continuing.
Here is the code being executed:
On a machine with version 3 installed then it is fine.
On a machine with version 2 installed I get a MissingMethodException regarding method x().
It I removed the call to x(); and uncomment the throwing of the exception - no exception is thrown.
Relevant code:
Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(3rdPartyClass));
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
if (fileVersionInfo.FileMajorPart >= 3)
{
// throw new Exception("aagghh");
x();
}
else
{
y();
}
Using reflection, it's possible to get a list of Methods available for a particular DLL (more specifically: Type).
You could use this methodinfo to dynamically invoke the method as specified in Vlad's solution.
In fact, you could leave out the version check and just try to find the intended method directly.
var methodX = assembly.GetType("sometype").GetMethod("X");
if (methodX != null)
{
methodX.Invoke(params);
}
else
{
assembly.GetType("sometype").GetMethod("Y").Invoke(otherParams);
}
Edit: This is not exactly what you want, but with this kind of reflection you can find the correct methods, also for your own assembly.
There is no "branch prediction": the runtime binding seems to happen as the method is executed.
So the workaround would be like this:
if (fileVersionInfo.FileMajorPart >= 3)
{
CallX();
}
else
{
CallY();
}
void CallX()
{
DependentClass.X();
}
void CallY()
{
DependentClass.Y();
}
However, anyway this seems to be a hack: you need to execute with the version of DLL you were linking against.
This is actually a more accurate answer :
Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(String));
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
ObjectHandle oh = Activator.CreateInstanceFrom("AssemblyName.dll", "namespace.class");
object o = oh.Unwrap();
Type to = o.GetType();
if (fileVersionInfo.FileMajorPart >= 3)
{
to.InvokeMember("Method X", BindingFlags.InvokeMethod, null, o, null);
}
else
{
to.InvokeMember("Method Y", BindingFlags.InvokeMethod, null, o, null);
}

Is there a way I can safely check to see if an assembly CAN be loaded before I actually do so?

I am working on some software that will dynamically build menu items for certain dlls so that we can load components in dynamically based on what dlls are available on the users machine. Any dlls that I want to load have been flagged with an Assembly Attribute in the AssemblyInfo.cs file and how I determine whether or not I want to build a menu item for that dll. Here is my method so far:
private void GetReportModules() {
foreach (string fileName in Directory.GetFiles(Directory.GetCurrentDirectory())) {
if (Path.GetExtension(fileName) == ".dll" || Path.GetExtension(fileName) == ".exe") {
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(fileName);
object[] attributes = assembly.GetCustomAttributes(typeof(ReportNameAttribute), false);
if (attributes.Count() > 0) {
ReportNameAttribute reportNameAttribute = attributes[0] as ReportNameAttribute;
Type type = assembly.GetType(reportNameAttribute.BaseType);
MenuItem customReportsMenuItem = new MenuItem();
customReportsMenuItem.Header = reportNameAttribute.ReportName;
ReportsMenuItem.Items.Add(customReportsMenuItem);
customReportsMenuItem.Click += (s, ev) => {
var obj = Activator.CreateInstance(type);
type.InvokeMember("Show", System.Reflection.BindingFlags.Default | System.Reflection.BindingFlags.InvokeMethod, null, obj, null);
};
}
}
}
}
For the most part its working fine, I am getting the dlls that I am expecting back out and am creating my menu items fine. The problem is that in order to check for the attribute I first need to load the assembly using Reflection. Some of the other local dlls are throwing errors when I try to load them about missing dependencies or he module was expected to contain an assembly manifest. Is there a way I can safely check to see if an assembly CAN be loaded before I actually do so? (sounds stupid as I write it out). Any thoughts on the problem I'm running into or better suggestions for how to accomplish what I'm trying here? Feeling a little bit in over my head.
You can create a separate AppDomain, try to load the assemblies there, send the results back, and unload the AppDomain. This way you do not change your current AppDomain with 'garbage' of any loaded assemblies.
One way would be to make use of a try catch block. If it throw's an exception, you're not interested...
EDIT:
MSDN explains clearly the type of exceptions LoadFrom can throw. FileLoadException looks likely in your case.
I'm sure there is code out there that carried on after a catch. For example a logging framework. I would not want my framework to catch an exception and make my executable stop etc, i'd want it to smother the exception. My application should not fail just because a line of log miss fired.
You can try the Unmanaged Metadata API (http://msdn.microsoft.com/en-us/library/ms404384.aspx) or the Common Compiler Infrastructure Metadata API (http://ccimetadata.codeplex.com/) as alternatives to plain reflection.

ASP.net exception "FileNotFoundException" after idle when assembly file is present in the bin folder

The file is present, correctly named and not corrupted. If I move it out and back in from the "Bin", it works again, for about 5 minutes, then the error bellow comes back. Any operation that refreshes the file is fine, publishing it the anew, renaming or moving makes the site work again, for a moment.
{"Message":"Could not load file or assembly \u0027Ouranos,
Version=1.0.0.0, Culture=fr-CA, PublicKeyToken=null\u0027 or one of
its dependencies. Le fichier spécifié est introuvable.","StackTrace":"
at Services.Asynchrone(String DimensionX, String DimensionY, String
Action, String Culture, String Utilisateur, String Interface, String
Source, String Champ, String Valeur, String Classement, String
Direction, StriFileNotFoundExceptionng Page, String
Itérations)","ExceptionType":"System.IO."}
Fusion did give me an error code (0x80070002), which pointed me to get Process Monitor. Which lead me to the temporary assembly folder. Now I may be wrong about this. Comparing the cache files from an healthy website and the sick one, I noticed something odd.
Healthy website as all the DLL from the BIN in cache.
The sick website is missing two DLL in the cache that are present in the BIN.
Now, I know that ASP.net tends to say that the main library is missing when it's in fact one of the referenced library that is missing. In this current situation I don't know what I could do to fix that problem. The two DLL are not set in the cache, thus when it tries to load the main DLL it fails locating the two others from the cache and throws a file not found on the main DLL.
The two culprits are:
PresentationCore.dll
WindowsBase.dll
To troubleshot this kinf of errors, you can use Fusion log, instructions about how to enable it and how to use it can be found here: How to enable assembly bind failure logging (Fusion) in .NET.
It would seem that the following code actually fixes the problem. It checks for all the required assemblies for the assembly and loads the missing. I had such a code before and it did not work, because without the !(Assemblée is System.Reflection.Emit.AssemblyBuilder) && (Assemblée.GetType().FullName != "System.Reflection.Emit.InternalAssemblyBuilder") was not present and has the code causing an exception in .net 4.0 and over. It's not elegant, but it does the job.
public static void Chargeur()
{
var Assemblées_Chargées = (from Assembly Assemblée in AppDomain.CurrentDomain.GetAssemblies() where !(Assemblée is System.Reflection.Emit.AssemblyBuilder) && (Assemblée.GetType().FullName != "System.Reflection.Emit.InternalAssemblyBuilder") && (!Assemblée.GlobalAssemblyCache) && (Assemblée.CodeBase != Assembly.GetExecutingAssembly().CodeBase) select Assemblée).ToList();
var Chemins_Chargés = Assemblées_Chargées.Select(Assemblée => Assemblée.Location).ToArray();
var Chemins_Référencés = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
var Assemblées_NonChargées = Chemins_Référencés.Where(Références => !Chemins_Chargés.Contains(Références, StringComparer.InvariantCultureIgnoreCase)).ToList();
Assemblées_NonChargées.ForEach(path => Assemblées_Chargées.Add(AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path))));
}

Categories