简体   繁体   中英

Assembly.LoadFrom works differently in .NET Core and .NET Framework

I have two .csproj projects, with the exact same source code:

using Newtonsoft.Json.Linq;
using System;
using System.Reflection;
class Program
{
    static void Main(string[] args)
    {
        Assembly jsonAssembly = Assembly.LoadFrom(@"C:\path\to\Newtonsoft.Json.dll");
        Type reflectionType = jsonAssembly.GetType("Newtonsoft.Json.Linq.JObject");

        Console.Write("Types match: " + (reflectionType == typeof(JObject)));
        Console.Write("Typenames match: " + (reflectionType.FullName == typeof(JObject).FullName));

        JObject cast = (JObject)Activator.CreateInstance(reflectionType);
        Console.Write("Success!");
    }
}

Both .csproj files have an identical reference to Newtonsoft.Json:

<Reference Include="Newtonsoft.Json">
  <HintPath>C:\path\to\Newtonsoft.Json.dll</HintPath>
</Reference>

The only difference between the two projects is that I created the first one using .NET Core 2.0, and the second one using .NET Framework 4.6.1.

Framework:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{A6D2C332-B60D-41F1-9983-DE10065973A1}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <RootNamespace>ConsoleApp1</RootNamespace>
    <AssemblyName>ConsoleApp1</AssemblyName>
    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Newtonsoft.Json">
      <HintPath>C:\path\to\Newtonsoft.Json.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <ItemGroup>
    <None Include="App.config" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Core:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="Newtonsoft.Json">
      <HintPath>C:\path\to\Newtonsoft.Json.dll</HintPath>
    </Reference>
  </ItemGroup>

</Project>

When I run the above code using .NET Core, I get the following response:

Types match: True
Typenames match: True
Success!

When I run the above code using .NET Framework, I get the following response:

Types match: False
Typenames match: True

Unhandled Exception: System.InvalidCastException: [A]Newtonsoft.Json.Linq.JObject cannot be cast to [B]Newtonsoft.Json.Linq.JObject

Why do .NET Framework and .NET Core work differently when loading assemblies via reflection?

The problem maybe is, that in .NET Framework you use 2 different assemblies (2 different files on disk). Try to run the .NET Framework project in debug mode and see where these types are coming from or add these lines.

Console.Write("Reflection type module: " + (reflectionType.Module.FullyQualifiedName));
Console.Write("Static type module: " + (typeof(JObject).Module.FullyQualifiedName));

Inspired by Walter Branson's answer, I did some research and found how some of the Load methods behave.

    /* Loads closest assembly given by FullName loaded by default, in this case it is from the same location as executable */
    Assembly jsonAssembly1 = Assembly.Load(@"Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed");

    /* Loads assembly exaclty from the file specified by path */
    Assembly jsonAssembly2 = Assembly.LoadFile($@"{pathToAssembly}\Newtonsoft.Json.dll");

    /* In NET.Framework loads same assembly as LoadFrom, but in .NET Core loads same assembly as Load */
    Assembly jsonAssembly3 = Assembly.LoadFrom($@"{pathToAssembly}\Newtonsoft.Json.dll");

I believe this is occurring because the reference compare fails for .NET. When you look at the objects there is a different handle in .NET. When you look at the objects in core they both have same handle.

I think this occurs because you are loading the assembly from file. Try loading the assembly by its fully qualified name.

Assembly jsonAssembly = Assebmly.Load("NewtonSoft.Json,Version=12.0.0.0,Culture=neutral,PublicKeyToken=30adfe6b2a6aeed")

.NET Framework one copies the .dll that you are referencing to its executable directory. So the loaded .dlls are actually different.

Try to change the path from "C:\\path\\to\\Newtonsoft.Json.dll" in .NET Framework project to "Newtonsoft.Json.dll" , the result will be the same as in .NET Core one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM