Exemple #1
0
        private static void AddIComponentRazorViewFactoryImplementation(ClassDeclarationIRNode classNode)
        {
            // The Activator.CreateInstance feature that I added to the DNA runtime is very basic and doesn't
            // actually invoke the default constructor of the type being created. It just allocates memory for
            // the instance and returns it, without having run any constructor. This could be confusing if you
            // put constructor logic (such as field initializers) in your Razor page, given that we instantiate
            // it using Activator.CreateInstance.
            // As a workaround (without actually adding constructor support to Activator.CreateInstance, which
            // would be nontrivial), the Razor views privately implement an interface IComponentRazorViewFactory
            // that can return new instances of their own type. We can then just call this with normal .NET code.
            // This means we allocate memory for two instances of the view even though we're only using one,
            // but it's not going to matter much as the first instance will just be released to GC immediately.
            if (classNode.Interfaces == null)
            {
                classNode.Interfaces = new List <string>();
            }
            classNode.Interfaces.Add(typeof(IRazorComponentFactory).FullName);
            var methodStatement = new CSharpStatementIRNode {
                Parent = classNode, Source = null
            };

            classNode.Children.Add(methodStatement);
            methodStatement.Children.Add(new RazorIRToken
            {
                Kind    = RazorIRToken.TokenKind.CSharp,
                Parent  = classNode,
                Content = $@"
                    {typeof(RazorComponent).FullName} {typeof(IRazorComponentFactory).FullName}.{nameof(IRazorComponentFactory.Instantiate)}()
                    {{
                        return new {classNode.Name}();
                    }}"
            });
        }
Exemple #2
0
        public static string CompileToStream(bool enableLogging, string rootDir, string[] referenceAssemblies, string outputAssemblyName, Stream outputStream)
        {
            if (!rootDir.EndsWith(Path.DirectorySeparatorChar.ToString()))
            {
                rootDir += Path.DirectorySeparatorChar.ToString();
            }

            EnableLogging = enableLogging;
            Log("Creating Razor engine...");
            var engine = RazorEngine.Create(builder =>
            {
                var defaultCSharpLoweringPhase = builder.Phases.OfType <IRazorCSharpLoweringPhase>().Single();
                builder.Phases.Remove(defaultCSharpLoweringPhase);
                builder.Phases.Add(new VirtualDomCSharpLoweringPhase(defaultCSharpLoweringPhase));
                builder.SetNamespace("Views");
                builder.SetBaseType(typeof(RazorComponent).FullName);
                builder.ConfigureClass((codeDoc, classNode) =>
                {
                    classNode.Name = RazorComponent.GetViewClassName(rootDir, codeDoc.Source.FileName);
                    if (!string.IsNullOrEmpty((string)codeDoc.Items["DetectedBaseClass"]))
                    {
                        classNode.BaseType = (string)codeDoc.Items["DetectedBaseClass"];
                    }

                    AddIComponentRazorViewFactoryImplementation(classNode);

                    var layoutProperty = new CSharpStatementIRNode
                    {
                        Parent = classNode,
                        Source = null
                    };
                    classNode.Children.Add(layoutProperty);

                    layoutProperty.Children.Add(new RazorIRToken
                    {
                        Kind    = RazorIRToken.TokenKind.CSharp,
                        Parent  = classNode,
                        Content = $"protected override string Layout {{ get {{ return \"{ codeDoc.Items["DetectedLayout"] ?? string.Empty }\"; }} }}"
                    });
                });
            });

            Log("Compiling Razor files to C#...");
            var filenames   = GetFilesToCompile(rootDir);
            var syntaxTrees = GetSyntaxTrees(engine, rootDir, filenames);

            Log("Compiling C#...");
            var modelAssemblyRefs = referenceAssemblies
                                    .Select(a => MetadataReference.CreateFromFile(Path.GetFullPath(a)))
                                    .Cast <MetadataReference>()
                                    .ToList();

            CompileToFile(syntaxTrees, modelAssemblyRefs, outputAssemblyName, outputStream);
            return($"Compiled {syntaxTrees.Count} view(s) as {outputAssemblyName}");
        }
        protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
        {
            var parserOptions = irDocument.Options;

            var designTime = parserOptions.DesignTime;
            var walker     = new DirectiveWalker();

            walker.VisitDocument(irDocument);

            var classNode = walker.ClassNode;

            foreach (var node in walker.FunctionsDirectiveNodes)
            {
                node.Parent.Children.Remove(node);

                foreach (var child in node.Children.Except(node.Tokens))
                {
                    child.Parent = classNode;
                    classNode.Children.Add(child);
                }
            }

            foreach (var node in walker.InheritsDirectiveNodes.Reverse())
            {
                node.Parent.Children.Remove(node);

                var token = node.Tokens.FirstOrDefault();
                if (token != null)
                {
                    classNode.BaseType = token.Content;
                    break;
                }
            }

            var sectionsMethodNode = new CSharpStatementIRNode();

            RazorIRBuilder.Create(sectionsMethodNode)
            .Add(new RazorIRToken()
            {
                Kind    = RazorIRToken.TokenKind.CSharp,
                Content = "public override void DefineSections() {"
            });
            classNode.Children.Add(sectionsMethodNode);

            foreach (var node in walker.SectionDirectiveNodes)
            {
                //var sectionIndex = node.Parent.Children.IndexOf(node);
                node.Parent.Children.Remove(node);

                var lambdaContent = designTime ? "__razor_section_writer" : "builder";
                var sectionName   = node.Tokens.FirstOrDefault()?.Content;
                var defineSectionStartStatement = new CSharpStatementIRNode();
                RazorIRBuilder.Create(defineSectionStartStatement)
                .Add(new RazorIRToken()
                {
                    Kind    = RazorIRToken.TokenKind.CSharp,
                    Content = $"DefineSection(\"{sectionName}\", async ({lambdaContent}) => {{"
                });

                classNode.Children.Add(defineSectionStartStatement);

                foreach (var child in node.Children.Except(node.Tokens))
                {
                    classNode.Children.Add(child);
                }

                var defineSectionEndStatement = new CSharpStatementIRNode();
                RazorIRBuilder.Create(defineSectionEndStatement)
                .Add(new RazorIRToken()
                {
                    Kind    = RazorIRToken.TokenKind.CSharp,
                    Content = "});"
                });

                classNode.Children.Add(defineSectionEndStatement);
            }

            var sectionsMethodNodeEnd = new CSharpStatementIRNode();

            RazorIRBuilder.Create(sectionsMethodNodeEnd)
            .Add(new RazorIRToken()
            {
                Kind    = RazorIRToken.TokenKind.CSharp,
                Content = "}"
            });

            classNode.Children.Add(sectionsMethodNodeEnd);
        }
