Hosten von .NET Core

Wie alle verwalteten Codes werden .NET Core-Anwendungen von einem Host ausgeführt. Der Host ist verantwortlich für das Starten der Laufzeit (einschließlich Komponenten wie die JIT und Garbage Collector), das Erstellen der AppDomains und das Aufrufen von verwalteten Einstiegspunkten.

Das Hosten der Laufzeit von .NET Core ist ein erweitertes Szenario, und in den meisten Fällen brauchen sich .NET Core-Entwickler nicht darum kümmern, da die Buildprozesse von .NET Core einen Standardhost bereitstellen, der die .NET Core-Anwendungen ausführt. Unter speziellen Umständen kann es jedoch hilfreich sein, die .NET Core-Laufzeit explizit zu hosten, entweder als Mittel zum Aufrufen von verwalteten Codes in einem nativen Prozess oder um mehr Kontrolle über die Funktionsweise der Laufzeit zu erhalten.

Dieser Artikel bietet einen Überblick über die erforderlichen Schritte zum Starten der .NET Core-Laufzeit aus nativem Code, Erstellen einer ersten Anwendungsdomäne (<xref:System.AppDomain>), und Ausführen von darin enthaltenem, verwalteten Code.

Erforderliche Komponenten

Da Hosts native Anwendungen sind, wird in diesem Lernprogramm das Erstellen einer C++-Anwendung zum Hosten auf .NET Core behandelt. Sie benötigen eine C++-Entwicklungsumgebung (z.B. von Visual Studio).

Sie sollten außerdem über eine einfache .NET Core-Anwendung zum Testen des Hosts verfügen, daher sollten Sie die .NET Core SDK installieren und eine kleine .NET Core-Testanwendung erstellen (z.B. die Anwendung „Hello World“). Die „Hello World“-Anwendung, die von der neuen Projektvorlage der .NET Core-Konsole erstellt wird, ist ausreichend.

In diesem Tutorial und dem zugehörigen Beispiel wird ein Windows-Host erstellt, jedoch finden Sie in den Hinweisen am Ende dieses Artikels Informationen zum Hosten unter Unix.

Erstellen des Hosts

Ein Beispielhost zur Veranschaulichung der Schritte in diesem Artikel steht in unserem Repository „dotnet/docs“ auf GitHub. Kommentare in der Beispieldatei host.cpp ordnen die nummerierten Schritte in diesem Tutorial ihrer Position im Beispiel deutlich zu. Anweisungen zum Herunterladen finden Sie unter Beispiele und Lernprogramme.

Bedenken Sie, dass der Beispielhost zu Lernzwecken gedacht und somit bei der Fehlerüberprüfung nachsichtig ist und bessere Lesbarkeit über Effizienz stellt. Weitere echte Hostbeispiele finden Sie in der Repository dotnet/coreclr. Vor allem der CoreRun-Host ist ein guter allgemeiner Host, den Sie nach den einfacheren Beispielen studieren können.

Ein Hinweis zur mscoree.h

Die primäre .NET Core-Hostingschnittstelle (ICLRRuntimeHost2) ist in MSCOREE. IDL definiert. MIDL erzeugt eine Headerversion dieser Datei (mscoree.h), auf die Ihr Host verweisen muss, wenn die .NET Core-Laufzeit erstellt wird. Wenn Sie die .NET Core-Laufzeit nicht erstellen möchten, steht mscoree.h auch als vorgefertigter Header im Repository Dotnet/Coreclr zur Verfügung. Hinweise zum Erstellen der .NET Core-Laufzeit finden Sie in der GitHub-Repository.

Schritt 1: Ermitteln des verwalteten Einstiegspunkts

Nach Verweisen auf die erforderlichen Header (z.B. mscoree.h und stdio.h), muss ein .NET Core-Host als eine der ersten Aktionen den verwalteten Einstiegspunkt suchen, den er verwenden wird. In unserem Beispielhost wird nur das erste Befehlszeilenargument als Pfad zu einer verwalteten Binärdatei verwendet, deren main-Methode ausgeführt wird.

// The managed application to run should be the first command-line parameter.
// Subsequent command line parameters will be passed to the managed app later in this host.
wchar_t targetApp[MAX_PATH];
GetFullPathNameW(argv[1], MAX_PATH, targetApp, NULL);

