2016-10-20 5 views
1

Ich muss meine Übersetzungen in der Datenbank behalten, damit Benutzer sie hinzufügen, löschen und ändern können. Ich behalte alle meine Übersetzungen in einer Tabelle mit zusammengesetztem Primärschlüssel (Variablenname, Kultur), wobei Variablenname nur ein Name von etwas Text ist, der mehrere Übersetzungen haben kann, und sie entsprechen der Kultur, die eine Zeichenkette ist, wie "en-US" . So habe ich zum Beispiel eine Variable "submitLogin", die ich auf dem Login-Button anzeige. In meiner Datenbank gibt es drei Sprachen: Englisch, Deutsch und Polnisch. Das bedeutet, dass ich für diesen bestimmten Text drei Zeilen in meiner Tabelle verwalte: ("submitLogin", "en-US", "englische Übersetzung), (" submitLogin "," de-DE "," deutsche Übersetzung ") und (" submitLogin “, "pl-PL", "Polnisch Übersetzung")MVC - Validierungsattribute mit Fehlermeldungen aus der Datenbank

bisher meine Anwendung wurde auf einer Klasse Resources.cs basiert, die alle Übersetzungsvariablen aus der Datenbank enthält, zum Beispiel:.

public static string buttonContinueShopping { 
    get { 
     return (string) resourceProvider.GetResource("buttonContinueShopping", CultureInfo.CurrentUICulture.Name); 
    } 
} 

In Ansichten Ich verwende diese statischen Eigenschaften, um meine Übersetzungen wie folgt zu erhalten:

Ich kann einen dynamischen Typ erstellen, der wird genau die gleiche Art und Weise in den Ansichten verhalten (mit Ausnahme nicht statische Eigenschaften hat, aber ich kann ein Objekt in jeder Ansicht erstellen, das ist nicht das Problem - obwohl es nicht schön scheint):

public class Resource : DynamicObject 
{ 
    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     ResourceManager rsManager = new ResourceManager(); 
     result = rsManager.GetString(binder.Name); 
     return true; 
    } 
} 

Aber ich habe ein Problem mit die Attribute meiner Modelle. Bisher habe ich sie wie folgt verwendet:

[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "errorRequired")] 
[DataType(DataType.EmailAddress, ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "errorWrongDataType")] 
[EmailAddress] 
[Display(Name = "nameEmail", ResourceType = typeof(Resources.Resources))] 
public string Email { get; set; } 

Jetzt muss ich meine Resources.cs loszuwerden, weil sie erzeugt werden, nachdem ein Konsolenprogramm ausgeführt wird, die alle eindeutigen Werte von Übersetzungsvariablen aus der Datenbank liest und erstellt Eigenschaften (Wie der, den ich oben gezeigt habe). Ich kann diese Datei nicht mehr haben, da Benutzer neue Übersetzungsvariablen in Runtime hinzufügen können.

Wie ändere ich so wenig wie möglich und mache diese Attribute lesen Fehlermeldungen, Anzeigenamen usw. aus der Datenbank?

Ich habe drei Ideen, aber ich weiß nicht, wie sie zu tun bekommen:

  1. Verwenden Sie benutzerdefinierte Attribute - Ich habe versucht, es für erforderliches Attribut, aber es fügt nur keine clientseitige Validierung noch irgendwelche Fehlermeldungen in HTML.

  2. Verwenden Sie benutzerdefinierte DataAnnotationsModelMetadataProvider - Ich habe dies versucht, aber es funktioniert nicht nach dem Neuladen der Seite - auf der ersten Seite laden alle Fehler vorhanden sind (besonders dies: 'Feld Email erforderlich.'), Aber nach dem erneuten Laden der Seite erforderlich Fehlermeldung ändert sich in 'Feld ist erforderlich'. Das ist, was ich tue:

    public class CustomDataAnnotationsProvider: DataAnnotationsModelMetadataProvider 
    { 
    private ResourceManager resourceManager = new ResourceManager(); 
    
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) 
    { 
        string key = string.Empty; 
        string localizedValue = string.Empty; 
    
    foreach (var attr in attributes) 
    { 
        if (attr != null) 
        { 
          if (attr is DisplayAttribute) 
          { 
           key = ((DisplayAttribute)attr).Name; 
           if (!string.IsNullOrEmpty(key) && !key.Contains(" ")) 
           { 
            localizedValue = resourceManager.GetString(key); 
            ((DisplayAttribute)attr).Name = localizedValue; 
           } 
          } 
          else if (attr is ValidationAttribute || attr is RequiredAttribute) 
          { 
           key = ((ValidationAttribute)attr).ErrorMessage; 
           if (!string.IsNullOrEmpty(key) && !key.Contains(" ")) 
           { 
            localizedValue = resourceManager.GetString(key); 
            ((ValidationAttribute)attr).ErrorMessage = localizedValue; 
           } 
          } 
        } 
    } 
    return base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); 
    

    }

