/// <summary> /// An event handler for resolving Silverlight framework assembly versioning. /// </summary> /// <remarks> /// When a previous version of a Silverlight assembly is sought, the targeted version /// of that Silverlight assembly will be returned. /// </remarks> /// <param name="sender">The event sender.</param> /// <param name="args">The assembly resolution event arguments.</param> /// <returns>The <see cref="Assembly"/> from the targeted version of Silverlight, or <c>null</c>.</returns> private static Assembly ResolveFrameworkAssemblyVersioning(object sender, ResolveEventArgs args) { FrameworkManifest frameworkManifest = (FrameworkManifest)AppDomain.CurrentDomain.GetData(AppDomainUtilities.FrameworkManifestKey); System.Diagnostics.Debug.Assert(frameworkManifest != null, "The FrameworkManifest must have been set on the AppDomain"); AssemblyName requestedAssembly = new AssemblyName(args.Name); // If the requested assembly is a System assembly and it's an older version // than the framework manifest has, then we'll need to resolve to its newer version bool isOldVersion = requestedAssembly.Version.CompareTo(frameworkManifest.SystemVersion) < 0; if (isOldVersion && requestedAssembly.IsSystemAssembly()) { // Now we need to see if the requested assembly is part of the framework manifest (as opposed to an SDK assembly) FrameworkManifestEntry silverlightAssembly; // If the assembly is part of the framework manifest, then we need to "redirect" its resolution // to the current framework version. if (frameworkManifest.Assemblies.TryGetValue(requestedAssembly.Name, out silverlightAssembly)) { // Find the Silverlight framework assembly from the already-loaded assemblies var matches = from assembly in AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies() let assemblyName = assembly.GetName() where assemblyName.Name == silverlightAssembly.Name && assemblyName.GetPublicKeyToken().SequenceEqual(silverlightAssembly.PublicKeyTokenBytes) && assemblyName.Version.CompareTo(silverlightAssembly.Version) == 0 select assembly; return(matches.SingleOrDefault()); } } return(null); }
/// <summary> /// Creates an <see cref="AppDomain"/> configured for client code generation. /// </summary> /// <param name="options">The code generation options.</param> internal static void ConfigureAppDomain(ClientCodeGenerationOptions options) { FrameworkManifest frameworkManifest = GetFrameworkManifest(options.ClientFrameworkPath); AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += AppDomainUtilities.ResolveFrameworkAssemblyVersioning; AppDomain.CurrentDomain.SetData(FrameworkManifestKey, frameworkManifest); }
/// <summary> /// Gets the list of Silverlight assemblies found in the manifest within the specified /// Silverlight framework directory. /// </summary> /// <param name="silverlightFrameworkDirectory">The directory containing the Silverlight framework manifest.</param> /// <returns>The list of assemblies that are part of the Silverlight runtime.</returns> private static FrameworkManifest GetSilverlightFrameworkManifest(string silverlightFrameworkDirectory) { FrameworkManifest manifest = new FrameworkManifest(); List <FrameworkManifestEntry> assemblies = new List <FrameworkManifestEntry>(); XPathDocument manifestDocument = new XPathDocument(silverlightFrameworkDirectory + SilverlightManifestFilename); XPathNavigator navigator = manifestDocument.CreateNavigator(); XPathNodeIterator iterator = navigator.Select("/manifest/*[name and publickeytoken and version]"); while (iterator.MoveNext()) { // guaranteed to have name, publickeytoken and version by the XPath query iterator.Current.MoveToChild("name", string.Empty); string name = iterator.Current.Value; iterator.Current.MoveToParent(); iterator.Current.MoveToChild("publickeytoken", string.Empty); string publickeytoken = iterator.Current.Value; iterator.Current.MoveToParent(); iterator.Current.MoveToChild("version", string.Empty); string version = iterator.Current.Value; iterator.Current.MoveToParent(); // The public key token that was read as a hex string; convert it to a byte array // Every 2 characters represent a single byte in hex. byte[] publicKeyTokenBytes = Enumerable.Range(0, publickeytoken.Length) .Where(x => 0 == x % 2) .Select(x => Convert.ToByte(publickeytoken.Substring(x, 2), 16)) .ToArray(); FrameworkManifestEntry assembly = new FrameworkManifestEntry(); assembly.Name = name; assembly.Version = new Version(version); assembly.PublicKeyTokenBytes = publicKeyTokenBytes; assemblies.Add(assembly); } manifest.Assemblies = assemblies.ToArray(); return(manifest); }
/// <summary> /// Gets the list of Silverlight assemblies found in the manifest within the specified /// Silverlight framework directory. /// </summary> /// <param name="silverlightFrameworkDirectory">The directory containing the Silverlight framework manifest.</param> /// <returns>The list of assemblies that are part of the Silverlight runtime.</returns> private static FrameworkManifest GetSilverlightFrameworkManifest(string silverlightFrameworkDirectory) { FrameworkManifest manifest = new FrameworkManifest(); List<FrameworkManifestEntry> assemblies = new List<FrameworkManifestEntry>(); XPathDocument manifestDocument = new XPathDocument(silverlightFrameworkDirectory + SilverlightManifestFilename); XPathNavigator navigator = manifestDocument.CreateNavigator(); XPathNodeIterator iterator = navigator.Select("/manifest/*[name and publickeytoken and version]"); while (iterator.MoveNext()) { // guaranteed to have name, publickeytoken and version by the XPath query iterator.Current.MoveToChild("name", string.Empty); string name = iterator.Current.Value; iterator.Current.MoveToParent(); iterator.Current.MoveToChild("publickeytoken", string.Empty); string publickeytoken = iterator.Current.Value; iterator.Current.MoveToParent(); iterator.Current.MoveToChild("version", string.Empty); string version = iterator.Current.Value; iterator.Current.MoveToParent(); // The public key token that was read as a hex string; convert it to a byte array // Every 2 characters represent a single byte in hex. byte[] publicKeyTokenBytes = Enumerable.Range(0, publickeytoken.Length) .Where(x => 0 == x % 2) .Select(x => Convert.ToByte(publickeytoken.Substring(x, 2), 16)) .ToArray(); FrameworkManifestEntry assembly = new FrameworkManifestEntry(); assembly.Name = name; assembly.Version = new Version(version); assembly.PublicKeyTokenBytes = publicKeyTokenBytes; assemblies.Add(assembly); } manifest.Assemblies = assemblies.ToArray(); return manifest; }