Schritt 2: Suchen und Laden von CoreCLR.dll

Die .NET Core Runtime-APIs befinden sich in CoreCLR.dll (unter Windows). Um unsere Hostingschnittstelle (ICLRRuntimeHost2) abzurufen, ist es erforderlich, CoreCLR.dll zu suchen und zu laden. Es obliegt dem Host, eine Konvention für das Auffinden von CoreCLR.dll zu definieren. Einige Hosts erwarten, dass die Datei in einem bekannten, computerweiten Speicherort (z.B. %programfiles%\dotnet\shared\Microsoft.NETCore.App\1.1.0) vorhanden ist. Andere erwarten, dass CoreCLR.dll von einem anderen Speicherort neben dem Host selbst oder der zu hostenden Anwendung geladen wird. Noch andere konsultieren möglicherweise eine Umgebungsvariable, um die Bibliothek zu finden.

Unter Linux oder Mac ist die Core Runtime Library jeweils libcoreclr.so oder libcoreclr.dylib.

Unser Beispielhost prüft einige gängige Speicherorte für CoreCLR.dll. Wenn er gefunden wird, muss er geladen werden, über LoadLibrary (oder dlopen auf Linux/Mac).

HMODULE ret = LoadLibraryExW(coreDllPath, NULL, 0);

Schritt 3: Abrufen einer ICLRRuntimeHost2-Instanz

Die ICLRRuntimeHost2-Hostingschnittstelle wird durch den Aufruf von GetProcAddress (oder dlsym auf Linux/Mac) auf GetCLRRuntimeHost abgerufen, und dann wird diese Funktion aufgerufen.

ICLRRuntimeHost2* runtimeHost;

FnGetCLRRuntimeHost pfnGetCLRRuntimeHost =
	(FnGetCLRRuntimeHost)::GetProcAddress(coreCLRModule, "GetCLRRuntimeHost");

if (!pfnGetCLRRuntimeHost)
{
	printf("ERROR - GetCLRRuntimeHost not found");
	return -1;
}

// Get the hosting interface
HRESULT hr = pfnGetCLRRuntimeHost(IID_ICLRRuntimeHost2, (IUnknown**)&runtimeHost);

Schritt 4: Festlegen von Startflags und Starten der Laufzeit

Mit ICLRRuntimeHost2 können wir jetzt die laufzeitweiten Startflags angeben und die Laufzeit starten. Startflags bestimmen, welchen Garbage Collector (GC) Sie verwenden (gleichzeitig oder Server), ob wir eine einzelne AppDomain oder mehrere verwenden, und welche Ladeoptimierungsrichtlinie (für domänenneutrales Laden von Assemblys) wir verwenden.

hr = runtimeHost->SetStartupFlags(
	// These startup flags control runtime-wide behaviors.
	// A complete list of STARTUP_FLAGS can be found in mscoree.h,
	// but some of the more common ones are listed below.
	static_cast<STARTUP_FLAGS>(
		// STARTUP_FLAGS::STARTUP_SERVER_GC |								// Use server GC
		// STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN |		// Maximize domain-neutral loading
		// STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN_HOST |	// Domain-neutral loading for strongly-named assemblies
		STARTUP_FLAGS::STARTUP_CONCURRENT_GC |						// Use concurrent GC
		STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN |					// All code executes in the default AppDomain 
																	// (required to use the runtimeHost->ExecuteAssembly helper function)
		STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN	// Prevents domain-neutral loading
	)
);

Die Laufzeit wird durch einen Aufruf der Start-Funktion gestartet.

hr = runtimeHost->Start();

Schritt 5: Vorbereiten der Einstellungen der AppDomain

Nachdem die Laufzeit gestartet wurde, möchten wir eine AppDomain einrichten. Es gibt jedoch eine Reihe von Optionen, die beim Erstellen einer .NET AppDomain angegeben werden müssen, daher ist es erforderlich, diese zuerst vorzubereiten.

AppDomain-Flags geben das Verhalten der AppDomain im Zusammenhang mit der Sicherheit und Interoperabilität an. Ältere Silverlight-Hosts verwendeten diese Einstellungen für Sandbox-Benutzercodes, aber die meisten modernen .NET Core-Hosts führen den Benutzercode als voll vertrauenswürdig und interoperabel aus.

