2013-05-21 187 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文件中。