System.TypeLoadException

The exception that is thrown when type-loading failures occur.

Minimum version: >= 1.1 >= Core 1.0

Statistics

16
elmah.io logo 19
13

How to handle it

try
{

}
catch (System.TypeLoadException e)
{

}
try
{

}
catch (System.TypeLoadException e) when (e.Message.Contains("something"))
{

}
try
{

}
catch (System.TypeLoadException e) when (LogException(e))
{

}

private static bool LogException(Exception e)
{
    logger.LogError(...);
    return false;
}

How to avoid it

TypeLoadException happens when a type could not be loaded by the CLR. This can be caused by several different issues, but here's a list of things to try out:

  • Locate the DLL file containing the type that could not be loaded in the build folder (typically Debug or Release). Make sure that the DLL files exist.
  • Right-click the DLL file and go to the Details tab and make sure that the DLL has the expected version number.
  • Make sure to use the same version of a NuGet package in all projects.
  • Search the app.config or web.config for any references to the assembly name of the missing type. There may be an unexpected binding redirect set up to the wrong version number.

Links

YouTube videos

Possible fixes from StackOverflow

Since many different problems can cause this error page, I can strongly recommend the following in order to determine the root cause quickly and easily, without wrestling Azure (or any server/platform for that matter) to get logs.

You can enable extremely helpful developer friendly error messages at startup by setting the .UseSetting("detailedErrors", "true") and .CaptureStartupErrors(true) actions in your Program.cs file.

For ASP.NET Core 1.x

public static void Main(string[] args)
{
  var host = new WebHostBuilder()
      .UseKestrel()
      .UseContentRoot(Directory.GetCurrentDirectory())
      .UseSetting("detailedErrors", "true")
      .UseIISIntegration()
      .UseStartup<Startup>()
      .CaptureStartupErrors(true)
      .Build();

  host.Run();
}

(2018/07) Update for ASP.NET Core 2.1

public class Program  
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .CaptureStartupErrors(true)
            .UseSetting("detailedErrors", "true")
            .UseStartup<Startup>()
            .Build();
}
  • These settings should be removed as soon as your troubleshooting is complete so as not to expose your application to malicious attacks.

According to the MSDN, in .NET 4.0 basically you should not use ISerializable for partially trusted code, and instead you should use ISafeSerializationData

Quoting from https://docs.microsoft.com/en-us/dotnet/standard/serialization/custom-serialization

Important

In versions previous to .NET Framework 4.0, serialization of custom user data in a partially trusted assembly was accomplished using the GetObjectData. Starting with version 4.0, that method is marked with the SecurityCriticalAttribute attribute which prevents execution in partially trusted assemblies. To work around this condition, implement the ISafeSerializationData interface.

So probably not what you wanted to hear if you need it, but I don't think there's any way around it while keeping using ISerializable (other than going back to Level1 security, which you said you don't want to).

PS: the ISafeSerializationData docs state that it is just for exceptions, but it doesn't seem all that specific, you may want to give it a shot... I basically can't test it with your sample code (other than removing ISerializable works, but you knew that already)... you'll have to see if ISafeSerializationData suits you enough.

PS2: the SecurityCritical attribute doesn't work because it's ignored when the assembly is loaded in partial trust mode (on Level2 security). You can see it on your sample code, if you debug the target variable in ExecuteUntrustedCode right before invoking it, it'll have IsSecurityTransparent to true and IsSecurityCritical to false even if you mark the method with the SecurityCritical attribute)

EF calls CreateWebHostBuilder or BuildWebHost without running Main. So Iconfiguration is null.

Create new class which inherited from IDesignTimeDbContextFactory .

public class YourDbContext : DbContext
{
//Dbcontext implementation
}

public class YourDbContextFactory : IDesignTimeDbContextFactory<YourDbContext>
{
    public YourDbContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder<YourDbContext>();
        optionsBuilder.UseSqlServer("your connection string");

        return new YourDbContext(optionsBuilder.Options);
    }
}