Global.asax:

ModelMetadataProviders.Current = new CustomDataAnnotationsProvider(); 

Modell:

[Required(ErrorMessage = "errorRequired")] 
[EmailAddress(ErrorMessage = "errorWrongDataType")] 
[Display(Name = "nameEmail")] 
public string Email { get; set; } 
  1. Verwenden Sie Reflektion (wäre das Beste aber ich habe keine Ahnung, wie es geht). Lassen Sie uns sagen, dass ich meine Attribute so belasse und alle Eigenschaften aus meiner Resources.cs entferne. Was macht RequiredAttribute?Es nimmt den gegebenen Typ und bekommt die Eigenschaft gegeben, also z.B. Es wird versucht, dies zu tun:

    Resources.Resources.nameEmail.get 
    

Die Frage ist: ist es möglich, einige Überlegungen, Code zu schreiben, die sich um die Wünsche "für nicht vorhandene Eigenschaften (wie nameEmail) nehmen würde?

Antwort

2

Ich denke, die Antwort ist, einen Standardwert in Ihrem Resources.cs file zu liefern. Während Benutzer Übersetzungen dynamisch bereitstellen können, kann Ihre Anwendung sie nur verwenden, wenn sie über den Schlüssel verfügen, den Sie im Modell verwendet haben.

Wenn Sie Ihre bestehende Verfahren ändern, um einen Standardwert zu akzeptieren, dann können Sie diese zurück, wenn es keine Datenbankwert vorhanden ist:

public static string buttonContinueShopping { 
    get { 
     return GetResource("buttonContinueShopping", 
      CultureInfo.CurrentUICulture.Name, "Continue Shopping"); 
    } 
} 


public string GetResource(string key, string cultureName, string defaultText) 
{ 
    // Get db value 
    if (dbValue != null) 
     return dbValue; 

    return defaultText; 
} 

Sie die Tasten steuern, indem sie manuell in Resources.cs modifizieren, die IMO das ist der beste Ort für sie, da sie im selben Projekt gepflegt werden, in dem sie verwendet werden. Sie können (und ich habe diese Technik verwendet) dann eine Companion-Konsole-App schreiben, die Reflektion verwenden kann, um die SQL zu generieren, die benötigt wird, um die Datenbank zu aktualisieren. direkt von meinem Projekt

Dieses Beispiel genommen, aber Sie können die Idee

static void Main(string[] args) 
    { 
     var resources = typeof(Resources).GetProperties(); 

     StreamWriter streamWriter = new StreamWriter(new FileStream(@"..\..\Resources.sql", FileMode.Create)); 

     streamWriter.WriteLine(createTable); 


     for (int i = 0; i < resources.Count(); i++) 
     { 
      var line = GetValues(resources[i].Name, resources[i].GetValue(null, null) as string); 

      if (i == 0) 
      { 
       streamWriter.Write(insertValues + line); 
      } 
      else if (i == resources.Count() - 1) 
      { 
       streamWriter.Write(",\r\n" + line + "\r\nGO"); 
      } 
      else if (i % 4 == 0) 
      { 
       streamWriter.Write("\r\nGO\r\n\r\n" + insertValues + line); 
      }     
      else 
      { 
       streamWriter.Write(",\r\n" + line); 
      }     
     } 

     streamWriter.Flush(); 
     streamWriter.Close(); 


    } 

    private static string createTable = "IF NOT EXISTS (SELECT * FROM sys.objects where Object_Id = OBJECT_ID(tempdb..#Resources))" 
     + "\r\n\tCREATE TABLE Resources (StaticTextKey VARCHAR(100), DefaultText VARCHAR(MAX))\r\nGO\r\n"; 

    private static string insertValues = "INSERT INTO #Resources (StaticTextKey, DefaultText) VALUES\r\n"; 

    private static string GetValues(string staticTextKey, string defaultText) 
    { 
     return string.Format("('{0}', '{1}')", staticTextKey, defaultText.Replace("'", "''")); 
    } 
bekommen
Verwandte Themen