docs/design/features/assembly-conflict-resolution.md
This document describes current behavior for dealing with references to assemblies that exist physically in more than one location including the "app" location and "framework" location(s).
When a CoreCLR app is being launched, it builds a list of "probing" locations and then iterates through each <layer's'>.app.deps.json file. For each assembly entry in that file, it uses the probing locations in order to determine the physical location of the assembly. Once all deps.json files are parsed, that information (which consists of a list of full paths to assemblies) is passed to the CLR which it uses to load each assembly when it is accessed.
A layer consists of the app at the highest layer, then a chain of one or more framework layers ending with Microsoft.NETCore.App as the lowest layer. For 2.0 and earlier, there were only the app and Microsoft.NETCore.App layers. For 2.1+, those two layers exist plus additional, optional frameworks in-between those two.
Since each layer (and other probing locations) can contain the same assembly by name, the "host policy" determines the semantics for conflict cases where the same assembly exists more than once. The "host policy" logic lives in hostpolicy.dll located in the Microsoft.NETCore.App's folder.
The probing locations consists of:
runtimeconfig.dev.json or via --additionalprobingpath fileDetailed description of the exact probe locations is described in host-probing.
Once a deps.json entry has been found in a probe location, no further probes are performed for that entry.
The order in which each layer's deps.json is processed is:
--additional-deps argument.deps.json.deps.json to see if it contains the exact package (by name and version). If it does, then use that location and end probing for this entry.--additional-deps and repeat steps 3-7Note that for an app both its .deps.json as well as probing path comes before the framework's .deps.json, so the app will usually win. Also because the app will likely reference an OOB package that the framework doesn't (because a framework, at least Microsoft.NETCore.App, has its own metapackage and does not reference OOB packages), the framework probing path never matches up in step 6 for the app's .deps.json package\assembly entry, so the "app wins".
The reason for only probing paths from equal or lower level framework in step 5 is that a given framework should never have a dependency on a higher-level framework, and is expected to find deps assets in its layer or lower. This is also required so that the given framework can find its asset, and replace the higher-level asset (see next paragraph).
In order to compare Assembly Version and File Version, additional metadata will need to be written to each deps.json file. If this metadata is not present (as in the case of applications published prior to 2.1) then the assembly will be considered older and will not replace any locations that the assembly was previously found at.