Reputation: 8396
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?
Upvotes: 0
Views: 1113
Reputation: 247
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");
Upvotes: 1
Reputation: 969
.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.
Upvotes: 0
Reputation: 23
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")
Upvotes: 0