public static bool Execute(bool isSecondPass, string flagsString, string referencePathsString, string sourceAssemblyForPass2, string nameOfAssembliesThatDoNotContainUserCode, bool isBridgeBasedVersion, bool isProcessingCSHTML5Itself, ILogger logger, string typeForwardingAssemblyPath) #endif { string passNumber = (isSecondPass ? "2" : "1"); string operationName = string.Format("C#/XAML for HTML5: BeforeXamlPreprocessor (pass {0})", passNumber); try { using (var executionTimeMeasuring = new ExecutionTimeMeasuring()) { //------- DISPLAY THE PROGRESS ------- logger.WriteMessage(operationName + " started."); //----------------------------------------------------- // Note: we create a static instance of the "ReflectionOnSeparateAppDomainHandler" to avoid reloading the assemblies for each XAML file. // We dispose the static instance in the "AfterXamlPreprocessor" task. //----------------------------------------------------- if (isSecondPass && string.IsNullOrEmpty(sourceAssemblyForPass2)) { throw new Exception(operationName + " failed because the SourceAssembly parameter was not specified during the second pass."); } // Create a new static instance of the "ReflectionOnSeparateAppDomainHandler": ReflectionOnSeparateAppDomainHandler.Current = new ReflectionOnSeparateAppDomainHandler(typeForwardingAssemblyPath); ReflectionOnSeparateAppDomainHandler reflectionOnSeparateAppDomain = ReflectionOnSeparateAppDomainHandler.Current; #if BRIDGE //todo: if we are compiling CSHTML5 itself (or CSHTML5.Stubs), we need to process the XAML files in CSHTML5, // and for that we need to load the XAML types, so we need to load the previous version of CSHTML5 (from // the NuGet package). Note: this is not supposed to lead to a circular reference because it is only used // for the XamlPreprocessor to generate the .xaml.g.cs files from the .xaml files. // To do so, we need to stop skipping the processing of the CSHTML5 and CSHTML5.Stubs assemblies (c.f. // "Skip the assembly if it is not a user assembly" in "LoadAndProcessReferencedAssemblies"). #endif // we load the source assembly early in case we are processing the CSHTML5. if (isSecondPass && isProcessingCSHTML5Itself) { reflectionOnSeparateAppDomain.LoadAssembly(sourceAssemblyForPass2, loadReferencedAssembliesToo: true, isBridgeBasedVersion: isBridgeBasedVersion, isCoreAssembly: false, nameOfAssembliesThatDoNotContainUserCode: nameOfAssembliesThatDoNotContainUserCode); } #if CSHTML5BLAZOR // work-around: reference path string is not correctly setted so we set it manually string referencePathsString = OpenSilverHelper.ReferencePathsString(resolvedReferences); #endif // Retrieve paths of referenced .dlls and load them: HashSet <string> referencePaths = (referencePathsString != null) ? new HashSet <string>(referencePathsString.Split(';')) : new HashSet <string>(); referencePaths.RemoveWhere(s => !s.ToLower().EndsWith(".dll") || s.Contains("DotNetBrowser") || s.ToLower().EndsWith(@"\bridge.dll")); foreach (string referencedAssembly in AssembliesLoadHelper.EnsureCoreAssemblyIsFirstInList(referencePaths)) // Note: we ensure that the Core assembly is loaded first so that types such as "XmlnsDefinitionAttribute" are known when loading the other assemblies. { reflectionOnSeparateAppDomain.LoadAssembly(referencedAssembly, loadReferencedAssembliesToo: false, isBridgeBasedVersion: isBridgeBasedVersion, isCoreAssembly: false, nameOfAssembliesThatDoNotContainUserCode: nameOfAssembliesThatDoNotContainUserCode); } // Load "mscorlib.dll" too (this is useful for resolving Mscorlib types in XAML, such as <system:String x:Key="TestString" xmlns:system="clr-namespace:System;assembly=mscorlib">Test</system:String>) reflectionOnSeparateAppDomain.LoadAssemblyMscorlib(isBridgeBasedVersion: isBridgeBasedVersion, isCoreAssembly: false, nameOfAssembliesThatDoNotContainUserCode: nameOfAssembliesThatDoNotContainUserCode); // Load for reflection the source assembly itself and the referenced assemblies if second path: if (isSecondPass && !isProcessingCSHTML5Itself) { reflectionOnSeparateAppDomain.LoadAssembly(sourceAssemblyForPass2, loadReferencedAssembliesToo: true, isBridgeBasedVersion: isBridgeBasedVersion, isCoreAssembly: false, nameOfAssembliesThatDoNotContainUserCode: nameOfAssembliesThatDoNotContainUserCode); } bool isSuccess = true; //------- DISPLAY THE PROGRESS ------- logger.WriteMessage(operationName + (isSuccess ? " completed in " + executionTimeMeasuring.StopAndGetTimeInSeconds() + " seconds." : " failed.") + "\". IsSecondPass: "******". Source assembly file: \"" + (sourceAssemblyForPass2 ?? "").ToString()); return(isSuccess); } } catch (Exception ex) { if (ReflectionOnSeparateAppDomainHandler.Current != null) { ReflectionOnSeparateAppDomainHandler.Current.Dispose(); } logger.WriteError(operationName + " failed: " + ex.ToString()); return(false); } }
static void IsReferenceAcceptable(string referenceName, string referenceHintPath, string allowedAssemblies, HashSet <string> flags, bool isBridgeBasedVersion, string nameOfAssembliesThatDoNotContainUserCode, string projectDir, string referencesPaths, string typeForwardingAssemblyPath, out ResultEnum result, out string minimumRequiredCompilerVersionFriendlyNameIfAny) { minimumRequiredCompilerVersionFriendlyNameIfAny = null; //-------------------------------------------------------------------------------- // This method will verify that the referenced DLL is itself of type C#/XAML for HTML5, and that the minimum version number is OK. //-------------------------------------------------------------------------------- #if !BRIDGE // Check if the reference is a file that belongs to "C#/XAML for HTML5": if (referenceName.ToLower().Contains(Constants.LOWERCASE_CORE_ASSEMBLY_NAME) || (!string.IsNullOrEmpty(referenceHintPath) && (Path.GetFileName(referenceHintPath)).ToLower().Contains(Constants.LOWERCASE_CORE_ASSEMBLY_NAME))) { result = ResultEnum.ReferenceIsOK; return; } #else // In the Bridge version, we use the "AllowedAssemblies" below to allow the CSHTML5 assemblies. #endif // Check if the reference is among the specially allowed ones: string[] allowedAssembliesArray = allowedAssemblies != null?allowedAssemblies.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries) : new string[] { }; foreach (var allowedAssembly in allowedAssembliesArray) { if (referenceName.ToLower() == allowedAssembly.ToLower()) { result = ResultEnum.ReferenceIsOK; return; } } // Otherwise, check if the reference was compiled with "C#/XAML for HTML5" // and if the user is running the Professional Edition // and if the version of the compiler is OK: if (!string.IsNullOrEmpty(referenceHintPath)) { // Perform reflection on a separate AppDomain so that the types loaded for reflection can be unloaded when done. using (var reflectionOnSeparateAppDomain = new ReflectionOnSeparateAppDomainHandler(typeForwardingAssemblyPath)) { #if BRIDGE // In the Bridge.NET version, we use "Assembly.LoadFile" instead of "Assembly.LoadFrom", so we need to convert a Relative path into an Absolute path: if (!Path.IsPathRooted(referenceHintPath)) { referenceHintPath = Path.Combine(projectDir, referenceHintPath); } // Verify that the file was found: if (!File.Exists(referenceHintPath)) { throw new CompilationExceptionWithOptions("File not found: " + referenceHintPath) { DisplayOnlyTheMessageInTheOutputNothingElse = true } } ; // In the Bridge.NET version, we need to preload the CSHTML5 assemblies so that it can find types such as "XmlnsDefinitionAttribute" or "CompilerVersionNumberAttribute": HashSet <string> referencesPathsHasSet = (referencesPaths != null) ? new HashSet <string>(referencesPaths.Split(';')) : new HashSet <string>(); referencesPathsHasSet.RemoveWhere(s => !s.ToLower().EndsWith(".dll") || s.Contains("DotNetBrowser") || s.ToLower().EndsWith(@"\bridge.dll")); foreach (string referencedAssembly in AssembliesLoadHelper.EnsureCoreAssemblyIsFirstInList(referencesPathsHasSet)) // Note: we ensure that the Core assembly is loaded first so that types such as "XmlnsDefinitionAttribute" are known when loading the other assemblies. { reflectionOnSeparateAppDomain.LoadAssembly(referencedAssembly, loadReferencedAssembliesToo: false, isBridgeBasedVersion: isBridgeBasedVersion, isCoreAssembly: false, nameOfAssembliesThatDoNotContainUserCode: nameOfAssembliesThatDoNotContainUserCode, skipReadingAttributesFromAssemblies: false); } #endif string assemblySimpleName = reflectionOnSeparateAppDomain.LoadAssembly(referenceHintPath, loadReferencedAssembliesToo: false, isBridgeBasedVersion: isBridgeBasedVersion, isCoreAssembly: false, nameOfAssembliesThatDoNotContainUserCode: nameOfAssembliesThatDoNotContainUserCode, skipReadingAttributesFromAssemblies: false); //----------------------------------------------------------------------------- // Check if the reference was compiled with "C#/XAML for HTML5" by reading the "C#/XAML for HTML5" compiler version attributes: //----------------------------------------------------------------------------- string compilerVersionNumber = reflectionOnSeparateAppDomain.GetCSharpXamlForHtml5CompilerVersionNumberOrNull(assemblySimpleName); string compilerVersionFriendlyName = reflectionOnSeparateAppDomain.GetCSharpXamlForHtml5CompilerVersionFriendlyNameOrNull(assemblySimpleName); // If at least one of those attributes exists, it means that the assembly was compiled with C#/XAML fot HTML5: bool wasCompiledWithCSharpXamlForHtml5 = (compilerVersionNumber != null || compilerVersionFriendlyName != null); if (wasCompiledWithCSharpXamlForHtml5) { // The reference is OK, it was compiled with "C#/XAML for HTML5". //---------------------------------------------------------------------- // Now check if the "minimum compiler version" (if any) required by the DLL is compatible with the current version: //---------------------------------------------------------------------- string minimumRequiredCompilerVersionNumberIfAny = reflectionOnSeparateAppDomain.GetCSharpXamlForHtml5MinimumRequiredCompilerVersionNumberOrNull(assemblySimpleName); minimumRequiredCompilerVersionFriendlyNameIfAny = reflectionOnSeparateAppDomain.GetCSharpXamlForHtml5MinimumRequiredCompilerVersionFriendlyNameOrNull(assemblySimpleName); if (minimumRequiredCompilerVersionNumberIfAny == null || compilerVersionNumber == null || (new Version(minimumRequiredCompilerVersionNumberIfAny) <= new Version(compilerVersionNumber))) { // The reference is OK, the version of the "C#/XAML for HTML5" compiler is compatible. #if REQUIRE_PRO_EDITION_FOR_REFERENCING_ASSEMBLIES //------------------------------------------------------------------------- // Now check if the user is running the Professional Edition, which is required for referencing non-default DLLs: //------------------------------------------------------------------------- if (ActivationHelpers.IsFeatureEnabled(Constants.ENTERPRISE_EDITION_FEATURE_ID, flags)) { // It's OK to proceed, the Enterprise Edition is being used. // Everything is OK: result = ResultEnum.ReferenceIsOK; return; } else if (ActivationHelpers.IsFeatureEnabled(Constants.SL_MIGRATION_EDITION_FEATURE_ID, flags)) { // It's OK to proceed, the SL Migration Edition is being used. //todo: once (if it happens) sl migration and enterprise editions will be different, add a test like for the professional edition. // Everything is OK: result = ResultEnum.ReferenceIsOK; return; } else if (ActivationHelpers.IsFeatureEnabled(Constants.PROFESSIONAL_EDITION_FEATURE_ID, flags)) { // It's OK to proceed, the Professional Edition is being used. //todo: actually test what the references tries to use to make sure it limits to the professional edition // Everything is OK: result = ResultEnum.ReferenceIsOK; return; } else { // Display the activation app and, if we are not in trial mode, stop the compilation and raise the compilation error: result = ResultEnum.ReferenceRequiresToUpgradeToTheProEdition; return; } #else // Everything is OK: result = ResultEnum.ReferenceIsOK; return; #endif } else { // A new version of the compiler is required: result = ResultEnum.ReferenceRequiresNewerVersionOfTheCompiler; if (minimumRequiredCompilerVersionFriendlyNameIfAny == null) { minimumRequiredCompilerVersionFriendlyNameIfAny = "Build " + minimumRequiredCompilerVersionNumberIfAny; } return; } } else { // Otherwise, fail: result = ResultEnum.ReferenceIsNotCompatible; return; } } } else { // Otherwise, fail: result = ResultEnum.ReferenceIsNotCompatible; return; } }