2013-05-21 38 views
10

的JavaScript的表示我有我的码数[Flags]枚举我想呈现给JavaScript没有复制粘贴&。 SignalR似乎正在通过将URL映射到返回由反射生成的JavaScript存根的Action来为Hub代理做类似的事情。由于代码是在运行时生成的,它似乎不可能包含在Bundles中。生成枚举

作为替代,我实现了一个T4模板来生成在设计时js文件:

<#@ template debug="false" hostspecific="true" language="C#" #> 
<#@ assembly name="System.Core" #> 
<#@ assembly name="EnvDte" #> 
<#@ import namespace="EnvDTE" #> 
<#@ import namespace="System.Linq" #> 
<#@ import namespace="System.Text" #> 
<#@ import namespace="System.Collections.Generic" #> 
<#@ output extension=".js" #> 
Enums = { 
<# 
    var visualStudio = (Host as IServiceProvider).GetService(typeof(EnvDTE.DTE)) 
         as EnvDTE.DTE; 
    var project = visualStudio.Solution.FindProjectItem(this.Host.TemplateFile) 
             .ContainingProject as EnvDTE.Project; 

    foreach(EnvDTE.ProjectItem item in GetProjectItemsRecursively(project.ProjectItems)) 
    { 
     if (item.FileCodeModel == null) continue; 
     foreach(EnvDTE.CodeElement elem in item.FileCodeModel.CodeElements) 
     { 
      if (elem.Kind == EnvDTE.vsCMElement.vsCMElementNamespace) 
      { 
       foreach (CodeElement innerElement in elem.Children) 
       { 
        if (innerElement.Kind == vsCMElement.vsCMElementEnum) 
        { 
         CodeEnum enu = (CodeEnum)innerElement; 
#> <#= enu.Name #>: { 
<# 
     Dictionary<string, string> values = new Dictionary<string, string>(); 
     foreach (CodeElement child in enu.Members) 
     { 
      CodeVariable value = child as CodeVariable; 

      if (value != null) { 
       string init = value.InitExpression as string; 
       int unused; 
       if (!int.TryParse(init, out unused)) 
       { 
        foreach (KeyValuePair<string, string> entry in values) { 
         init = init.Replace(entry.Key, entry.Value); 
        } 
        init = "(" + init + ")"; 
       } 
       values.Add(value.Name, init); 
       WriteLine("\t\t" + value.Name + ": " + init + ","); 
      } 
     } 
#> 
    }, 
<# 
        } 
       } 
      } 
     } 
    } 
#> 
}; 
<#+ 
    public List<EnvDTE.ProjectItem> GetProjectItemsRecursively(EnvDTE.ProjectItems items) 
    { 
     var ret = new List<EnvDTE.ProjectItem>(); 
     if (items == null) return ret; 
     foreach(EnvDTE.ProjectItem item in items) 
     { 
     ret.Add(item); 
     ret.AddRange(GetProjectItemsRecursively(item.ProjectItems)); 
     } 
     return ret; 
    } 
#> 

但是这种感觉与EnvDTE脆弱。特别是处理枚举的逻辑如:

[Flags] 
public enum Access 
{ 
    None = 0, 
    Read = 1, 
    Write = 2, 

    ReadWrite = Read | Write 
} 

与复合值是一个脏字符串替换。上面的T4模板将生成:

Enums = { 
    Access: { 
     None: 0, 
     Read: 1, 
     Write: 2, 
     ReadWrite: (1 | 2), 
    }, 
}; 

有一个更清洁的方式来实现这一目标?理想情况下,某种设计时反射来生成js文件,因此可用于捆绑。

回答

0

我喜欢使用自定义属性,并在我的应用程序的控制作用。在开发过程中,我添加一个枚举值并点击“运行”。我浏览到我的控制器操作(仅在调试期间可用的链接)。控制器抓取所有实现自定义[GenerateJavascriptEnum]属性的枚举,并且看到一个带有所有好JavaScript的弹出浏览器窗口。我复制/粘贴并刷新浏览器以获取客户端上的更改。这是非常舒适,最小的大惊小怪。

+0

我认为甚至比基于T4的方法我在这个问题meantioned糟糕的是,因为你不仅要围绕复制和粘贴的东西,但要访问一个神奇的URL在浏览器,然后重新编译(!)复制和粘贴后,T4只需要右键单击 - >运行自定义工具 – mensi

+0

不需要重新编译。只需浏览器刷新。没有神奇的URL,这是调试时可见的链接。这实际上工作得很好,并且已经得到了我工作过的几个团队的好评。 T4模板代码往往相当深奥,脆弱,难以维护。我已经使用了这两种方法,并发现自定义属性解决方案效率更高。 –

1

我认为你可以使用捆绑变换来完成这个...

http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification

您可以定义一个包并附加IBundleTransform类插值源文件的内容。您应该能够使用反射将JavaScript写入输出流。

如果你想要做一个哈克的方式,这将是很容易做到的。您可以为它提供一个空文件并对您的课程进行硬编码以使用反射来编写您想要的JavaScript。

现在,如果您想要以不需要修改IBundleTransform类的方式进行设计,以便将其他枚举添加到您的javascript输出中,则需要将一些额外工作放入真实结构中。例如,假设您在一个名为Enums.cs的文件中包含所有枚举,可以将该文件添加到您的包的Include列表中,并且可以动态解析它以获取枚举声明,然后使用反射按名称查找它们以便输出每个都在生成的JavaScript文件中。