Exemple #4
0
 public override void VisitCSharpStatement(CSharpStatementIRNode node)
 {
     Context.BasicWriter.WriteCSharpStatement(Context, node);
 }
Exemple #5
0
        private static void AddIComponentRazorViewFactoryImplementation(ClassDeclarationIRNode classNode, RazorCodeDocument codeDoc)
        {
            // The Activator.CreateInstance feature that I added to the DNA runtime is very basic and doesn't
            // actually invoke the default constructor of the type being created. It just allocates memory for
            // the instance and returns it, without having run any constructor. This could be confusing if you
            // put constructor logic (such as field initializers) in your Razor page, given that we instantiate
            // it using Activator.CreateInstance.
            // As a workaround (without actually adding constructor support to Activator.CreateInstance, which
            // would be nontrivial), the Razor views privately implement an interface IComponentRazorViewFactory
            // that can return new instances of their own type. We can then just call this with normal .NET code.
            // This means we allocate memory for two instances of the view even though we're only using one,
            // but it's not going to matter much as the first instance will just be released to GC immediately.
            if (classNode.Interfaces == null)
            {
                classNode.Interfaces = new List <string>();
            }
            classNode.Interfaces.Add(typeof(IRazorComponentFactory).FullName);
            var methodStatement = new CSharpStatementIRNode {
                Parent = classNode, Source = null
            };

            classNode.Children.Add(methodStatement);

            var    model    = codeDoc.Items["DetectedModel"];
            string content  = "";
            string isPage   = "";
            string addItems = "";

            if (model != null)
            {
                content = $@"Model = new {model}();";
            }
            if ((bool)codeDoc.Items["DetectedPage"])
            {
                isPage += "classNode.IsPage = true;";
            }

            if ((codeDoc.Items["DetectedPageMatches"]) != null)
            {
                var list = (List <string>)codeDoc.Items["DetectedPageMatches"];
                addItems += "List<string> list = new List<string>();";
                foreach (var item in list)
                {
                    addItems += $"\r\n list.Add(\"{item}\");";
                }
                addItems += "\r\n Items = list;";
            }
            var razorToken = new RazorIRToken
            {
                Kind    = RazorIRToken.TokenKind.CSharp,
                Parent  = classNode,
                Content = $@"
                    {typeof(RazorComponent).FullName} {typeof(IRazorComponentFactory).FullName}.{nameof(IRazorComponentFactory.Instantiate)}()
                    {{
                        {content} 
                        var classNode = new {classNode.Name}();
                        {isPage}
                        {addItems}
                        return classNode;
                    }}"
            };

            methodStatement.Children.Add(razorToken);
        }