66684


以下の構成のアプリケーションがあった場合のベストプラクティスがあれば教えてください。  
気になったのはバージョンを明示的に指定しているのに実行時に別のバージョンのアセンブリがロードされてしまうことです。

[code]

    App.sln
      - Console.csproj(.NET Core 2.1)
          プロジェクト参照: Lib1.csproj, Lib2.csproj
      - Lib1.csproj(.NET Standard 2.0)
          nuget: Newtonsoft.Json(11.0.0)
      - Lib2.csproj(.NET Standard 2.0)
          nuget: Newtonsoft.Json(10.0.0)
    
[/code]

**Console.csproj**

[code]

    class Program
    {
      static void Main(string[] args)
      {
        var target = new {
          num = 2,
          str = "aaa",
        };
    
        var oldOne = Lib2.Converter.Convert(target);
        var newOne = Lib1.Converter.Convert(target);
    
        Console.WriteLine(oldOne);
        Console.WriteLine(newOne);
        Console.ReadLine();
      }
    }
    
[/code]

**Lib1.csproj**

[code]

    namespace Lib1
    {
      public static class Converter
      {
        public static string Convert(object target)
        {
           return Newtonsoft.Json.JsonConvert.SerializeObject(target);
        }
      }
    }
    
[/code]

**Lib2.csproj**

[code]

    namespace Lib2
    {
      public static class Converter
      {
        public static string Convert(object target)
        {
           return Newtonsoft.Json.JsonConvert.SerializeObject(target);
        }
      }
    }
    
[/code]

上記のようなコードを作成し、バージョン間の違いって何かあるのかを確認しようと思ったのですが、実際にロードされているNewtonsoft.Jsonが同一のバージョンであることに気付きました。nugetで参照を追加する順番やプロジェクトの順番(ソリューションエクスプローラのツリー上の順番)、Newtonsoft.Jsonのアセンブリにアクセスする順番を変えて試してみたのですが、結果としては全て新しいバージョン(11.0.0)がロードされていました。

メタデータとして実際にどのバージョンが参照されているかを確かめるために、以下のコードを追加して実験をしてみました。

**Lib1.csproj**

[code]

    namespace Lib1
    {
      public class ExHolder
      {
        public Newtonsoft.Json.JsonException JsonException = new Newtonsoft.Json.JsonException();
      }
    }
    
[/code]

**Lib2.csproj**

[code]

    namespace Lib2
    {
      public class ExHolder
      {
        public Newtonsoft.Json.JsonException JsonException = new Newtonsoft.Json.JsonException();
      }
    }
    
[/code]

Main関数の先頭にブレイクポイントをはってイミディエイトウィンドウで確認した結果が以下です。

> ＞ new **_Lib1_**.ExHolder().JsonException.GetType()  
>  error CS0012: 型 'JsonException' は、参照されていないアセンブリに定義されています。アセンブリ
> 'Newtonsoft.Json, **_Version=11.0.0.0_** , Culture=neutral,
> PublicKeyToken=30ad4fe6b2a6aeed' に参照を追加する必要があります。
>
> ＞ new **_Lib2_**.ExHolder().JsonException.GetType()  
>  error CS0012: 型 'JsonException' は、参照されていないアセンブリに定義されています。アセンブリ
> 'Newtonsoft.Json, **_Version=10.0.0.0_** , Culture=neutral,
> PublicKeyToken=30ad4fe6b2a6aeed' に参照を追加する必要があります。

まだアセンブリがロードされていないので例外がスローされました。参照しているアセンブリの情報を確認するとLib1が11.0.0でLib2が10.0.0なので想定通りでした。

その後、Lib2の呼び出しまでステップ実行して再度イミディエイトウィンドウで確認した結果が以下です。

> ＞ new **_Lib_**.ExHolder().JsonException.GetType()  
>  {Newtonsoft.Json.JsonException}  
>  Assembly: {Newtonsoft.Json, **_Version=11.0.0.0_** , Culture=neutral,
> PublicKeyToken=30ad4fe6b2a6aeed}  
>  AssemblyQualifiedName: "Newtonsoft.Json.JsonException, Newtonsoft.Json,
> **_Version=11.0.0.0_** , Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed"  
>  \-- 以下省略 --
>
> ＞ new **_Lib2_**.ExHolder().JsonException.GetType()  
>  {Newtonsoft.Json.JsonException}  
>  Assembly: {Newtonsoft.Json, **_Version=11.0.0.0_** , Culture=neutral,
> PublicKeyToken=30ad4fe6b2a6aeed}  
>  AssemblyQualifiedName: "Newtonsoft.Json.JsonException, Newtonsoft.Json,
> **_Version=11.0.0.0_** , Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed"  
>  \-- 以下省略 --

ともに11.0.0が参照されています。

