Exemplo n.º 1
0
        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);
            }
        }
Exemplo n.º 2
0
        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;
            }
        }