in src/Utilities/ToolLocationHelper.cs [3130:3280]
internal static string ChainReferenceAssemblyPath(string targetFrameworkDirectory)
{
string path = Path.GetFullPath(targetFrameworkDirectory);
lock (s_locker)
{
// Cache the results of the chain search so that we do not have to do an expensive read more than once per process per redist list.
s_chainedReferenceAssemblyPath = s_chainedReferenceAssemblyPath ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
s_cachedTargetFrameworkDisplayNames = s_cachedTargetFrameworkDisplayNames ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
string cachedPath = null;
if (s_chainedReferenceAssemblyPath.TryGetValue(path, out cachedPath))
{
return cachedPath;
}
}
// Read in the redist list at the specified path, and return
// the display name and the "include framework" value for chaining.
// If display name is not available, returns empty string.
// If include framework is not available, returns null.
// Caches the display name keyed by the path.
// Make sure we have a directory with a redist list folder and a FrameworkList.xml file in there as this is what we will use for chaining.
string redistListFolder = Path.Combine(path, "RedistList");
string redistFile = Path.Combine(redistListFolder, "FrameworkList.xml");
// If the redist list does not exist then the entire chain is incorrect.
if (!File.Exists(redistFile))
{
// Under MONO a directory may chain to one that has no redist list
var chainReference = NativeMethodsShared.IsMono ? string.Empty : null;
lock (s_locker)
{
s_chainedReferenceAssemblyPath[path] = chainReference;
s_cachedTargetFrameworkDisplayNames[path] = chainReference;
}
return chainReference;
}
string includeFramework = null;
string displayName = null;
string redirectPath = null;
try
{
// Read in the xml file looking for the includeFramework inorder to chain.
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.DtdProcessing = DtdProcessing.Ignore;
using (XmlReader reader = XmlReader.Create(redistFile, readerSettings))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (string.Equals(reader.Name, "FileList", StringComparison.OrdinalIgnoreCase))
{
reader.MoveToFirstAttribute();
do
{
if (String.Equals(reader.Name, "IncludeFramework", StringComparison.OrdinalIgnoreCase))
{
includeFramework = reader.Value;
continue;
}
if (String.Equals(reader.Name, "Name", StringComparison.OrdinalIgnoreCase))
{
displayName = reader.Value;
continue;
}
// Mono may redirect this to another place
if (NativeMethodsShared.IsMono && String.Equals(reader.Name, "TargetFrameworkDirectory", StringComparison.OrdinalIgnoreCase))
{
// The new folder is relative to the place where the FrameworkList.
redirectPath = Path.GetFullPath(Path.Combine(redistListFolder, FileUtilities.FixFilePath(reader.Value)));
}
}
while (reader.MoveToNextAttribute());
reader.MoveToElement();
break;
}
}
}
}
}
catch (XmlException ex)
{
ErrorUtilities.ThrowInvalidOperation("ToolsLocationHelper.InvalidRedistFile", redistFile, ex.Message);
}
catch (Exception ex) when (ExceptionHandling.IsIoRelatedException(ex))
{
ErrorUtilities.ThrowInvalidOperation("ToolsLocationHelper.InvalidRedistFile", redistFile, ex.Message);
}
// Cache the display name if we have one
if (displayName != null)
{
lock (s_locker)
{
s_cachedTargetFrameworkDisplayNames[path] = displayName;
}
}
string pathToReturn = String.Empty;
try
{
// The IncludeFramework element could not be found so our chain is done.
if (!String.IsNullOrEmpty(includeFramework))
{
// Take the path which should point to something like c:\ProgramFiles\ReferenceAssemblies\Framework\.NETFramework\v4.1
// We will take the path, to "up" a directory then append the name found in the redist. For example if the redist list had v4.0
// the path which would be expected would be c:\ProgramFiles\ReferenceAssemblies\Framework\.NETFramework\v4.0
pathToReturn = path;
pathToReturn = Directory.GetParent(pathToReturn).FullName;
pathToReturn = Path.Combine(pathToReturn, includeFramework);
pathToReturn = Path.GetFullPath(pathToReturn);
// The directory which we are chaining to does not exist, return null indicating the chain is incorrect.
if (!Directory.Exists(pathToReturn))
{
pathToReturn = null;
}
}
// We may also have a redirect path
else if (!string.IsNullOrEmpty(redirectPath) && Directory.Exists(redirectPath))
{
pathToReturn = redirectPath;
}
lock (s_locker)
{
s_chainedReferenceAssemblyPath[path] = pathToReturn;
}
return pathToReturn;
}
catch (Exception e)
{
if (ExceptionHandling.IsCriticalException(e))
throw;
ErrorUtilities.ThrowInvalidOperation("ToolsLocationHelper.CouldNotCreateChain", path, pathToReturn, e.Message);
}
return null;
}