このようにロードされてしまうと、nuget参照しているパッケージが参照しているアセンブリのバージョンがコントロールできなくなってしまうので、テストされていない組み合わせのバージョンで実行されてしまう可能性がでてきます。これは仕様としてあきらめるしかないのか、解決するための手段が提供されているかなど、お教えいただけないでしょうか。

※上記の実行環境は以下の通りです

[code]

    > % dotnet --info
    .NET Core SDK (global.json を反映):
     Version:   3.1.200
     Commit:    c5123d973b
    
    ランタイム環境:
     OS Name:     Mac OS X
     OS Version:  10.15
     OS Platform: Darwin
     RID:         osx.10.15-x64
     Base Path:   /usr/local/share/dotnet/sdk/3.1.200/
    
    Host (useful for support):
      Version: 3.1.2
      Commit:  916b5cba26
    
    .NET Core SDKs installed:
      2.0.3 [/usr/local/share/dotnet/sdk]
      2.1.202 [/usr/local/share/dotnet/sdk]
      2.1.805 [/usr/local/share/dotnet/sdk]
      3.1.200 [/usr/local/share/dotnet/sdk]
    
    .NET Core runtimes installed:
      Microsoft.AspNetCore.All 2.1.17 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
      Microsoft.AspNetCore.App 2.1.17 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
      Microsoft.AspNetCore.App 3.1.2 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
      Microsoft.NETCore.App 2.0.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
      Microsoft.NETCore.App 2.0.9 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
      Microsoft.NETCore.App 2.1.16 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
      Microsoft.NETCore.App 2.1.17 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
      Microsoft.NETCore.App 3.1.2 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
    
    To install additional .NET Core runtimes or SDKs:
      https://aka.ms/dotnet-download
    
[/code]


CC BY-SA 4.0
2020-05-16T04:07:54.237
66660
2020-05-16T20:31:19.730
2020-05-16T04:15:02.940
40171
40171
question
c# .net .net-core nuget
参照先のアセンブリが違うバージョンのnugetパッケージを参照している場合のベストプラクティスについて


> テストされていない組み合わせのバージョンで実行されてしまう可能性がでてきます。

[パッケージのバージョン管理](https://docs.microsoft.com/ja-jp/nuget/concepts/package-
versioning#version-ranges) に 書かれているように バージョン番号の明示的に指定する事で  
そのバージョン以外のライブラリでは使わないように 宣言する事ができます。

Lib1.csproj

[code]

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Include="Newtonsoft.Json" Version="[11.0.1,12)" />
      </ItemGroup>
    </Project>
    
[/code]

Lib2.csproj

[code]

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Include="Newtonsoft.Json" Version="[10.0.1,11)" />
      </ItemGroup>
    </Project>
    
[/code]

Lib1 は Newtonsoft.Json version 11.0.1 <= x < 12.0.0  
Lib2 は Newtonsoft.Json version 10.0.1 <= x < 11.0.0

なので

Console.csproj が Lib1 と Lib2 を参照すると

[code]

    エラー NU1107  Newtonsoft.Json のバージョンの競合が検出されました。
    この問題を解決するには、Newtonsoft.Json 11.0.1 をプロジェクト Console に直接インストールするか、
    参照します。 
    
[/code]

というエラーが出ます。

なので **予期せず違うバージョンで動作させて動かなかった** という事を防ぐことはできます。  
また、 **このバージョンでは 動かないという事がわかっている** 場合に バージョン指定する事ができます。

また エラーメッセージにあるように `Console.csproj` で Newtonsoft.Json 11.0.1 や 12.0.1 を  
参照すると **エラーは警告に変わり** 、その指定されたバージョンで 動作してしまいます。  
でも、そのバージョンで 動かないのであれば、実行時にエラーとなると思います。

>
> このようにロードされてしまうと、nuget参照しているパッケージが参照しているアセンブリのバージョンがコントロールできなくなってしまうので、テストされていない組み合わせのバージョンで実行されてしまう可能性がでてきます。これは仕様としてあきらめるしかないのか、

ライブラリの作者として 利用できるバージョンの宣言をすることはできます。  
そのライブラリを使う人が 宣言を無視して 別のバージョンで使う事もできます。  
でも、それによって 一部の処理はちゃんと動かないかもしれません。  
それを どう解決するかは、いろいろなパターンがあるので何とも言えません。

> 解決するための手段が提供されているか

`.NET Framework` の時は 1つのプロセスの中に アプリケーションドメインがあって その中に  
違うバージョンのライブラリを読み込み 呼び出したり、動的に読み込んだ物を切り離したり  
できましたが、 `.NET Core` では アプリケーションドメインは１つだけしかないため  
それはできません。  
1つのプロセスの中に 違うバージョンの ライブラリを読み込む事はできないと思います。

解決策として

  * プロセスを分ける事はできないか？
  * 新しいバージョンで動作するように 古いライブラリを修正できないか？

等を検討してみてはいかがでしょうか？


CC BY-SA 4.0
2020-05-16T20:31:19.730
66684
2020-05-16T20:31:19.730
18851
66660
answer