You are using a new .net core EF which uses IHostBuilder.(in an older version like yours the provider is IWebHostBuilder).

The tools first try to obtain the service provider by invoking the Program.CreateHostBuilder(), calling Build(), then accessing the Services property.

You can learn more about Design-time DbContext Creation from Here

It may happen from a condition in your startup file or while you are injecting. for example, you have a flag that checks if some variable in appsettings is true to use inmemory database instance.

EF needs to build the model and use the DbContext without starting the application. When EF invokes methods, your config services are still null that's why you get an error.

Make sure you have installed the package

Microsoft.EntityFrameworkCore.Tools

The accepted answer is so convincing that I almost believed this wasn't a bug. But after doing some experiments now I can say that Level2 security is a complete mess; at least, something is really fishy.

A couple of days ago I bumped into the same issue with my libraries. I quickly created a unit test; however, I could not reproduce the problem I experienced in .NET Fiddle, while the very same code "successfully" threw the exception in a console app. In the end I found two weird ways to overcome the issue.

TL;DR: It turns out that if you use an internal type of the used library in your consumer project, then the partially trusted code works as expected: it is able to instantiate an ISerializable implementation (and a security critical code cannot be called directly, but see below). Or, which is even more ridiculous, you can try to create the sandbox again if it didn't work for the first time...

But let's see some code.

ClassLibrary.dll:

Let's separate two cases: one for a regular class with security critical content and one ISerializable implementation:

public class CriticalClass
{
    public void SafeCode() { }

    [SecurityCritical]
    public void CriticalCode() { }

    [SecuritySafeCritical]
    public void SafeEntryForCriticalCode() => CriticalCode();
}

[Serializable]
public class SerializableCriticalClass : CriticalClass, ISerializable
{
    public SerializableCriticalClass() { }

    private SerializableCriticalClass(SerializationInfo info, StreamingContext context) { }

    [SecurityCritical]
    public void GetObjectData(SerializationInfo info, StreamingContext context) { }
}

One way to overcome the issue is to use an internal type from the consumer assembly. Any type will do it; now I define an attribute:

[AttributeUsage(AttributeTargets.All)]
internal class InternalTypeReferenceAttribute : Attribute
{
    public InternalTypeReferenceAttribute() { }
}

And the relevant attributes applied to the assembly:

[assembly: InternalsVisibleTo("UnitTest, PublicKey=<your public key>")]
[assembly: AllowPartiallyTrustedCallers]
[assembly: SecurityRules(SecurityRuleSet.Level2, SkipVerificationInFullTrust = true)]

Sign the assembly, apply the key to the InternalsVisibleTo attribute and prepare for test project:

UnitTest.dll (uses NUnit and ClassLibrary):

To use the internal trick the test assembly should be signed as well. Assembly attributes:

// Just to make the tests security transparent by default. This helps to test the full trust behavior.
[assembly: AllowPartiallyTrustedCallers] 

// !!! Comment this line out and the partial trust test cases may fail for the fist time !!!
[assembly: InternalTypeReference]

Note: The attribute can be applied anywhere. In my case it was on a method in a random test class took me a couple of days to find.

Note 2: If you run all test methods together it can happen that the tests will pass.

The skeleton of the test class:

[TestFixture]
public class SecurityCriticalAccessTest
{
    private partial class Sandbox : MarshalByRefObject
    {
    }

    private static AppDomain CreateSandboxDomain(params IPermission[] permissions)
    {
        var evidence = new Evidence(AppDomain.CurrentDomain.Evidence);
        var permissionSet = GetPermissionSet(permissions);
        var setup = new AppDomainSetup
        {
            ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
        };

        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        var strongNames = new List<StrongName>();
        foreach (Assembly asm in assemblies)
        {
            AssemblyName asmName = asm.GetName();
            strongNames.Add(new StrongName(new StrongNamePublicKeyBlob(asmName.GetPublicKey()), asmName.Name, asmName.Version));
        }

        return AppDomain.CreateDomain("SandboxDomain", evidence, setup, permissionSet, strongNames.ToArray());
    }