int appDomainFlags =
	// APPDOMAIN_FORCE_TRIVIAL_WAIT_OPERATIONS |		// Do not pump messages during wait
	// APPDOMAIN_SECURITY_SANDBOXED |					// Causes assemblies not from the TPA list to be loaded as partially trusted
	APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS |			// Enable platform-specific assemblies to run
	APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP |	// Allow PInvoking from non-TPA assemblies
	APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT;			// Entirely disables transparency checks 

Nach der Entscheidung, welche der AppDomain-Flags verwendet werden, müssen die AppDomain-Eigenschaften definiert werden. Die Eigenschaften sind Schlüssel-/Wertpaare von Zeichenfolgen. Viele der Eigenschaften beziehen sich auf die Art, mit der die AppDomain Assemblys laden wird.

Allgemeine AppDomain-Eigenschaften beinhalten:

  • TRUSTED_PLATFORM_ASSEMBLIES Dies ist eine Liste von Assemblypfaden (getrennt durch „;“ unter Windows und „:“ unter Unix), die AppDomains laden sollten und denen sie komplett vertrauen (auch in teilweise vertrauenswürdigen Domänen). Diese Liste soll „Framework“-Assemblys und andere vertrauenswürdige Module, ähnlich dem GAC in .NET Framework-Szenarios, enthalten. Einige Hosts platzieren eine Bibliothek neben coreclr.dll in dieser Liste, andere haben andere hartcodierte Manifeste, die vertrauenswürdige Assemblys für ihre Zwecke listen.
  • APP_PATHS Dies ist eine Liste der Pfade, in denen nach einer Assembly gesucht werden soll, wenn sie in der Liste der vertrauenswürdigen Plattformassemblys (TPA) nicht gefunden werden kann. Diese Pfade sollen die Speicherorte sein, in denen die Assemblys der Benutzer gefunden werden können. In einer Sandbox-AppDomain erhalten Assemblys von diesen Pfaden nur teilweise Vertrauenswürdigkeit. Allgemeine APP_PATH-Pfade enthalten den Pfad, von dem die Zielanwendung geladen wurde oder andere Speicherorte, in denen Benutzerressourcen vorhanden sind.
  • APP_NI_PATHS Diese Liste ist APP_PATHS sehr ähnlich, außer dass es Pfade sein sollten, in denen nach nativen Images gesucht werden sollen.
  • NATIVE_DLL_SEARCH_DIRECTORIES Diese Eigenschaft ist eine Liste der Pfade, die das Ladeprogramm durchsuchen sollte, wenn es nach nativen DLLs sucht, die über p/invoke aufgerufen werden.
  • PLATFORM_RESOURCE_ROOTS Diese Liste enthält die Pfade, in denen nach Assemblys der Ressourcensatelliten (in kulturspezifischen Unterverzeichnissen) gesucht wird.
  • AppDomainCompatSwitch Diese Zeichenfolge gibt an, welche Kompatibilitätsquirks für Assemblys ohne eine explizite Zielframeworkmoniker (ein Attribut auf Assemblyebene, das angibt, welches Framework eine Assembly ausführen soll) verwendet werden sollen. Dies sollte in der Regel auf "UseLatestBehaviorWhenTFMNotSpecified" festgelegt werden, aber einige Hosts möchten stattdessen ältere Silverlight- oder Windows Phone-Kompatibilitätsquirks abrufen.

In unserem einfache Beispielhost sind diese Eigenschaften wie folgt eingerichtet:

// TRUSTED_PLATFORM_ASSEMBLIES
// "Trusted Platform Assemblies" are prioritized by the loader and always loaded with full trust.
// A common pattern is to include any assemblies next to CoreCLR.dll as platform assemblies.
// More sophisticated hosts may also include their own Framework extensions (such as AppDomain managers)
// in this list.
int tpaSize = 100 * MAX_PATH; // Starting size for our TPA (Trusted Platform Assemblies) list
wchar_t* trustedPlatformAssemblies = new wchar_t[tpaSize];
trustedPlatformAssemblies[0] = L'\0';

// Extensions to probe for when finding TPA list files
wchar_t *tpaExtensions[] = {
	L"*.dll",
	L"*.exe",
	L"*.winmd"
};

