2013-05-21 12 views
10

Ho alcune enumerazioni [Flags] nel mio codice che vorrei esporre su JavaScript senza copiare & incollando. SignalR sembra fare qualcosa di simile per i suoi proxy Hub mappando un URL a un'azione che restituisce gli stub JavaScript generati dalla riflessione. Poiché il codice viene generato in fase di runtime, non sembra possibile essere incluso nei pacchetti.Genera JavaScript Rappresentazione di Enum

In alternativa, ho implementato un modello T4 per generare un file js in fase di progettazione:

<#@ 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; 
    } 
#> 

Tuttavia questo si sente fragile, con EnvDTE. Soprattutto la logica per gestire enum come:

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

    ReadWrite = Read | Write 
} 

con valori compositi è un trucco sporco con sostituzioni di stringa. Il modello T4 sopra genererà:

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

C'è un modo più pulito per raggiungere questo obiettivo? Idealmente una sorta di riflessione in fase di progettazione per generare il file js in modo che sia disponibile per il raggruppamento.

risposta

0

Mi piace utilizzare attributi personalizzati e un'azione controller nella mia app. Durante lo sviluppo, aggiungo un valore enum e premo 'Esegui'. Accedo all'azione del mio controller (un collegamento disponibile solo durante il debug). Il controller esegue la scansione di tutte le mie enumerazioni che implementano l'attributo personalizzato [GenerateJavascriptEnum] e voilà, vedo una finestra del browser popup con tutto il bel javascript. Copia/incolla e aggiorno il browser per ottenere le modifiche sul client. È stato molto confortevole con il minimo sforzo.

+0

Considererei che, ancor peggio dell'approccio basato su T4, intendevo nella domanda, dal momento che non solo devi copiare e incollare materiale, ma devi visitare un URL magico nel browser e poi ricompilare (!) Dopo copia e incolla , dove T4 ha solo bisogno di rightclick-> esegui lo strumento personalizzato – mensi

+0

Non ricompilare. Basta un aggiornamento del browser. Nessun URL magico, un link visibile durante il debug. Questo ha funzionato davvero bene ed è stato ben accolto da alcune squadre su cui ho lavorato. Il codice template T4 tende ad essere piuttosto esoterico, fragile e difficile da mantenere. Ho utilizzato entrambi gli approcci e ho trovato che la soluzione degli attributi personalizzati è molto più efficiente. –

1

Penso che si possa utilizzare Bundle Transforms per raggiungere questo obiettivo ...

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

È possibile definire un fascio e allegare una classe IBundleTransform che interpola il contenuto dei file di origine. Dovresti essere in grado di utilizzare la riflessione per scrivere il codice JavaScript nel flusso di output.

Se si volesse farlo in modo hacky sarebbe abbastanza facile da fare. Potresti semplicemente inserire un file vuoto e codificare la classe in modo che utilizzi il reflection per scrivere il codice JavaScript che desideri.

Ora, se si desidera progettarlo in modo che non sia necessario modificare la classe IBundleTransform per aggiungere enumerazioni aggiuntive all'output di javascript, è necessario aggiungere lavoro in una struttura reale . Ad esempio, supponiamo di avere tutte le tue enumerazioni in un file chiamato Enums.cs, potresti aggiungere quel file all'elenco Includi del tuo pacchetto e potresti analizzarlo dinamicamente per le dichiarazioni enum e quindi usare reflection per trovarle per nome in modo da generare ognuno nel file JavaScript risultante.

Problemi correlati