Skip to content

Support custom hosting a hybrid between app and component #35465

Closed
@rseanhall

Description

@rseanhall

In .NET Core 3.x, work was done to make custom hosting easier. Support was added for an "application" and a "component". I need support for a hybrid between these two.

The general use case is for an application where its features are spread across native and managed code, with the entry point being in native code. The details of my specific use case are here: #34946.

It's like an "application" but not "component":

  • This is the main application.
    -Missing dependencies are an error.
    -Loading into default ALC is expected.
    -Any isolation must be implemented by the app itself.
  • It may be deployed as self-contained or framework-dependent.

It's like a "component" but not an "application":

  • No static void Main(string[] args), no concept of args
  • Entry point is custom
  • Managed code needs to continue running after execution has passed back to native code

Unique aspects for this hybrid scenario:

  • The native code portion will initialize the .NET Core runtime very early in the lifetime of the process.
  • If deployed as self-contained, then it was published with a RID compatible with the native code portion of the application.

Reasons to be implemented in .NET Core instead of by the custom host using coreclr directly:

  • Logic to find the framework requested by the app is very complex and is subject to change with each new release of the framework.
  • Building the TPA list from deps.json files is very complex and is subject to change with each new release of the framework.
  • Various documentation discourages using coreclr directly, and some even make it seem like it could be deprecated in the future.

Proposal

Original proposal Add two new exported functions to `hostfxr` - `hostfxr_initialize_for_managed_host` and `hostfxr_create_delegate`. These two functions are similar to the existing `hostfxr_initialize_for_dotnet_command_line`/`hostfxr_run_app` and `hostfxr_initialize_for_runtime_config`/`hostfxr_get_runtime_delegate` function pairs in that the handle created from `hostfxr_initialize_for_managed_host` can only be used with `hostfxr_create_delegate`.
//
// Initializes the hosting components using an application
//
// Parameters:
//    managed_host_path
//      Path to the managed host assembly file
//    deps_json_path
//      Optional. Path to the .deps.json file
//    runtime_config_path
//      Optional. Path to the .runtimeconfig.json file
//    parameters
//      Optional. Additional parameters for initialization
//    host_context_handle
//      On success, this will be populated with an opaque value representing the initialized host context
//
// Return value:
//    Success          - Hosting components were successfully initialized
//    HostInvalidState - Hosting components are already initialized
//
// This function will find the .runtimeconfig.json and .deps.json corresponding to the given 
     application
// with which to resolve frameworks and dependencies and prepare everything needed to load the runtime.
//
// This function does not load the runtime.
//
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_initialize_for_managed_host_fn)(
    const char_t *managed_host_path,
    const char_t *deps_json_path,
    const char_t *runtime_config_path,
    const struct hostfxr_initialize_parameters *parameters,
    /*out*/ hostfxr_handle *host_context_handle);

//
// Create a native callable function pointer for a managed method from the currently loaded CoreCLR or from a newly created one.
//
// Parameters:
//     host_context_handle
//       Handle to the initialized host context
//     entry_point_assembly_name
//       Name of the assembly which holds the custom entry point
//     entry_point_type_name
//       Name of the type which holds the custom entry point
//     entry_point_method_name
//       Name of the method which is the custom entry point
//     delegate
//       Output parameter, the function stores a native callable function pointer to the delegate at the specified address
//
// Returns:
//     The error code result.
//
// The host_context_handle must have been initialized using hostfxr_initialize_for_managed_host.
// The assembly is loaded into the default AssemblyLoadContext.
//
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_create_delegate_fn)(
    const hostfxr_handle host_context_handle,
    const char_t *entry_point_assembly_name,
    const char_t *entry_point_type_name,
    const char_t *entry_point_method_name,
    /*out*/ void **delegate);

hostfxr_initialize_for_managed_host is essentially the same as hostfxr_initialize_for_dotnet_command_line but instead of argc/argv, it takes the application, deps.json, and runtimeconfig.json as explicit parameters.

hostfxr_create_delegate is simply a wrapper around the create delegate functionality of coreclr. hostfxr_get_runtime_delegate could not be reused since it always loads the target assembly into an isolated ALC (which is why it requires a handle from hostfxr_initialize_for_runtime_config - isolation is not supported in self-contained applications and it blocks on SCD).

Design document update and discussion: #36990

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions