diff --git a/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs b/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs index f6395b23b4..164b15c728 100644 --- a/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs +++ b/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs @@ -32,7 +32,7 @@ namespace Umbraco.Configuration.Legacy { // giant kill switch, default: false // must be explicitely set to true for anything else to happen - Enable = ConfigurationManager.AppSettings[Prefix + "Enable"] == "true"; + Enable = true; // ensure defaults are initialized for tests ModelsNamespace = Constants.ModelsBuilder.DefaultModelsNamespace; diff --git a/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs b/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs index d111dbba70..f797cc4383 100644 --- a/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs +++ b/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs @@ -29,7 +29,7 @@ namespace Umbraco.Configuration.Models /// If this is false then absolutely nothing happens. /// Default value is false which means that unless we have this setting, nothing happens. /// - public bool Enable => _configuration.GetValue(Prefix+"Enable", false); + public bool Enable => _configuration.GetValue(Prefix+"Enable", true); /// /// Gets the models mode. diff --git a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs index c5d87abf91..3e0ea9c971 100644 --- a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs +++ b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Composing "Umbraco.Core", "Umbraco.Infrastructure", "Umbraco.PublishedCache.NuCache", - // "Umbraco.ModelsBuilder.Embedded", TODO reintroduce when ModelsBuilder is migrated + "Umbraco.ModelsBuilder.Embedded", "Umbraco.Examine.Lucene", "Umbraco.Web.Common", "Umbraco.Web.BackOffice", diff --git a/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs index 3e3b116395..07b344cec3 100644 --- a/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs +++ b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs @@ -1,5 +1,6 @@ using System.Configuration; using System.IO; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; namespace Umbraco.Core.Configuration @@ -8,13 +9,13 @@ namespace Umbraco.Core.Configuration { private static string _modelsDirectoryAbsolute = null; - public static string ModelsDirectoryAbsolute(this IModelsBuilderConfig modelsBuilderConfig, IIOHelper ioHelper) + public static string ModelsDirectoryAbsolute(this IModelsBuilderConfig modelsBuilderConfig, IHostingEnvironment hostingEnvironment) { if (_modelsDirectoryAbsolute is null) { var modelsDirectory = modelsBuilderConfig.ModelsDirectory; - var root = ioHelper.MapPath("~/"); + var root = hostingEnvironment.MapPathContentRoot("~/"); _modelsDirectoryAbsolute = GetModelsDirectory(root, modelsDirectory, modelsBuilderConfig.AcceptUnsafeModelsDirectory); diff --git a/src/Umbraco.Core/PublishedModelFactoryExtensions.cs b/src/Umbraco.Core/PublishedModelFactoryExtensions.cs index a877d6a7f5..dcfa076cae 100644 --- a/src/Umbraco.Core/PublishedModelFactoryExtensions.cs +++ b/src/Umbraco.Core/PublishedModelFactoryExtensions.cs @@ -64,7 +64,7 @@ namespace Umbraco.Core { lock (liveFactory.SyncRoot) { - liveFactory.Reset(); + liveFactory.Refresh(); // TODO: Reset to Reset action(); } diff --git a/src/Umbraco.ModelsBuilder.Embedded/Building/Builder.cs b/src/Umbraco.ModelsBuilder.Embedded/Building/Builder.cs index 0e75a3839a..d49b6eb0a6 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Building/Builder.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Building/Builder.cs @@ -26,14 +26,11 @@ namespace Umbraco.ModelsBuilder.Embedded.Building protected readonly IList TypesUsing = new List { "System", - "System.Collections.Generic", "System.Linq.Expressions", - "System.Web", - "Umbraco.Core.Models", "Umbraco.Core.Models.PublishedContent", - "Umbraco.Web", "Umbraco.Web.PublishedCache", - "Umbraco.ModelsBuilder.Embedded" + "Umbraco.ModelsBuilder.Embedded", + "Umbraco.Core" }; /// diff --git a/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs b/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs index 648a2e76fa..587e1a6bc4 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs @@ -1,7 +1,7 @@ using System.IO; using System.Text; using Umbraco.Core.Configuration; -using Umbraco.Core.IO; +using Umbraco.Core.Hosting; namespace Umbraco.ModelsBuilder.Embedded.Building { @@ -10,19 +10,19 @@ namespace Umbraco.ModelsBuilder.Embedded.Building private readonly UmbracoServices _umbracoService; private readonly IModelsBuilderConfig _config; private readonly OutOfDateModelsStatus _outOfDateModels; - private readonly IIOHelper _ioHelper; + private readonly IHostingEnvironment _hostingEnvironment; - public ModelsGenerator(UmbracoServices umbracoService, IModelsBuilderConfig config, OutOfDateModelsStatus outOfDateModels, IIOHelper ioHelper) + public ModelsGenerator(UmbracoServices umbracoService, IModelsBuilderConfig config, OutOfDateModelsStatus outOfDateModels, IHostingEnvironment hostingEnvironment) { _umbracoService = umbracoService; _config = config; _outOfDateModels = outOfDateModels; - _ioHelper = ioHelper; + _hostingEnvironment = hostingEnvironment; } internal void GenerateModels() { - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); diff --git a/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs b/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs index e218a2da5f..abd5bcb85b 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs @@ -191,9 +191,10 @@ namespace Umbraco.ModelsBuilder.Embedded.Building type.ClrName); sb.Append("\t\t\t=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector);\n"); sb.Append("#pragma warning restore 0109\n\n"); + sb.Append("private IPublishedValueFallback _publishedValueFallback;"); // write the ctor - sb.AppendFormat("\t\t// ctor\n\t\tpublic {0}(IPublished{1} content)\n\t\t\t: base(content)\n\t\t{{ }}\n\n", + sb.AppendFormat("\t\t// ctor\n\t\tpublic {0}(IPublished{1} content, IPublishedValueFallback publishedValueFallback)\n\t\t\t: base(content)\n\t\t{{\n _publishedValueFallback = publishedValueFallback; \n}}\n\n", type.ClrName, type.IsElement ? "Element" : "Content"); // write the properties @@ -324,7 +325,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building WriteClrType(sb, property.ClrTypeName); sb.Append(">"); } - sb.AppendFormat("(\"{0}\");\n", + sb.AppendFormat("(_publishedValueFallback, \"{0}\");\n", property.Alias); } diff --git a/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs b/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs index f8f6e8c7bc..e4b5da0a98 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs @@ -2,6 +2,7 @@ using System.IO; using System.Text; using Umbraco.Core.Configuration; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; namespace Umbraco.ModelsBuilder.Embedded @@ -9,12 +10,12 @@ namespace Umbraco.ModelsBuilder.Embedded public sealed class ModelsGenerationError { private readonly IModelsBuilderConfig _config; - private readonly IIOHelper _ioHelper; + private readonly IHostingEnvironment _hostingEnvironment; - public ModelsGenerationError(IModelsBuilderConfig config, IIOHelper ioHelper) + public ModelsGenerationError(IModelsBuilderConfig config, IHostingEnvironment hostingEnvironment) { _config = config; - _ioHelper = ioHelper; + _hostingEnvironment = hostingEnvironment; } public void Clear() @@ -59,7 +60,7 @@ namespace Umbraco.ModelsBuilder.Embedded private string GetErrFile() { - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) return null; diff --git a/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs b/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs index b8105eeef2..0f034c04bc 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs @@ -1,5 +1,6 @@ using System.IO; using Umbraco.Core.Configuration; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Web.Cache; @@ -8,12 +9,12 @@ namespace Umbraco.ModelsBuilder.Embedded public sealed class OutOfDateModelsStatus { private readonly IModelsBuilderConfig _config; - private readonly IIOHelper _ioHelper; + private readonly IHostingEnvironment _hostingEnvironment; - public OutOfDateModelsStatus(IModelsBuilderConfig config, IIOHelper ioHelper) + public OutOfDateModelsStatus(IModelsBuilderConfig config, IHostingEnvironment hostingEnvironment) { _config = config; - _ioHelper = ioHelper; + _hostingEnvironment = hostingEnvironment; } internal void Install() @@ -28,7 +29,7 @@ namespace Umbraco.ModelsBuilder.Embedded private string GetFlagPath() { - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); return Path.Combine(modelsDirectory, "ood.flag"); diff --git a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs index 7809d2bf48..bc419bece4 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs @@ -9,8 +9,6 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Web; -using System.Web.Compilation; -using System.Web.WebPages.Razor; using Umbraco.Core.Configuration; using Umbraco.Core; using Umbraco.Core.Hosting; @@ -19,6 +17,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.ModelsBuilder.Embedded.Building; using File = System.IO.File; +using Umbraco.Core.Composing; namespace Umbraco.ModelsBuilder.Embedded { @@ -33,18 +32,21 @@ namespace Umbraco.ModelsBuilder.Embedded private readonly FileSystemWatcher _watcher; private int _ver, _skipver; private readonly int _debugLevel; - private BuildManager _theBuildManager; + private RoslynCompiler _roslynCompiler; private readonly Lazy _umbracoServices; // fixme: this is because of circular refs :( private UmbracoServices UmbracoServices => _umbracoServices.Value; private static readonly Regex AssemblyVersionRegex = new Regex("AssemblyVersion\\(\"[0-9]+.[0-9]+.[0-9]+.[0-9]+\"\\)", RegexOptions.Compiled); private const string ProjVirt = "~/App_Data/Models/all.generated.cs"; + private const string CodeGen = "~/App_Data/Models/"; private static readonly string[] OurFiles = { "models.hash", "models.generated.cs", "all.generated.cs", "all.dll.path", "models.err" }; private readonly IModelsBuilderConfig _config; + private readonly IHostingEnvironment _hostingEnvironment; private readonly IApplicationShutdownRegistry _hostingLifetime; - private readonly IIOHelper _ioHelper; private readonly ModelsGenerationError _errors; + private readonly ITypeFinder _typeFinder; + private readonly IPublishedValueFallback _publishedValueFallback; public PureLiveModelFactory( Lazy umbracoServices, @@ -52,22 +54,25 @@ namespace Umbraco.ModelsBuilder.Embedded IModelsBuilderConfig config, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, - IIOHelper ioHelper) + ITypeFinder typeFinder, + IPublishedValueFallback publishedValueFallback) { _umbracoServices = umbracoServices; _logger = logger; _config = config; + _hostingEnvironment = hostingEnvironment; _hostingLifetime = hostingLifetime; - _ioHelper = ioHelper; - _errors = new ModelsGenerationError(config, ioHelper); + _typeFinder = typeFinder; + _publishedValueFallback = publishedValueFallback; + _errors = new ModelsGenerationError(config, _hostingEnvironment); _ver = 1; // zero is for when we had no version _skipver = -1; // nothing to skip - RazorBuildProvider.CodeGenerationStarted += RazorBuildProvider_CodeGenerationStarted; + // RazorBuildProvider.CodeGenerationStarted += RazorBuildProvider_CodeGenerationStarted; if (!hostingEnvironment.IsHosted) return; - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -113,7 +118,7 @@ namespace Umbraco.ModelsBuilder.Embedded infos.TryGetValue(contentTypeAlias, out var info); // create model - return info == null ? element : info.Ctor(element); + return info == null ? element : info.Ctor(element, _publishedValueFallback); } // this runs only once the factory is ready @@ -200,13 +205,14 @@ namespace Umbraco.ModelsBuilder.Embedded if (_debugLevel > 0) _logger.Debug("RazorBuildProvider.CodeGenerationStarted"); - if (!(sender is RazorBuildProvider provider)) return; + // TODO: How to handle this? + // if (!(sender is RazorBuildProvider provider)) return; // add the assembly, and add a dependency to a text file that will change on each // compilation as in some environments (could not figure which/why) the BuildManager // would not re-compile the views when the models assembly is rebuilt. - provider.AssemblyBuilder.AddAssemblyReference(_modelsAssembly); - provider.AddVirtualPathDependency(ProjVirt); + //provider.AssemblyBuilder.AddAssemblyReference(_modelsAssembly); + //provider.AddVirtualPathDependency(ProjVirt); } finally { @@ -227,7 +233,7 @@ namespace Umbraco.ModelsBuilder.Embedded _hasModels = false; _pendingRebuild = true; - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -248,16 +254,13 @@ namespace Umbraco.ModelsBuilder.Embedded } // gets "the" build manager - private BuildManager TheBuildManager + private RoslynCompiler RoslynCompiler { get { - if (_theBuildManager != null) return _theBuildManager; - var prop = typeof(BuildManager).GetProperty("TheBuildManager", BindingFlags.NonPublic | BindingFlags.Static); - if (prop == null) - throw new InvalidOperationException("Could not get BuildManager.TheBuildManager property."); - _theBuildManager = (BuildManager)prop.GetValue(null); - return _theBuildManager; + if (_roslynCompiler != null) return _roslynCompiler; + _roslynCompiler = new RoslynCompiler(System.Runtime.Loader.AssemblyLoadContext.All.SelectMany(x => x.Assemblies)); + return _roslynCompiler; } } @@ -285,7 +288,7 @@ namespace Umbraco.ModelsBuilder.Embedded { // always take the BuildManager lock *before* taking the _locker lock // to avoid possible deadlock situations (see notes above) - Monitor.Enter(TheBuildManager, ref buildManagerLocked); + Monitor.Enter(RoslynCompiler, ref buildManagerLocked); _locker.EnterUpgradeableReadLock(); @@ -343,13 +346,13 @@ namespace Umbraco.ModelsBuilder.Embedded if (_locker.IsUpgradeableReadLockHeld) _locker.ExitUpgradeableReadLock(); if (buildManagerLocked) - Monitor.Exit(TheBuildManager); + Monitor.Exit(RoslynCompiler); } } private Assembly GetModelsAssembly(bool forceRebuild) { - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -402,7 +405,7 @@ namespace Umbraco.ModelsBuilder.Embedded if (File.Exists(dllPathFile)) { var dllPath = File.ReadAllText(dllPathFile); - var codegen = HttpRuntime.CodegenDir; + var codegen = CodeGen; _logger.Debug($"Cached models dll at {dllPath}."); @@ -452,7 +455,7 @@ namespace Umbraco.ModelsBuilder.Embedded _ver++; try { - assembly = BuildManager.GetCompiledAssembly(ProjVirt); + assembly = RoslynCompiler.GetCompiledAssembly(_hostingEnvironment.MapPathContentRoot(ProjVirt), Path.Combine(_hostingEnvironment.ApplicationPhysicalPath, "App_Data", $"generated.cs.{currentHash}.dll")); File.WriteAllText(dllPathFile, assembly.Location); } catch @@ -490,7 +493,7 @@ namespace Umbraco.ModelsBuilder.Embedded // compile and register try { - assembly = BuildManager.GetCompiledAssembly(ProjVirt); + assembly = RoslynCompiler.GetCompiledAssembly(_hostingEnvironment.MapPathContentRoot(ProjVirt), Path.Combine(_hostingEnvironment.ApplicationPhysicalPath, "App_Data", $"generated.cs.{currentHash}.dll")); File.WriteAllText(dllPathFile, assembly.Location); File.WriteAllText(modelsHashFile, currentHash); } @@ -523,7 +526,7 @@ namespace Umbraco.ModelsBuilder.Embedded private static Infos RegisterModels(IEnumerable types) { - var ctorArgTypes = new[] { typeof(IPublishedElement) }; + var ctorArgTypes = new[] { typeof(IPublishedElement), typeof(IPublishedValueFallback) }; var modelInfos = new Dictionary(StringComparer.InvariantCultureIgnoreCase); var map = new Dictionary(); @@ -535,7 +538,7 @@ namespace Umbraco.ModelsBuilder.Embedded foreach (var ctor in type.GetConstructors()) { var parms = ctor.GetParameters(); - if (parms.Length == 1 && typeof(IPublishedElement).IsAssignableFrom(parms[0].ParameterType)) + if (parms.Length == 2 && typeof(IPublishedElement).IsAssignableFrom(parms[0].ParameterType) && typeof(IPublishedValueFallback).IsAssignableFrom(parms[1].ParameterType)) { if (constructor != null) throw new InvalidOperationException($"Type {type.FullName} has more than one public constructor with one argument of type, or implementing, IPropertySet."); @@ -562,7 +565,7 @@ namespace Umbraco.ModelsBuilder.Embedded gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Newobj, constructor); gen.Emit(OpCodes.Ret); - var func = (Func)meth.CreateDelegate(typeof(Func)); + var func = (Func)meth.CreateDelegate(typeof(Func)); modelInfos[typeName] = new ModelInfo { ParameterType = parameterType, Ctor = func, ModelType = type }; map[typeName] = type; @@ -573,7 +576,7 @@ namespace Umbraco.ModelsBuilder.Embedded private string GenerateModelsCode(IList typeModels) { - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -651,7 +654,7 @@ namespace Umbraco.ModelsBuilder.Embedded internal class ModelInfo { public Type ParameterType { get; set; } - public Func Ctor { get; set; } + public Func Ctor { get; set; } public Type ModelType { get; set; } public Func ListCtor { get; set; } } diff --git a/src/Umbraco.ModelsBuilder.Embedded/ReferencedAssemblies.cs b/src/Umbraco.ModelsBuilder.Embedded/ReferencedAssemblies.cs index 596e63d8e1..7094f3fd38 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/ReferencedAssemblies.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/ReferencedAssemblies.cs @@ -9,12 +9,12 @@ namespace Umbraco.ModelsBuilder.Embedded internal static class ReferencedAssemblies { private static readonly Lazy> LazyLocations; - + // TODO: Do we even use this anymore? static ReferencedAssemblies() { - LazyLocations = new Lazy>(() => Current.HostingEnvironment.IsHosted // fixme inject! - ? GetAllReferencedAssembliesLocationFromBuildManager() - : GetAllReferencedAssembliesFromDomain()); + //LazyLocations = new Lazy>(() => Current.HostingEnvironment.IsHosted // fixme inject! + // ? GetAllReferencedAssembliesLocationFromBuildManager() + // : GetAllReferencedAssembliesFromDomain()); } /// @@ -26,7 +26,7 @@ namespace Umbraco.ModelsBuilder.Embedded public static Assembly GetNetStandardAssembly(List assemblies) { if (assemblies == null) - assemblies = BuildManager.GetReferencedAssemblies().Cast().ToList(); + //assemblies = BuildManager.GetReferencedAssemblies().Cast().ToList(); // for some reason, netstandard is also missing from BuildManager.ReferencedAssemblies and yet, is part of // the references that CSharpCompiler (above) receives - where is it coming from? cannot figure it out @@ -60,34 +60,34 @@ namespace Umbraco.ModelsBuilder.Embedded } // hosted, get referenced assemblies from the BuildManager and filter - private static IEnumerable GetAllReferencedAssembliesLocationFromBuildManager() - { - var assemblies = BuildManager.GetReferencedAssemblies().Cast().ToList(); + //private static IEnumerable GetAllReferencedAssembliesLocationFromBuildManager() + //{ + // //var assemblies = BuildManager.GetReferencedAssemblies().Cast().ToList(); - assemblies.Add(typeof(ReferencedAssemblies).Assembly); // always include ourselves + // assemblies.Add(typeof(ReferencedAssemblies).Assembly); // always include ourselves - // see https://github.com/aspnet/RoslynCodeDomProvider/blob/master/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCompiler.cs: - // mentions "Bug 913691: Explicitly add System.Runtime as a reference." - // and explicitly adds System.Runtime to references before invoking csc.exe - // so, doing the same here - try - { - var systemRuntime = Assembly.Load("System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); - assemblies.Add(systemRuntime); - } - catch { /* never mind */ } + // // see https://github.com/aspnet/RoslynCodeDomProvider/blob/master/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCompiler.cs: + // // mentions "Bug 913691: Explicitly add System.Runtime as a reference." + // // and explicitly adds System.Runtime to references before invoking csc.exe + // // so, doing the same here + // try + // { + // var systemRuntime = Assembly.Load("System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); + // assemblies.Add(systemRuntime); + // } + // catch { /* never mind */ } - // for some reason, netstandard is also missing from BuildManager.ReferencedAssemblies and yet, is part of - // the references that CSharpCompiler (above) receives - where is it coming from? cannot figure it out - var netStandard = GetNetStandardAssembly(assemblies); - if (netStandard != null) assemblies.Add(netStandard); + // // for some reason, netstandard is also missing from BuildManager.ReferencedAssemblies and yet, is part of + // // the references that CSharpCompiler (above) receives - where is it coming from? cannot figure it out + // var netStandard = GetNetStandardAssembly(assemblies); + // if (netStandard != null) assemblies.Add(netStandard); - return assemblies - .Where(x => !x.IsDynamic && !x.Location.IsNullOrWhiteSpace()) - .Select(x => x.Location) - .Distinct() - .ToList(); - } + // return assemblies + // .Where(x => !x.IsDynamic && !x.Location.IsNullOrWhiteSpace()) + // .Select(x => x.Location) + // .Distinct() + // .ToList(); + //} // non-hosted, do our best private static IEnumerable GetAllReferencedAssembliesFromDomain() diff --git a/src/Umbraco.ModelsBuilder.Embedded/RoslynCompiler.cs b/src/Umbraco.ModelsBuilder.Embedded/RoslynCompiler.cs index 43a9202c13..ed9c013236 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/RoslynCompiler.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/RoslynCompiler.cs @@ -5,6 +5,7 @@ using Microsoft.CodeAnalysis.Text; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using System.Text; @@ -14,21 +15,38 @@ namespace Umbraco.ModelsBuilder.Embedded { private OutputKind _outputKind; private CSharpParseOptions _parseOptions; + private List _refs; - public RoslynCompiler() + public RoslynCompiler(IEnumerable referenceAssemblies) { _outputKind = OutputKind.DynamicallyLinkedLibrary; _parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest); // What languageversion should we default to? + + // The references should be the same every time GetCompiledAssembly is called + // Making it kind of a waste to convert the Assembly types into MetadataReference + // every time GetCompiledAssembly is called, so that's why I do it in the ctor + _refs = new List(); + foreach(var assembly in referenceAssemblies.Where(x => !x.IsDynamic && !string.IsNullOrWhiteSpace(x.Location))) + { + _refs.Add(MetadataReference.CreateFromFile(assembly.Location)); + }; + + // Might have to do this another way, see + // see https://github.com/aspnet/RoslynCodeDomProvider/blob/master/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCompiler.cs: + // mentions "Bug 913691: Explicitly add System.Runtime as a reference." + // and explicitly adds System.Runtime to references before invoking csc.exe + _refs.Add(MetadataReference.CreateFromFile(typeof(System.Runtime.AssemblyTargetedPatchBandAttribute).Assembly.Location)); + _refs.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)); + _refs.Add(MetadataReference.CreateFromFile(typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).Assembly.Location)); } - public Assembly GetCompiledAssembly(string pathToSourceFile, IEnumerable refs) + public Assembly GetCompiledAssembly(string pathToSourceFile, string saveLocation) { // TODO: Get proper temp file location/filename - var outputPath = $"generated.cs.{Guid.NewGuid()}.dll"; var sourceCode = File.ReadAllText(pathToSourceFile); - CompileToFile(outputPath, sourceCode, "ModelsGenerated", refs); - return Assembly.LoadFile(outputPath); + CompileToFile(saveLocation, sourceCode, "ModelsGeneratedAssembly", _refs); + return Assembly.LoadFile(saveLocation); } @@ -46,7 +64,8 @@ namespace Umbraco.ModelsBuilder.Embedded // Not entirely certain that assemblyIdentityComparer is nececary? assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default)); - compilation.Emit(outputFile); + var result = compilation.Emit(outputFile); + } } } diff --git a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj index 40ed5a8093..0feb289806 100644 --- a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj +++ b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj @@ -98,6 +98,7 @@ +