2016-08-05 24 views
2

Ich versuche, mehrere Sprachen in einer ASP.NET Webforms (.NET 4.5, C#) Anwendung von mir zu behandeln.Automatisch mehrsprachige Eigenschaften in einer .NET-Klasse behandeln

Grundsätzlich haben einige meiner Entitäten in meiner SQL Server 2012-Datenbank Eigenschaften wie Name oder Description, die in drei Sprachen vorhanden sind - Deutsch, Französisch, Italienisch.

Diese werden als Spalten (deutsch), Name_Fr (französisch) und Name_It (italienisch) gespeichert.

Wenn ich meine .NET-Objekte aus der Datenbank erstellen, bekomme ich natürlich auch diese drei Eigenschaften in meiner Entitätsklasse. Aber für die Darstellung auf dem Bildschirm, zum Beispiel in einem Raster, wäre es schön, wenn ich irgendwie "magisch" immer die "richtige" Sprache zeigen könnte. Dies sollte auf der Thread.Current.CurrentUICulture.TwoLetterISOLanguageName (die de, fr oder it zurückgibt, abhängig von den Spracheinstellungen des Browsers) basieren.

Also hatte ich gehofft, irgendwie in der Lage zu sein, z.B. ein .NET-Attribut, das mir so etwas zu tun erlauben würde:

Base "Module" Entity - erzeugt aus bestehenden SQL Server-Datenbank:

public partial class Module 
{ 
    public string ModuleCode { get; set; } 

    public string Name_De { get; set; } 
    public string Name_Fr { get; set; } 
    public string Name_It { get; set; } 

    ... // other properties 
} 

Teilauszug in einer separaten Datei

public partial class Module 
{ 
    [Multilingual] 
    public string Name { get; set; } 
} 

Die Grundidee ist: Ich kann auf die Module.Name Eigenschaft zugreifen, und abhängig von der aktuellen Einstellung von CurrentUICulture, würde entweder der Wert Name_De, Name_Fr oder Name_It geholt werden, wh de Ich greife auf den Getter der Name Eigenschaft zu.

Kann so etwas in C# gemacht werden? Ich habe mir viele benutzerdefinierte Attribut-Implementierungen angeschaut, aber nichts schien jemals so etwas zu tun ...

Antwort

2

Angenommen, Sie verwenden zwei separate Entitäten (eine generiert von Ihren SQL-Entitäten und eine "Business Entity", die nur enthält eine Name Eigenschaft), sind Sie offen für etwas wie AutoMapper?

Wenn dies der Fall ist, können Sie die Auflösungsfunktion anpassen, um die Entität abhängig von der aktuellen Threadkultur zuzuordnen.

switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant()) 
    { 
     case "DE": 
      return dto.Name_De; 
     case "FR": 
      return dto.Name_Fr; 
     // ... 
     default : 
      return String.Empty; 
    } 

die für Ihr Szenario funktionieren würde.

Wenn dies eine Lösung, die für Sie arbeiten könnte, ich denke, diese Frage ist ganz in der Nähe zu dem, was Sie suchen: Automapper Mapping for Localization Resolver in a Multi-Language Website

Wenn Sie das benutzerdefinierte Attribut Weg gehen tun, werden Sie zu tun haben mit Reflection Stuff und String Parsing fürchte ich. AFAIK, gibt es keine eingebaute Möglichkeit, dies mit den von .NET bereitgestellten Lokalisierungsfunktionen zu tun. AutoMapper wird das vor dir verstecken.

Das Problem mit benutzerdefinierten Attributen in diesem Fall ist, dass Sie immer noch versuchen, auf die Name Eigenschaft zuzugreifen. Sie versuchen, das Standardverhalten der Eigenschaft zu "beschatten", indem Sie auf andere Eigenschaften zugreifen.Wenn ich es richtig wollen Sie das Multilingual benutzerdefinierte Attribut verstehen Ihr Eigentum verwandeln sich in:

public String Name 
{ 
    get 
    { switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant()) 
     { 
      case "DE": 
       return dto.Name_De; 
      case "FR": 
       return dto.Name_Fr; 
      // ... 
      default : 
       return String.Empty; 
     } 
    } 
} 

Wenn das stimmt, dann werden Sie nicht in der Lage sein, dass mit Attributen leicht zu tun, einfach weil das Attribut nie bewusst sein von die Existenz der Eigenschaft.

+0