    private static PermissionSet GetPermissionSet(IPermission[] permissions)
    {
        var evidence = new Evidence();
        evidence.AddHostEvidence(new Zone(SecurityZone.Internet));
        var result = SecurityManager.GetStandardSandbox(evidence);
        foreach (var permission in permissions)
            result.AddPermission(permission);
        return result;
    }
}

And let's see the test cases one by one

Case 1: ISerializable implementation

The same issue as in the question. The test passes if

  • InternalTypeReferenceAttribute is applied
  • sandbox is tried to be created multiple times (see the code)
  • or, if all the test cases are executed at once and this is not the first one

Otherwise, there comes the totally inappropriate Inheritance security rules violated while overriding member... exception when you instantiate SerializableCriticalClass.

[Test]
[SecuritySafeCritical] // for Activator.CreateInstance
public void SerializableCriticalClass_PartialTrustAccess()
{
    var domain = CreateSandboxDomain(
        new SecurityPermission(SecurityPermissionFlag.SerializationFormatter), // BinaryFormatter
        new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)); // Assert.IsFalse
    var handle = Activator.CreateInstance(domain, Assembly.GetExecutingAssembly().FullName, typeof(Sandbox).FullName);
    var sandbox = (Sandbox)handle.Unwrap();
    try
    {
        sandbox.TestSerializableCriticalClass();
        return;
    }
    catch (Exception e)
    {
        // without [InternalTypeReference] it may fail for the first time
        Console.WriteLine($"1st try failed: {e.Message}");
    }

    domain = CreateSandboxDomain(
        new SecurityPermission(SecurityPermissionFlag.SerializationFormatter), // BinaryFormatter
        new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)); // Assert.IsFalse
    handle = Activator.CreateInstance(domain, Assembly.GetExecutingAssembly().FullName, typeof(Sandbox).FullName);
    sandbox = (Sandbox)handle.Unwrap();
    sandbox.TestSerializableCriticalClass();

    Assert.Inconclusive("Meh... succeeded only for the 2nd try");
}

private partial class Sandbox
{
    public void TestSerializableCriticalClass()
    {
        Assert.IsFalse(AppDomain.CurrentDomain.IsFullyTrusted);

        // ISerializable implementer can be created.
        // !!! May fail for the first try if the test does not use any internal type of the library. !!!
        var critical = new SerializableCriticalClass();

        // Critical method can be called via a safe method
        critical.SafeEntryForCriticalCode();

        // Critical method cannot be called directly by a transparent method
        Assert.Throws<MethodAccessException>(() => critical.CriticalCode());
        Assert.Throws<MethodAccessException>(() => critical.GetObjectData(null, new StreamingContext()));

        // BinaryFormatter calls the critical method via a safe route (SerializationFormatter permission is required, though)
        new BinaryFormatter().Serialize(new MemoryStream(), critical);
    }

}

Case 2: Regular class with security critical members

The test passes under the same conditions as the first one. However, the issue is completely different here: a partially trusted code may access a security critical member directly.

[Test]
[SecuritySafeCritical] // for Activator.CreateInstance
public void CriticalClass_PartialTrustAccess()
{
    var domain = CreateSandboxDomain(
        new ReflectionPermission(ReflectionPermissionFlag.MemberAccess), // Assert.IsFalse
        new EnvironmentPermission(PermissionState.Unrestricted)); // Assert.Throws (if fails)
    var handle = Activator.CreateInstance(domain, Assembly.GetExecutingAssembly().FullName, typeof(Sandbox).FullName);
    var sandbox = (Sandbox)handle.Unwrap();
    try
    {
        sandbox.TestCriticalClass();
        return;
    }
    catch (Exception e)
    {
        // without [InternalTypeReference] it may fail for the first time
        Console.WriteLine($"1st try failed: {e.Message}");
    }

    domain = CreateSandboxDomain(
        new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)); // Assert.IsFalse
    handle = Activator.CreateInstance(domain, Assembly.GetExecutingAssembly().FullName, typeof(Sandbox).FullName);
    sandbox = (Sandbox)handle.Unwrap();
    sandbox.TestCriticalClass();

    Assert.Inconclusive("Meh... succeeded only for the 2nd try");
}

