c# - 如何使用 RazorGenerator 而不是 T4 来生成 C# 文件?

标签 c# envdte razorgenerator

我想使用 http://razorgenerator.codeplex.com/而不是 Visual Studio 的 T4 功能来根据我的解决方案的代码模型自动生成 C# 文件/类。我已经使用带有 T4 的 EnvDTE 成功地做到了这一点,但是,我想使用比 T4 更易于维护和更好支持的东西。

我尝试通过 @* Generator: Template *@ 使用模板生成器,但输出是带有 Execute 函数的 C# 类,该函数将生成模板化的 c#我需要的类(class)。如何将 C# 输出直接放入我的解决方案中?

最佳答案

在您的解决方案中选择您的 cshtml 文件,打开属性 Pane (默认为 F4)并输入“RazorGenerator”(无引号)作为自定义工具。这将在您构建项目时生成一个 C# 源文件。

编辑 - 实际执行生成的类

这比较困难,您可能找不到像 RazorGenerator 这样的预构建自定义工具来为您完成这项工作。我会查看 RazorGenerator 源代码,了解他们如何构建自定义工具/扩展方面。我可能会 fork RazorGenerator 代码并修改它以满足我的需要。

这是我用来从 razor 标记生成类型的方法。以下是您可能会忽略的 MVC 特有的一些细节(例如,添加引用程序集的额外代码,这样编译就不会失败)。

private Type CompileRazorView(string virtualPath, FileInfo file, Assembly partialViewAssembly)
        {
            var config = WebConfigurationManager.OpenWebConfiguration("~/Views/web.config");
            var section = config.GetSectionGroup("system.web.webPages.razor") as RazorWebSectionGroup;
            var host = MvcWebRazorHostFactory.CreateHostFromConfig(section, virtualPath);
            var engine = new RazorTemplateEngine(host);
            using (var stream = file.OpenRead())
            {
                using (var reader = new StreamReader(stream))
                {
                    var result = engine.GenerateCode(reader);
                    string code = null;
                    using (var tw = new StringWriter())
                    {
                        CodeProvider.GenerateCodeFromCompileUnit(result.GeneratedCode, tw, new CodeGeneratorOptions());
                        tw.Flush();
                        code = tw.ToString();
                    }
                    var compilerParameters = new CompilerParameters()
                    {
                        MainClass = host.DefaultClassName,
                        GenerateInMemory = true,
                        IncludeDebugInformation = true,
                    };
                    var thisAssembly = Application.GetType().Assembly;
                    var thisAssemblyName = thisAssembly.GetName();
                    var referencedAssemblies = new List<AssemblyName>();
                    referencedAssemblies.Add(thisAssemblyName);
                    referencedAssemblies.Add(partialViewAssembly.GetName());
                    referencedAssemblies.AddRange(partialViewAssembly.GetReferencedAssemblies());
                    foreach (var applicationReference in thisAssembly.GetReferencedAssemblies())
                    {
                        var assembly = Assembly.Load(applicationReference.FullName);
                        referencedAssemblies.Add(assembly.GetName());
                        referencedAssemblies.AddRange(assembly.GetReferencedAssemblies());
                    }
                    var binPath = Path.GetDirectoryName(thisAssemblyName.CodeBase);
                    var distinctReferences = referencedAssemblies.Distinct((a, b) =>
                        string.Equals(a.FullName, b.FullName, StringComparison.OrdinalIgnoreCase)).ToList();
                    foreach (var reference in distinctReferences)
                    {
                        var referencedAssembly = Assembly.Load(reference.FullName).CodeBase.Substring("file:///".Length);
                        compilerParameters.ReferencedAssemblies.Add(referencedAssembly);
                    }
                    var compilerResults = CodeProvider.CompileAssemblyFromDom(compilerParameters, result.GeneratedCode);
                    if (compilerResults.Errors.HasErrors)
                    {
                        var errorText = new StringBuilder();
                        foreach (var compilerError in compilerResults.Errors)
                        {
                            errorText.AppendLine(compilerError.ToString());
                        }
                        throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
                            "The following errors were detected attempting to compile the partial view {0}: \n{1}",
                            virtualPath, errorText));
                    }
                    var typeName = string.Format(CultureInfo.InvariantCulture, "{0}.{1}",
                        host.DefaultNamespace, host.DefaultClassName);
                    var type = compilerResults.CompiledAssembly.GetType(typeName);
                    return type;

                }
            }
        }

此方法将为您提供一个类型,然后您可以使用反射来到达 Execute 方法,然后您可以调用该方法。诀窍是改变 WriteLiteral 的含义,以便它输出到任意流,如 cs 文件。

关于c# - 如何使用 RazorGenerator 而不是 T4 来生成 C# 文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17199410/

相关文章:

c# - 从 WSDL 文件在 Visual Studio 中创建 Web 服务代理

c# - Visual Studio 生成操作的当前类型 - Microsoft.VisualStudio.Shell.Interop

c# - 在哪里可以找到 System.Web.Helpers、System.Web.WebPages 和 System.Web.Razor?

c# - 理解 Protobuf-net 属性的序列化和反序列化

c# - 将 C# 表达式树保存到文件

c# - 简化空值检查和相等性

Razor 发电机 : how to use view compiled in a library as the partial view for master defined in main mvc project

c# - 如何使用 DTE 从 VS 2015/2017 的错误列表中获取错误代码?或者其他方式可以获得错误代码?

powershell - 使用 Powershell 自动化 Visual Studio 2012,做错了吗?

asp.net - RazorGenerator 未生成正确的命名空间