Danke - sicher könnte ich das tun - aber dies für mehrere Klassen tun, und bis zu 3 Gruppen von Eigenschaften für jede Klasse scheint übermäßig langweilig. Und ja - ich habe darüber nachgedacht, Reflektion in diesem Attribut zu verwenden - in dem Wissen, dass es an die Eigenschaft 'Name' angehängt ist, könnte es dann nach den Eigenschaften' Name_De' und so weiter suchen und den "korrekten" Wert zurückgeben. Aber ich habe keine geeignete Basisklasse für 'Attribut' gefunden, die es mir irgendwie ermöglichen würde, darüber informiert zu werden, wann der Getter dieser Eigenschaft aufgerufen wird ... –

+0

Eigentlich sind das zwei getrennte Dateien - aber beide sind' public partielle Klasse Modul, so dass der C# -Compiler diese am Ende zu einer einzigen Einheit verschmelzen wird. –

+1

Ja, es ist sicherlich mühsam. Benutzerdefinierte Attribute sind jedoch Metadaten über Ihrer Eigenschaft, so dass Sie 'Objekt.Name' nicht ausführen können und Ihren benutzerdefinierten Attributcode aufrufen müssen. Ich werde versuchen, eine andere Möglichkeit, dies ohne Autoadapter zu tun denken –

1

Andere Option, die noch nicht ganz ist, was Sie suchen:

void Main() 
{ 
    Module mod = new Module(); 

    mod.Name_De = "name"; 
    mod.Name_Fr = "nom"; 

    // This is the unfortunate nasty bit. I address the property using its name 
    // in a String which is just bad. I don't think there is a way 
    // you will be able to address the ".Name" property directly and have 
    // it return the localized value through your custom attribute though 
    String localizedValue = mod.GetLocalizedProperty("Name"); 
} 


[AttributeUsage(AttributeTargets.Property)] 
public sealed class MultilingualAttribute : Attribute 
{ 
    public MultilingualAttribute() 
    { 

    } 
} 

public static class ModuleExtensions 
{ 
    public static String GetLocalizedProperty(this Module module, String propName) 
    { 
     var type = typeof(Module); 
     var propInfo = type.GetProperty(propName); 

     // Make sure the prop really is "Multilingual" 
     if(Attribute.IsDefined(propInfo, typeof(MultilingualAttribute))) 
     { 
      String localizedPropName = propInfo.Name; 
      switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant()) 
      { 
       case "DE": 
        localizedPropName += "_De"; 
        return type.GetProperty(localizedPropName).GetValue(module, null).ToString(); 
       case "FR": 
        localizedPropName += "_Fr"; 
        return type.GetProperty(localizedPropName).GetValue(module, null).ToString(); 
      } 
     } 

     return String.Empty; 
    } 
} 

public class Module 
{ 
    public String Name_De {get; set;} 
    public String Name_Fr {get; set;} 

    [Multilingual] 
    public String Name {get; set;} 

    public Module() 
    { 

    } 
} 

Ich weiß nicht, von einer leistungsfähigeren Weise damit benutzerdefinierte Attribute verwendet für das, was Sie leider suchen. Ehrlich gesagt, ich denke nicht, dass dies eine gute Lösung ist, nur veröffentlicht, weil ich versucht habe zu sehen, was ich mit benutzerdefinierten Attributen tun könnte. Es gibt keinen wirklichen Sinn darin, diesen Code über eine "normale" Eigenschaft zu verwenden, die dasselbe deutlicher (ohne Attribute) tun würde. Wie Sie in Ihrer ursprünglichen Frage sagen, ist Ihr Ziel, den Aufruf der Eigenschaft Name abzufangen, und das erreicht es nicht.

+0

Danke - ja, das ist nur über das, was ich bisher erreicht habe - es funktioniert, und es ist einfacher als mühsamen Code für jede einzelne Eigenschaft zu schreiben. Es scheint also, ASP.NET Webforms hat keine Möglichkeit, Aktionen mit Attributen zu behandeln (wie das 'HandleError' Attribut in ASP.NET MVC tun kann) - richtig? Vielen Dank für Ihre Eingaben! –

+0

Korrigieren. ActionFilter in MVC sind eigentlich irreführend, weil sie wie Attribute aussehen, die Code ausführen (was Sie hier erreichen wollen). Das ist nicht so. ActionFilter funktionieren, weil die MVC-Engine Ereignisse auslöst, die nach den Attributen suchen und Code abhängig von ihrer Anwesenheit ausführen (oder nicht). –