pythonnet / pythonnet/clr-loader

Missing TargetFrameworkName from AppDomain.SetupInformation

オープン
#56 コメント 0 件 リアクション 2 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

主要言語
Python
スター
42
フォーク
32
平均マージ
14時間 1分
マージ済み PR(30日)
1

説明

When the .Net code is launched from pythonnet, the TargetFrameworkName property of the AppDomain.SetupInformation is not configured / provided.

Here is what AppDomain setup information returns from the normally executed .Net code:

AppDomain setup information:
	AppDomainManagerAssembly = NULL
	AppDomainManagerType = NULL
	ApplicationBase = D:\_WorkRoot\Clients\...\bin\Debug\
	ConfigurationFile = D:\_WorkRoot\Clients\...\bin\Debug\UPSTest.exe.Config
	TargetFrameworkName = .NETFramework,Version=v4.8
	DynamicBase = NULL
	DisallowPublisherPolicy = False
	DisallowBindingRedirects = False
	DisallowCodeDownload = False
	DisallowApplicationBaseProbing = False
	ApplicationName = UPSTest.exe
	PrivateBinPath = NULL
	PrivateBinPathProbe = NULL
	ShadowCopyDirectories = NULL
	ShadowCopyFiles = NULL
	CachePath = NULL
	LicenseFile = NULL
	LoaderOptimization = NotSpecified
	SandboxInterop = False

Here is how it is setup when called from PythonNet:

AppDomain setup information:
	AppDomainManagerAssembly = NULL
	AppDomainManagerType = NULL
	ApplicationBase = C:\Program Files\Python310\
	ConfigurationFile = C:\Program Files\Python310\python.exe.Config
	TargetFrameworkName = NULL
	DynamicBase = NULL
	DisallowPublisherPolicy = False
	DisallowBindingRedirects = False
	DisallowCodeDownload = False
	DisallowApplicationBaseProbing = False
	ApplicationName = python.exe
	PrivateBinPath = NULL
	PrivateBinPathProbe = NULL
	ShadowCopyDirectories = NULL
	ShadowCopyFiles = NULL
	CachePath = NULL
	LicenseFile = NULL
	LoaderOptimization = NotSpecified
	SandboxInterop = False

Why is it important? The below is the copy of the .Net 4.7.2 code that uses that moniker inside AppContext class (system\AppContext\AppContextDefaultValues.cs) (added in .Net 4.6.2).

    internal static partial class AppContextDefaultValues
    {
        public static void PopulateDefaultValues()
        {
            string platformIdentifier, profile;
            int version;

            ParseTargetFrameworkName(out platformIdentifier, out profile, out version);

            // Call into each library to populate their default switches
            PopulateDefaultValuesPartial(platformIdentifier, profile, version);
        }

        /// <summary>
        /// We have this separate method for getting the parsed elements out of the TargetFrameworkName so we can
        /// more easily support this on other platforms.
        /// </summary>
        private static void ParseTargetFrameworkName(out string identifier, out string profile, out int version)
        {
            string targetFrameworkMoniker = AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName;

            // If we don't have a TFM then we should default to the 4.0 behavior where all quirks are turned on.
            if (!TryParseFrameworkName(targetFrameworkMoniker, out identifier, out version, out profile))
            {
#if FEATURE_CORECLR
                if (CompatibilitySwitches.UseLatestBehaviorWhenTFMNotSpecified)
                {
                    // If we want to use the latest behavior it is enough to set the value of the switch to string.Empty.
                    // When the get to the caller of this method (PopulateDefaultValuesPartial) we are going to use the 
                    // identifier we just set to decide which switches to turn on. By having an empty string as the 
                    // identifier we are simply saying -- don't turn on any switches, and we are going to get the latest
                    // behavior for all the switches
                    identifier = string.Empty;
                }
                else
#endif
                {
                    identifier = ".NETFramework";
                    version = 40000;
                    profile = string.Empty;
                }
            }
        }

The AppContext switches control behavior of number of .Net components (between versions). For example, one of such switches controls behavior of asymmetric encryption. It may mean that any code that calls .Net API impacted by any of those switches will behave differently inside Python than what is expected by the .Net code author.

It creates uncertainties for the .Net code that calls such .Net Framework API. For example, we are trying to detect which level of compatibility we are currently under to call our encryption code accordingly. That determination includes TargetFramework of the entry assembly or supportedRuntime element in the config file. And our code might not have a proper recovery strategy to go all the way back to .Net 4.0 compatibility (yet having installed all the latest .Net and compiled using latest .Net Framework).

Some switches are explictely controllable via configuration file but missing framework in the AppDomain setup just opens the mine field of discrepancies.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず system\AppContext\AppContextDefaultValues.cs を読み、pythonnet 経由でコードが起動されたときに AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName がどのように設定されるかを追跡してください。その経路を、通常実行された .NET アプリケーションの場合と比較してください。Python から起動された AppDomain が NULL ではなく該当するターゲットフレームワークを報告すれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python
領域
tooling
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
35/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。