dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.95k stars 4.65k forks source link

Framework assembly overrides in component dependency resolution on self-contained apps #3641

Open vitek-karas opened 5 years ago

vitek-karas commented 5 years ago

Currently AssemblyDependencyResolver is designed to explicitly not resolve any assemblies from the app itself (to avoid mixing plugins with hosting app). It also explicitly doesn't resolve assemblies from the framework (to encourage sharing framework assemblies, avoiding potential issues which can occur when framework assemblies are loaded multiple times in the process).

There's one exception to this: If the component has an assembly which also exists in the framework, we perform version checks and pick the higher version - so potentially use the one from the framework. (Note that we explicitly don't do this checks for assemblies which are both in app and the component).

The question is what should happen if we're running in a self-contained app. In that case there's no way to differentiate application assemblies from framework assemblies - the self-contained app is one big pile. So in this case, if the component carries an assembly which also exists in the framework, we have no way to tell if it's part of the app, or if it's really a framework assembly (and thus we should do the version checks).

As such there are two options.

1 - Completely ignore app/FX assemblies in self-contained apps for component dependency resolution

This would mean that the behavior between self-contained and framework-dependent is very similar, with the exception of the version checks - the assembly from the component would always win in self-contained app (as oppose to framework dependent, where sometimes the one from the framework may win). Pros: keep the good separation between app and component Cons: potentially duplicated framework assemblies (different versions) - this is possible to implement on top of the AssemblyDependencyResolver with some guesses of what assemblies are "framework".

2 - Treat the entire app as a framework for self-contained apps

In this case we would get the version checks for framework assemblies, but we would also get those for any assembly which exists both in the app and in the component. Great example would be Newtonsoft.JSON - if the app uses newer version that the component, the newer version from the app would be resolved for the component. Pros: no duplication of framework assemblies (only one version would resolve for everybody) Cons: basically no separation between app and component - very hard to implement isolation on top of such AssemblyDependencyResolver - would have to rely at looking at paths on disk and guessing.

Potentially we could implement some kind of heuristic how to guess which assemblies are framework assemblies - this could be done based on names (System.*) or based on some info in the .deps.json - for example that it comes from a specifically named runtime pack.

Unfortunately AFAIK there's no clean solution which would make self-contained and framework-dependent behave consistently without SDK changes.

vitek-karas commented 5 years ago

@elinor-fung @sdmaclea @lpereira @AaronRobinsonMSFT @swaroop-sridhar @davidfowl

vitek-karas commented 5 years ago

Had an offline discussion on this topic:

The plan is to:

vitek-karas commented 5 years ago

I created https://github.com/dotnet/sdk/issues/3339 to track the ask on SDK for the additional information about framework assemblies.

dleeapho commented 5 years ago

/cc @leecow

vitek-karas commented 5 years ago

Moving this out of 3.0 as it requires SDK changes which won't make it in time.

vitek-karas commented 4 years ago

The SDK side is resolved. There's no need for a new property as each framework is already marked with type=runtimepack. As per discussion in https://github.com/dotnet/runtime/issues/36765 this should be enough for the host to implement this feature.