2013-05-21 10 views
10

コードに[Flags]の列挙型がいくつかあります。&貼り付けなしでJavaScriptに公開したいと思います。 SignalRは、リフレクションによって生成されたJavaScriptスタブを返すActionにURLをマッピングすることで、Hub-Proxiesと同様のことをしているようです。コードは実行時に生成されるため、バンドルに含めることはできないようです。代替案として列挙型のJavaScript表現を生成

は、私が設計時にJSファイルを生成するために、T4テンプレートを実装:

<#@ 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と壊れやすい感じ。特に、以下のような列挙型を扱うロジックは:合成値を持つ列挙型のハックである。上記のT4テンプレートは次のように生成されます:

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

これを達成するためのよりクリーンな方法がありますか?理想的には、jsファイルを生成するためのデザイン時のリフレクションがバンドル可能です。

答えて

0

私は自分のアプリでカスタム属性とコントローラアクションを使用するのが好きです。開発中に、enum値を追加して 'Run'を押します。私は私のコントローラのアクション(デバッグ中にのみ利用可能なリンク)を参照します。コントローラーはカスタム[GenerateJavascriptEnum]属性を実装しているすべての列挙型をクロールし、すべての素敵なjavascriptでポップアップブラウザウィンドウが表示されます。私はコピー/貼り付け、クライアント上の変更を取得するためにブラウザをリフレッシュします。最小限の騒ぎでとても快適でした。

+0

私は、T4ベースのアプローチよりも悪いと思っていました。あなたはコピーして貼り付けるだけでなく、ブラウザで魔法のURLにアクセスしてから、コピー&ペーストした後で再コンパイルしなければなりませんここで、T4にはrightclick->カスタムツールを実行するだけです – mensi

+0

再コンパイルしません。ブラウザの更新だけ。マジックURLはありません。デバッグ時に表示されるリンクです。これは実際には本当にうまくいっていて、私が取り組んできたいくつかのチームが好評を博しています。 T4のテンプレートコードはかなり難解で、壊れやすく、保守が難しい傾向があります。私は両方のアプローチを使用し、カスタム属性ソリューションがはるかに効率的であることを発見しました。 –

1

私はあなたがバンドルを定義し、ソースファイルの内容を補間IBundleTransformクラスを添付することができ

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

...あなたはこれを達成するためにバンドルトランスフォームを使用することができると思います。 JavaScriptを出力ストリームに書き込むには、リフレクションを使用できる必要があります。

あなたがハッキーなやり方でやりたければ、これはかなり簡単です。あなたはそれに空のファイルを与え、クラスをハードコードしてリフレクションを使って必要なJavaScriptを書くことができます。

JavaScript出力に追加の列挙型を追加するためにIBundleTransformクラスを変更する必要がないようにデザインしたい場合は、実際の構造に余分な作業を加える必要があります。たとえば、Enums.csという名前のファイルにすべての列挙型がある場合、そのファイルをバンドルのインクルードリストに追加し、列挙型宣言のために動的に解析してから、リフレクションを使用してそれらを名前で検索して出力することができます結果のJavaScriptファイルにそれぞれ1つずつ追加します。