// Probe next to CoreCLR.dll for any files matching the extensions from tpaExtensions and
// add them to the TPA list. In a real host, this would likely be extracted into a separate function
// and perhaps also run on other directories of interest.
for (int i = 0; i < _countof(tpaExtensions); i++)
{
	// Construct the file name search pattern
	wchar_t searchPath[MAX_PATH];
	wcscpy_s(searchPath, MAX_PATH, coreRoot);
	wcscat_s(searchPath, MAX_PATH, L"\\");
	wcscat_s(searchPath, MAX_PATH, tpaExtensions[i]);

	// Find files matching the search pattern
	WIN32_FIND_DATAW findData;
	HANDLE fileHandle = FindFirstFileW(searchPath, &findData);

	if (fileHandle != INVALID_HANDLE_VALUE)
	{
		do
		{
			// Construct the full path of the trusted assembly
			wchar_t pathToAdd[MAX_PATH];
			wcscpy_s(pathToAdd, MAX_PATH, coreRoot);
			wcscat_s(pathToAdd, MAX_PATH, L"\\");
			wcscat_s(pathToAdd, MAX_PATH, findData.cFileName);

			// Check to see if TPA list needs expanded
			if (wcslen(pathToAdd) + (3) + wcslen(trustedPlatformAssemblies) >= tpaSize)
			{
				// Expand, if needed
				tpaSize *= 2;
				wchar_t* newTPAList = new wchar_t[tpaSize];
				wcscpy_s(newTPAList, tpaSize, trustedPlatformAssemblies);
				trustedPlatformAssemblies = newTPAList;
			}

			// Add the assembly to the list and delimited with a semi-colon
			wcscat_s(trustedPlatformAssemblies, tpaSize, pathToAdd);
			wcscat_s(trustedPlatformAssemblies, tpaSize, L";");

			// Note that the CLR does not guarantee which assembly will be loaded if an assembly
			// is in the TPA list multiple times (perhaps from different paths or perhaps with different NI/NI.dll
			// extensions. Therefore, a real host should probably add items to the list in priority order and only
			// add a file if it's not already present on the list.
			//
			// For this simple sample, though, and because we're only loading TPA assemblies from a single path,
			// we can ignore that complication.
		}
		while (FindNextFileW(fileHandle, &findData));
		FindClose(fileHandle);
	}
}


// APP_PATHS
// App paths are directories to probe in for assemblies which are not one of the well-known Framework assemblies
// included in the TPA list.
//
// For this simple sample, we just include the directory the target application is in.
// More complex hosts may want to also check the current working directory or other
// locations known to contain application assets.
wchar_t appPaths[MAX_PATH * 50];

// Just use the targetApp provided by the user and remove the file name
wcscpy_s(appPaths, targetAppPath);


// APP_NI_PATHS
// App (NI) paths are the paths that will be probed for native images not found on the TPA list. 
// It will typically be similar to the app paths.
// For this sample, we probe next to the app and in a hypothetical directory of the same name with 'NI' suffixed to the end.
wchar_t appNiPaths[MAX_PATH * 50];
wcscpy_s(appNiPaths, targetAppPath);
wcscat_s(appNiPaths, MAX_PATH * 50, L";");
wcscat_s(appNiPaths, MAX_PATH * 50, targetAppPath);
wcscat_s(appNiPaths, MAX_PATH * 50, L"NI");


// NATIVE_DLL_SEARCH_DIRECTORIES
// Native dll search directories are paths that the runtime will probe for native DLLs called via PInvoke
wchar_t nativeDllSearchDirectories[MAX_PATH * 50];
wcscpy_s(nativeDllSearchDirectories, appPaths);
wcscat_s(nativeDllSearchDirectories, MAX_PATH * 50, L";");
wcscat_s(nativeDllSearchDirectories, MAX_PATH * 50, coreRoot);


// PLATFORM_RESOURCE_ROOTS
// Platform resource roots are paths to probe in for resource assemblies (in culture-specific sub-directories)
wchar_t platformResourceRoots[MAX_PATH * 50];
wcscpy_s(platformResourceRoots, appPaths);


// AppDomainCompatSwitch
// Specifies compatibility behavior for the app domain. This indicates which compatibility
// quirks to apply if an assembly doesn't have an explicit Target Framework Moniker. If a TFM is
// present on an assembly, the runtime will always attempt to use quirks appropriate to the version
// of the TFM.
// 
// Typically the latest behavior is desired, but some hosts may want to default to older Silverlight
// or Windows Phone behaviors for compatibility reasons.
wchar_t* appDomainCompatSwitch = L"UseLatestBehaviorWhenTFMNotSpecified";

