Utilizzare le risorse nell'attributo display in MVC

Scritto da  Alessandro Mostarda il giovedì 22 marzo 2012  •  Linguaggio: C#   • Livello: 100


Di default, ad oggi, dobbiamo settare 2 parametri: il tipo di risorsa ed una stringa che contiene il nome della proprietà della risorsa stessa.

Ma, utilizzando il seguente apprrocio è possibile utilizzare la risorsa specificando un solo parametro e soprattutto senza l'uso di alcuna stringa.
In tal modo avremo anche il vantaggio che il compilatore ci avvertirà di eventuali voci di risorsa rinominate e/o eliminate.

L'approccio si compone 1 file T4 ed un attributo custom che eredita da DisplayAttribute.

Il file T4 è il seguente:

<#@ template debug="true" hostspecific="true" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="EnvDTE80" #>
<#@ assembly name="VSLangProj" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="EnvDTE80" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#
   DTE dte = null;
    var serviceProvider = Host as IServiceProvider;
    if (serviceProvider != null) {
        dte = serviceProvider.GetService(typeof(SDTE)) as DTE;
    }
 
   var project = dte.Solution.FindProjectItem(Host.TemplateFile).ContainingProject;
 
   try
   {
      string rootNamespace =  project.Properties.Item("RootNamespace").Value.ToString();
      var resources = GetResources(project.ProjectItems, "");
  
      foreach(var currentNamespace in resources.Select(s=> s.Namespace).Distinct())
      {
         var namespaceToPrint = rootNamespace + ((string.IsNullOrWhiteSpace(currentNamespace) ? "" : "." + currentNamespace));
         WriteLine(string.Format("namespace {0}", namespaceToPrint));
         WriteLine("{");
         foreach(var currentClass in resources.Where(w => w.Namespace == currentNamespace).Select(s => s.ClassName).Distinct())
         {
            WriteLine(string.Format("\tpublic static class {0}Const", currentClass));
            WriteLine("\t{");
 
            foreach(var currentElement in resources.Where(w => w.Namespace == currentNamespace && w.ClassName == currentClass))
            {
               WriteLine(string.Format("\t\tpublic const string {0} = \"{1}\";", currentElement.Key, namespaceToPrint + "." +currentClass + "|" + currentElement.Key));
            }
            WriteLine("\t}");
         }
         WriteLine("}");
      }
 
   }
   catch(Exception ex)
   {
      Error(ex.ToString());
   }
#>
 
<#+
 
List<ResourceEntry> GetResources(ProjectItems items, string path)
{
   var ret = new List<ResourceEntry>();
   foreach(ProjectItem item in items)
   {
      if(Path.GetExtension(item.Name) == ".resx" && !Regex.IsMatch(item.Name, @".*\.[a-zA-z]{2}(-[a-zA-z]{2})?\.resx"))
      {
         var filePath = (string)item.Properties.Item("FullPath").Value;
         var xml = new XmlDocument();
         xml.Load(filePath);
         var entries = xml.DocumentElement.SelectNodes("//data");
 
         foreach (XmlElement entryElement in entries)
         {
           
            var entry = new ResourceEntry();
            if (path.Length > 0)
            {
               entry.Namespace = path.Substring(1);
            }
            entry.ClassName = item.Name.Replace(".resx", "");
            entry.Key = entryElement.Attributes["name"].Value;
            ret.Add(entry);
         }
      }
 
      if(item.Kind == "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}")
      {
         ret.AddRange(GetResources(item.ProjectItems, path + "." + item.Name));
      }
   }
   return ret;
}
 
public class ResourceEntry
{
   public string Namespace { get; set; }
   public string ClassName { get; set; }
   public string Key { get; set; }
}
 
#>

 

 Mentre l'attributo display è il seguente:

public class InheritedDisplayAttribute :
        DisplayNameAttribute
{
    private string _localizedName;
    private Dictionary<string, string> _cachedValues;
    public InheritedDisplayAttribute(string localizedName)
    {
        _localizedName = localizedName;
        _cachedValues = new Dictionary<string, string>();
    }
 
    public override string DisplayName
    {
        get
        {
            var cultureCode = Thread.CurrentThread.CurrentUICulture.ToString();
            if (!_cachedValues.ContainsKey(cultureCode))
            {
                _cachedValues.Add(cultureCode, this.ExtractValue());
            }
            return _cachedValues[cultureCode];
        }
    }
    private string ExtractValue()
    {
        var resourceType = Type.GetType(_localizedName.Split('|').First());
        var propertyName = _localizedName.Split('|').Last();
        return resourceType.GetProperty(propertyName).GetValue(null, null).ToString();
    }
}

 

Il tutto ci consente di utilizzare l'attributo in tale modo:

 
[InheritedDisplay(NomeRisorsaConst.VoceRisorsa)]
 

 

 P.S. Il suffisso Const l'ho fissato io nel File T4, ma possiamo cambiarlo a nostro piacimento.


Tags: MVC

 
x