Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow modification of entry assembly and probing after startup hooks are run #99883

Closed
6 tasks
steveisok opened this issue Mar 18, 2024 · 12 comments
Closed
6 tasks
Assignees
Labels
area-Host User Story A single user-facing feature. Can be grouped under an epic.
Milestone

Comments

@steveisok
Copy link
Member

steveisok commented Mar 18, 2024

In certain custom hosting scenarios, it is desirable to prime the runtime by running a dummy application with a startup hook and then give the host the ability to change the application being run by altering its entry assembly and probing paths.

The way the custom host can achieve this is by:

Rules of note

  • We should start with only allowing System.Private.CoreLib to be loaded because once it's loaded, we cannot replace it
  • The exception to the rule is the entry assembly.
  • If the thread apartment state changes, the main thread needs updated. See Streamline Windows Forms application configuration and bootstrap designs#223 (comment)
  • It is the responsibility of the custom host to check if the new runtime config is compatible via hostfxr_initialize_for_runtime_config
    • Success_HostAlreadyInitialized: compatible
    • Success_DifferentRuntimeProperties: technically compatible, but may impact runtime behavior. Not advised to use
    • CoreHostIncompatibleConfig: incompatible

Considerations

  • For inspiration of the HOST_RUNTIME_CONTRACT structure, mono has an equivalent-ish implementation.
@steveisok steveisok added this to the 9.0.0 milestone Mar 18, 2024
Copy link
Contributor

Tagging subscribers to this area: @vitek-karas, @agocke, @VSadov
See info in area-owners.md if you want to be subscribed.

@steveisok steveisok added the User Story A single user-facing feature. Can be grouped under an epic. label Mar 18, 2024
@jkotas
Copy link
Member

jkotas commented Mar 18, 2024

Add env variable or runtime config setting to identify this mode

I do not think this bundle of features should be a special runtime mode, we should break it down into general purpose individual features that can be used independently. Also, we should prefer exposing new features via managed APIs as much as possible.

Enable replacing entry assembly and lookup paths after startup hooks are run.

We should add a managed API to allow setting the entry assembly. It comes up every once in a while.

.NET Framework allowed overriding the entry assembly via AppDomainManager.EntryAssembly. And we have undocumented test hook to reset the entry assembly. (Yes, people can shoot themselves into foot by using this API - but it is their problem.)

We should start with only allowing System.Private.CoreLib to be loaded because once it's loaded, we cannot replace it

It should be fine to load all assemblies that are tightly coupled with CoreLib too (e.g. System.Runtime.dll).

thread apartment state needs to match and if it does not, then it's an error.

It does not need to be an error. You can reset the apartment state of the main thread: dotnet/designs#223 (comment)

@steveisok
Copy link
Member Author

steveisok commented Mar 18, 2024

I do not think this bundle of features should be a special runtime mode, we should break it down into general purpose individual features that can be used independently. Also, we should prefer exposing new features via managed APIs as much as possible.

OK, then maybe we check if the entry assembly has changed and if so, have the runtime query the contract again after the startup hooks are run. That's what I meant by having some env variable to opt into the re-query.

@jkotas
Copy link
Member

jkotas commented Mar 18, 2024

if so, have the runtime query the contract again after the startup hooks are run

I do not think that this would work well. The list of app dependencies needs to be updated before the new entry assembly is loaded. Otherwise, there can be situations where the assembly fails to load due to missing dependencies.

@steveisok
Copy link
Member Author

I do not think that this would work well. The list of app dependencies needs to be updated before the new entry assembly is loaded. Otherwise, there can be situations where the assembly fails to load due to missing dependencies.

Unless I'm missing something, I think it's a compound operation. You have to change not only the entry assembly, but specify new deps and other probing paths before this has a chance to work.

@jkotas
Copy link
Member

jkotas commented Mar 18, 2024

My understanding that the scenario we are going after is:

  1. Start the runtime with only a small set of dependencies. We may need something new for this, I am not sure.
  2. Execute startup hook. Startup hook receives the path to the actual app to execute via some RPC channel.
  3. Resolve the dependencies of the actuall app to execute. It should be possible via System.Runtime.Loader.AssemblyDependencyResolver today.
  4. Append additional assemblies to the list of app dependencies. Appending to the list of app dependencies is possible today by handling AssemblyLoadContext.Default.Resolving event (e.g. for do it for COM hosting here ) and updating the properties in AppContext.
  5. Load and set the actual entry assembly. We need a new API for that.
  6. Execute entrypoint of the actual entry assembly

Does this sound right?

@steveisok steveisok assigned fanyang-mono and unassigned steveisok Mar 18, 2024
@elinor-fung
Copy link
Member

elinor-fung commented Mar 19, 2024

  1. Append additional assemblies to the list of app dependencies. Appending to the list of app dependencies is possible today by handling AssemblyLoadContext.Default.Resolving event (e.g. for do it for COM hosting here ) and updating the properties in AppContext.

My understanding is that a key part of the scenario is that the app dependencies takes precedence over what would be in the default probing for the default ALC, as overriding framework assemblies can be a common use case for the actual app to execute. cc @davidwrighton

@jkotas
Copy link
Member

jkotas commented Mar 19, 2024

My understanding is that a key part of the scenario is that the app dependencies takes precedence over what would be in the default probing for the default ALC, as overriding framework assemblies can be a common use case for the actual app to execute.

I agree. We should omit all overridable dependencies when starting the initial runtime to avoid them being loaded accidentally. It is very easy to load something accidentally if there is no enforcement. It is what I meant by the first step in my previous comment "Start the runtime with only a small set of dependencies. We may need something new for this, I am not sure.".

@elinor-fung
Copy link
Member

It is what I meant by the first step in my previous comment "Start the runtime with only a small set of dependencies. We may need something new for this, I am not sure.".

Ah, got it. We don't have a built-in way to do this for dotnet/apphost. But a custom host can set the TPA list / native library directories / resource assembly directories - possible via the string properties, but preferably via a more structured contract per the description in this issue.

@jkotas
Copy link
Member

jkotas commented Mar 21, 2024

structured contract

I believe that the structured contract has been an internal implementation detail so far.

Are we going to expose it and document it as a public API? I do not see a problem with it, just making sure that it is intentional lift of internal implementation detail to a public API.

@steveisok
Copy link
Member Author

I believe that the structured contract has been an internal implementation detail so far.

Are we going to expose it and document it as a public API? I do not see a problem with it, just making sure that it is intentional lift of internal implementation detail to a public API.

From what I've seen, I think we have to.

@jkotas
Copy link
Member

jkotas commented Mar 21, 2024

From what I've seen, I think we have to.

Sounds good. We should write a short description for the new public API (ie the description that we will add to the docs) and agree that it is good design.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-Host User Story A single user-facing feature. Can be grouped under an epic.
Projects
Archived in project
Development

No branches or pull requests

5 participants