Schritt 6: Erstellen der AppDomain

Sobald alle Flags und Eigenschaften der AppDomain vorbereitet sind, kann ICLRRuntimeHost2::CreateAppDomainWithManager zum Einrichten der AppDomain verwendet werden. Diese Funktion hat optional einen vollqualifizierten Assemblynamen und Typnamen, die als AppDomain-Manager der Domäne verwendet werden. Ein AppDomain-Manager kann einem Host ermöglichen, einige Aspekte des AppDomain-Verhaltens steuern und möglicherweise Einstiegspunkte für den Start von verwaltetem Code bereitzustellen, wenn der Host den Benutzercode nicht direkt aufrufen möchte.

DWORD domainId;

// Setup key/value pairs for AppDomain  properties
const wchar_t* propertyKeys[] = {
	L"TRUSTED_PLATFORM_ASSEMBLIES",
	L"APP_PATHS",
	L"APP_NI_PATHS",
	L"NATIVE_DLL_SEARCH_DIRECTORIES",
	L"PLATFORM_RESOURCE_ROOTS",
	L"AppDomainCompatSwitch"
};

// Property values which were constructed in step 5
const wchar_t* propertyValues[] = {
	trustedPlatformAssemblies,
	appPaths,
	appNiPaths,
	nativeDllSearchDirectories,
	platformResourceRoots,
	appDomainCompatSwitch
};

// Create the AppDomain
hr = runtimeHost->CreateAppDomainWithManager(
	L"Sample Host AppDomain",		// Friendly AD name
	appDomainFlags,
	NULL,							// Optional AppDomain manager assembly name
	NULL,							// Optional AppDomain manager type (including namespace)
	sizeof(propertyKeys)/sizeof(wchar_t*),
	propertyKeys,
	propertyValues,
	&domainId);

Schritt 7: Ausführen von verwaltetem Code!

Mit einer laufenden AppDomain kann der Host jetzt verwalteten Code ausführen. Die einfachste Möglichkeit hierzu ist die Verwendung von ICLRRuntimeHost2::ExecuteAssembly, um die Einstiegspunktmethode für eine verwaltete Assembly aufzurufen. Beachten Sie, dass diese Funktion nur in Szenarios mit einzelnen Domänen funktioniert.

DWORD exitCode = -1;
hr = runtimeHost->ExecuteAssembly(domainId, targetApp, argc - 1, (LPCWSTR*)(argc > 1 ? &argv[1] : NULL), &exitCode);

Wenn ExecuteAssembly nicht den Anforderungen Ihres Hosts entspricht, gibt es eine andere Option, bei der Sie CreateDelegate verwenden, um einen Funktionszeiger zu einer statisch verwalteten Methode zu erstellen. Dafür muss der Host die Signatur der Methode kennen, die er aufruft (um den Funktionszeigertyp zu erstellen), aber es gibt dem Host die Flexibilität, einen anderen Code als den Assemblyeingangspunkt aufzurufen.

void *pfnDelegate = NULL;
hr = runtimeHost->CreateDelegate(
  domainId,
  L"HW, Version=1.0.0.0, Culture=neutral",  // Target managed assembly
  L"ConsoleApplication.Program",            // Target managed type
  L"Main",                                  // Target entry point (static method)
  (INT_PTR*)&pfnDelegate);

((MainMethodFp*)pfnDelegate)(NULL);

Step 8: Bereinigen

Schließlich sollte der Host die Umgebung hinter sich bereinigen, indem er AppDomains entlädt, die Laufzeit beendet und den ICLRRuntimeHost2-Verweis freigibt.

runtimeHost->UnloadAppDomain(domainId, true /* Wait until unload complete */);
runtimeHost->Stop();
runtimeHost->Release();

Zum Hosten von .NET Core unter Unix

.NET Core ist ein plattformübergreifendes Produkt, das auf Windows, Linux und Macintosh-Betriebssystemen ausgeführt wird. Als native Anwendungen werden Hosts für verschiedene Plattformen jedoch einige Unterschiede aufweisen. Der oben beschriebene Vorgang zur Verwendung von ICLRRuntimeHost2, womit die Laufzeit gestartet, eine AppDomain erstellt und verwalteter Code ausgeführt wird, sollte auf allen beliebigen unterstützten Betriebssystemen funktionieren. Allerdings kann es umständlich sein, mit den Schnittstellen auf Unix-Plattformen zu arbeiten, die in mscoree.h definiert sind, da bei Mscoree von vielen Win32-Annahmen ausgegangen wird.

Um das Hosten auf Unix-Plattformen einfacher zu gestalten, stehen weitere plattformneutrale Hosting-API-Wrapper in coreclrhost.h zur Verfügung.

Ein Beispiel zur Verwendung von coreclrhost.h (statt direkt mscoree.h) sehen Sie in UnixCoreRun-Host. Die Schritte zur Verwendung der APIs aus coreclrhost.h als Laufzeithost ähneln den Schritten bei der Verwendung von mscoree.h:

  1. Identifizieren Sie den auszuführenden verwalteten Code (z.B. aus den Befehlszeilenparametern).
  2. Laden der CoreCLR-Bibliothek.
    1. dlopen("./libcoreclr.so", RTLD_NOW | RTLD_LOCAL);
  3. Rufen Sie Funktionszeiger für CoreCLRs Funktionen coreclr_initialize, coreclr_create_delegate, coreclr_execute_assembly und coreclr_shutdown mithilfe von dlsym auf.
    1. coreclr_initialize_ptr coreclr_initialize = (coreclr_initialize_ptr)dlsym(coreclrLib, "coreclr_initialize");
  4. Einrichten von AppDomain-Eigenschaften (z.B. die TPA-Liste). Dies ist identisch mit Schritt 5 aus dem mscoree-Workflow oben.
  5. Verwenden Sie coreclr_initialize, um die Laufzeit zu starten und eine AppDomain zu erstellen. Dadurch wird auch ein hostHandle-Zeiger erstellt, der in Zukunft für das Hosten von Aufrufen verwendet wird.
    1. Beachten Sie, dass diese Funktion die beiden Schritte 4 und 6 aus dem vorherigen Workflow ausführt.
  6. Verwenden Sie entweder coreclr_execute_assembly oder coreclr_create_delegate, um verwalteten Code auszuführen. Diese Funktionen sind analog zu den ExecuteAssembly- und CreateDelegate-Funktionen von Mscoree aus Schritt 7 des vorherigen Workflows.
  7. Verwenden Sie coreclr_shutdown, um die AppDomain zu entladen und die Laufzeit herunterzufahren.

Schlussfolgerung

Nachdem Ihr Host erstellt wurde, kann er getestet werden, indem er von der Befehlszeile aus ausgeführt wird und Argumente (z.B. die auszuführende verwaltete Anwendung) übergeben werden, die der Host erwartet. Beim Angeben der .NET Core-Anwendung, die den Host ausführt, müssen Sie die DLL-Datei verwenden, die von dotnet build erzeugt wurde. Ausführbare Dateien, die für eigenständige Anwendungen von dotnet publish erstellt wurden, sind tatsächlich die Standardeinstellung des .NET Core-Host (sodass die Anwendung direkt über die Befehlszeile in Hauptszenarios gestartet werden kann); der Benutzercode wird in einer DLL mit dem gleichen Namen kompiliert.

Wenn anfangs Funktionsstörungen auftreten, überprüfen Sie, dass coreclr.dll in dem Speicherort zur Verfügung steht, den der Host erwartet, dass sich alle erforderlichen Framework-Bibliotheken in der TPA-Liste befinden, und dass die CoreCLR-Bitanzahl (32 oder 64 Bit) der Erstellungsart des Host entspricht.

Das Hosten der Laufzeit von .NET Core ist ein erweitertes Szenario, das für viele Entwickler nicht erforderlich ist, aber für diejenigen, die verwalteten Code von einem nativen Prozess starten müssen, oder die mehr Kontrolle über das Verhalten der .NET Core-Laufzeit benötigen, kann es sehr nützlich sein. Da .NET Core Seite-an-Seite mit sich selbst ausgeführt werden kann, ist es sogar möglich, Hosts zu erstellen, die mehrere Versionen der Laufzeit von .NET Core initialisieren und starten und im selben Prozess Anwendungen auf allen ausführen.