private partial class Sandbox
{
    public void TestCriticalClass()
    {
        Assert.IsFalse(AppDomain.CurrentDomain.IsFullyTrusted);

        // A type containing critical methods can be created
        var critical = new CriticalClass();

        // Critical method can be called via a safe method
        critical.SafeEntryForCriticalCode();

        // Critical method cannot be called directly by a transparent method
        // !!! May fail for the first time if the test does not use any internal type of the library. !!!
        // !!! Meaning, a partially trusted code has more right than a fully trusted one and is       !!!
        // !!! able to call security critical method directly.                                        !!!
        Assert.Throws<MethodAccessException>(() => critical.CriticalCode());
    }
}

Case 3-4: Full trust versions of case 1-2

For the sake of completeness here are the same cases as the ones above executed in a fully trusted domain. If you remove [assembly: AllowPartiallyTrustedCallers] the tests fail because then you can access critical code directly (as the methods are not transparent by default anymore).

[Test]
public void CriticalClass_FullTrustAccess()
{
    Assert.IsTrue(AppDomain.CurrentDomain.IsFullyTrusted);

    // A type containing critical methods can be created
    var critical = new CriticalClass();

    // Critical method cannot be called directly by a transparent method
    Assert.Throws<MethodAccessException>(() => critical.CriticalCode());

    // Critical method can be called via a safe method
    critical.SafeEntryForCriticalCode();
}

[Test]
public void SerializableCriticalClass_FullTrustAccess()
{
    Assert.IsTrue(AppDomain.CurrentDomain.IsFullyTrusted);

    // ISerializable implementer can be created
    var critical = new SerializableCriticalClass();

    // Critical method cannot be called directly by a transparent method (see also AllowPartiallyTrustedCallersAttribute)
    Assert.Throws<MethodAccessException>(() => critical.CriticalCode());
    Assert.Throws<MethodAccessException>(() => critical.GetObjectData(null, default(StreamingContext)));

    // Critical method can be called via a safe method
    critical.SafeEntryForCriticalCode();

    // BinaryFormatter calls the critical method via a safe route
    new BinaryFormatter().Serialize(new MemoryStream(), critical);
}

Epilogue:

Of course, this will not solve your problem with .NET Fiddle. But now I would be very surprised if it wasn't a bug in the framework.

The biggest question to me now is the quoted part in the accepted answer. How did they come out with this nonsense? The ISafeSerializationData is clearly not a solution for anything: it is used exclusively by the base Exception class and if you subscribe the SerializeObjectState event (why isn't that an overridable method?), then the state will also be consumed by the Exception.GetObjectData in the end.

The AllowPartiallyTrustedCallers/SecurityCritical/SecuritySafeCritical triumvirate of attributes were designed for exactly the usage shown above. It seems total nonsense to me that a partially trusted code cannot even instantiate a type regardless of the attempt using its security critical members. But it is an even bigger nonsense (a security hole actually) that a partially trusted code may access a security critical method directly (see case 2) whereas this is forbidden for transparent methods even from a fully trusted domain.

So if your consumer project is a test or another well-known assembly, then the internal trick can be used perfectly. For .NET Fiddle and other real-life sandboxed environments the only solution is reverting back to SecurityRuleSet.Level1 until this is fixed by Microsoft.


Update: A Developer Community ticket has been created for the issue.

If you know Class, that belongs to assembly, you can use GetTypeInfo

var runtimeVersion = typeof(MyClass)
.GetTypeInfo()
.Assembly
.GetCustomAttribute<AssemblyFileVersionAttribute>();

String ver=RuntimeVersion.Version;  

The example is for .Net Core from https://developers.de/blogs/damir_dobric/archive/2017/06/27/how-to-deal-with-assembly-version-in-net-core.aspx