diff --git a/src/React.MSBuild/AssemblyBindingRedirect.cs b/src/React.MSBuild/AssemblyBindingRedirect.cs new file mode 100644 index 000000000..c88a85d6b --- /dev/null +++ b/src/React.MSBuild/AssemblyBindingRedirect.cs @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2017-Present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Reflection; + +namespace React.MSBuild +{ + /// + /// Hacks around the fact that it's not possible to do assembly binding redirects in MSBuild. + /// + /// https://github.com/Microsoft/msbuild/issues/1309 + /// http://blog.slaks.net/2013-12-25/redirecting-assembly-loads-at-runtime/ + /// + public static class AssemblyBindingRedirect + { + /// + /// Redirects that have been configured + /// + private static readonly Dictionary _redirects = new Dictionary(); + + static AssemblyBindingRedirect() + { + // This is in a static constructor because it needs to run as early as possible + ConfigureRedirect("JavaScriptEngineSwitcher.Core"); + AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; + } + + /// + /// Enables assembly binding redirects + /// + public static void Enable() + { + // Intentionally empty. This is just meant to ensure the static constructor + // has run. + } + + /// + /// Configures a redirect for the specified assembly. Redirects to the version in the bin directory. + /// + /// Name of the assembly to redirect + private static void ConfigureRedirect(string name) + { + var currentAssemblyPath = Assembly.GetExecutingAssembly().Location; + var redirectAssemblyPath = Path.Combine( + Path.GetDirectoryName(currentAssemblyPath), + name + ".dll" + ); + + try + { + var realAssembly = Assembly.LoadFile(redirectAssemblyPath); + var version = realAssembly.GetName().Version; + _redirects[name] = version; + } + catch (Exception ex) + { + Trace.WriteLine("Warning: Could not determine version of " + name + " to use! " + ex.Message); + } + } + + /// + /// Overrides assembly resolution to redirect if necessary. + /// + private static Assembly ResolveAssembly(object sender, ResolveEventArgs args) + { + var requestedAssembly = new AssemblyName(args.Name); + + if (_redirects.ContainsKey(requestedAssembly.Name) && requestedAssembly.Version != _redirects[requestedAssembly.Name]) + { + requestedAssembly.Version = _redirects[requestedAssembly.Name]; + return Assembly.Load(requestedAssembly); + } + return null; + } + } +} diff --git a/src/React.MSBuild/MSBuildHost.cs b/src/React.MSBuild/MSBuildHost.cs index 75668032f..291f5191a 100644 --- a/src/React.MSBuild/MSBuildHost.cs +++ b/src/React.MSBuild/MSBuildHost.cs @@ -9,6 +9,7 @@ using System; using System.Diagnostics; +using System.Reflection; namespace React.MSBuild { @@ -36,6 +37,8 @@ public static bool EnsureInitialized() /// private static bool Initialize() { + AssemblyBindingRedirect.Enable(); + // All "per-request" registrations should be singletons in MSBuild, since there's no // such thing as a "request" Initializer.Initialize(requestLifetimeRegistration: registration => registration.AsSingleton()); diff --git a/src/React.Sample.Cassette/Web.config b/src/React.Sample.Cassette/Web.config index 76ddce629..03f710621 100644 --- a/src/React.Sample.Cassette/Web.config +++ b/src/React.Sample.Cassette/Web.config @@ -62,7 +62,7 @@ - + diff --git a/src/React.Sample.Mvc4/Web.config b/src/React.Sample.Mvc4/Web.config index f40e147d4..a763dbb65 100644 --- a/src/React.Sample.Mvc4/Web.config +++ b/src/React.Sample.Mvc4/Web.config @@ -92,6 +92,10 @@ + + + +