Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

185 lines
8.3 KiB
C#

// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security;
using Microsoft.Internal.Web.Utils;
using Microsoft.Web.Infrastructure;
namespace System.Web.WebPages.Deployment
{
internal static class AssemblyUtils
{
// Copied from AssemblyRefs.cs
private const string SharedLibPublicKey = "31bf3856ad364e35";
internal static readonly AssemblyName ThisAssemblyName = new AssemblyName(typeof(AssemblyUtils).Assembly.FullName);
private static readonly Version WebPagesV1Version = new Version(1, 0, 0, 0);
private static readonly string _binFileName = Path.GetFileName(ThisAssemblyName.Name) + ".dll";
// Special case MWI because it does not share the same assembly version as the rest of WebPages.
private static readonly Version _mwiVersion = new AssemblyName(typeof(InfrastructureHelper).Assembly.FullName).Version;
private static readonly AssemblyName _mwiAssemblyName = GetFullName("Microsoft.Web.Infrastructure", _mwiVersion);
private static readonly AssemblyName[] _version1AssemblyList = new[]
{
_mwiAssemblyName,
GetFullName("System.Web.Razor", WebPagesV1Version),
GetFullName("System.Web.Helpers", WebPagesV1Version),
GetFullName("System.Web.WebPages", WebPagesV1Version),
GetFullName("System.Web.WebPages.Administration", WebPagesV1Version),
GetFullName("System.Web.WebPages.Razor", WebPagesV1Version),
GetFullName("WebMatrix.Data", WebPagesV1Version),
GetFullName("WebMatrix.WebData", WebPagesV1Version)
};
private static readonly AssemblyName[] _versionCurrentAssemblyList = new[]
{
_mwiAssemblyName,
GetFullName("System.Web.Razor", ThisAssemblyName.Version),
GetFullName("System.Web.Helpers", ThisAssemblyName.Version),
GetFullName("System.Web.WebPages", ThisAssemblyName.Version),
GetFullName("System.Web.WebPages.Administration", ThisAssemblyName.Version),
GetFullName("System.Web.WebPages.Razor", ThisAssemblyName.Version),
GetFullName("WebMatrix.Data", ThisAssemblyName.Version),
GetFullName("WebMatrix.WebData", ThisAssemblyName.Version)
};
internal static Version GetMaxWebPagesVersion()
{
return GetMaxWebPagesVersion(GetLoadedAssemblies());
}
internal static Version GetMaxWebPagesVersion(IEnumerable<AssemblyName> loadedAssemblies)
{
return GetWebPagesAssemblies(loadedAssemblies).Max(c => c.Version);
}
internal static bool IsVersionAvailable(Version version)
{
return IsVersionAvailable(GetLoadedAssemblies(), version);
}
internal static bool IsVersionAvailable(IEnumerable<AssemblyName> loadedAssemblies, Version version)
{
return GetWebPagesAssemblies(loadedAssemblies).Any(c => c.Version == version);
}
private static IEnumerable<AssemblyName> GetWebPagesAssemblies(IEnumerable<AssemblyName> loadedAssemblies)
{
return (from otherName in loadedAssemblies
where NamesMatch(ThisAssemblyName, otherName, matchVersion: false)
select otherName);
}
/// <summary>
/// Returns the version of a System.Web.WebPages.Deployment.dll if it is present in the bin and matches the name and
/// public key token of the current assembly.
/// </summary>
/// <returns>Version from bin if present, null otherwise.</returns>
internal static Version GetVersionFromBin(string binDirectory, IFileSystem fileSystem, Func<string, AssemblyName> getAssemblyNameThunk = null)
{
// If a version of the assembly is present both in the bin and the GAC, the GAC would win.
// To work around this, we'll look for a physical file on disk with the same name as the current assembly and load it to determine the version.
// Determine if the Deployment assembly is present in the bin
var assemblyInBin = Path.Combine(binDirectory, _binFileName);
if (fileSystem.FileExists(assemblyInBin))
{
try
{
getAssemblyNameThunk = getAssemblyNameThunk ?? AssemblyName.GetAssemblyName;
AssemblyName assemblyName = getAssemblyNameThunk(assemblyInBin);
if (NamesMatch(ThisAssemblyName, assemblyName, matchVersion: false))
{
return assemblyName.Version;
}
}
catch (BadImageFormatException)
{
// Do nothing.
}
catch (SecurityException)
{
// Do nothing
}
catch (FileLoadException)
{
// Do nothing.
}
}
return null;
}
internal static bool NamesMatch(AssemblyName left, AssemblyName right, bool matchVersion)
{
return Equals(left.Name, right.Name) &&
Equals(left.CultureInfo, right.CultureInfo) &&
Enumerable.SequenceEqual(left.GetPublicKeyToken(), right.GetPublicKeyToken()) &&
(!matchVersion || Equals(left.Version, right.Version));
}
internal static IEnumerable<AssemblyName> GetLoadedAssemblies()
{
return AppDomain.CurrentDomain.GetAssemblies()
.Select(GetAssemblyName)
.ToList();
}
internal static IEnumerable<AssemblyName> GetAssembliesForVersion(Version version)
{
if (version == WebPagesV1Version)
{
return _version1AssemblyList;
}
return _versionCurrentAssemblyList;
}
private static AssemblyName GetAssemblyName(Assembly assembly)
{
return new AssemblyName(assembly.FullName);
}
private static AssemblyName GetFullName(string name, Version version, string publicKeyToken)
{
return new AssemblyName(String.Format(CultureInfo.InvariantCulture,
"{0}, Version={1}, Culture=neutral, PublicKeyToken={2}",
name, version, publicKeyToken));
}
internal static AssemblyName GetFullName(string name, Version version)
{
return GetFullName(name, version, SharedLibPublicKey);
}
public static IDictionary<string, Version> GetAssembliesMatchingOtherVersions(IDictionary<string, IEnumerable<string>> references)
{
var webPagesAssemblies = AssemblyUtils.GetAssembliesForVersion(AssemblyUtils.ThisAssemblyName.Version);
if (webPagesAssemblies == null || !webPagesAssemblies.Any())
{
return new Dictionary<string, Version>(0);
}
var matchingVersions = from item in references
let matchedVersion = GetMatchingVersion(webPagesAssemblies, item.Value)
where matchedVersion != null
select new KeyValuePair<string, Version>(item.Key, matchedVersion);
return matchingVersions.ToDictionary(k => k.Key, k => k.Value);
}
private static Version GetMatchingVersion(IEnumerable<AssemblyName> webPagesAssemblies, IEnumerable<string> references)
{
// Return assemblies that match in name but not in version.
var matchingVersions = from webPagesAssembly in webPagesAssemblies
from referenceName in references
let referencedAssembly = new AssemblyName(referenceName)
where AssemblyUtils.NamesMatch(webPagesAssembly, referencedAssembly, matchVersion: false) && webPagesAssembly.Version != referencedAssembly.Version
select referencedAssembly.Version;
return matchingVersions.FirstOrDefault();
}
}
}