2016-08-05 5 views
2

私は、ASP.NET Webforms(.NET 4.5、C#)アプリケーションで複数の言語を処理しようとしています。.NETクラスの多言語プロパティを自動処理する

基本的に、SQL Server 2012データベースのエンティティの一部は、NameまたはDescriptionのようなプロパティ(ドイツ語、フランス語、イタリア語)があります。

これらは列Name_De(ドイツ語)、Name_Fr(フランス語)、Name_It(イタリア語)として保存されています。

データベースから.NETオブジェクトを作成すると、もちろん、私のエンティティクラスにも3つのプロパティがあります。しかし、例えばグリッドで画面に表示するには、何らかの形で「魔法のように」常に「正しい」言語を表示できるといいでしょう。これは、Thread.Current.CurrentUICulture.TwoLetterISOLanguageName(ブラウザの言語設定に応じて、de,frまたはitを返します)に基づいている必要があります。

私は何とかして、別のファイルに

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

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 
} 

部分拡張子: - 既存のSQL Serverデータベースから生成

ベース「モジュールの」エンティティ:私はこのような何かを行うことができるようになる.NET属性

基本的な考え方は次のとおりです。Module.Nameプロパティにアクセスでき、現在の設定CurrentUICultureに応じて、Name_De,Name_FrまたはName_Itのいずれかの値が取得されます.wh ja Nameプロパティのゲッターにアクセスします。

C#でこれを行うことはできますか?私は多くのカスタム属性の実装を見てきましたが、これまで何もしていないようでした...

答えて

2

2つの別個のエンティティ(SQLエンティティによって生成されたエンティティと1つの "ビジネスエンティティ" Nameプロパティが含まれています)、AutoMapperのようなものを使用していますか?

現在のスレッドカルチャに応じて、解決機能を調整してエンティティをマップすることができます。

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

あなたのシナリオではうまくいくでしょう。

これはあなたのために働く可能性が解決された場合、私はこの質問はあなたが探しているものに非常に近いと思う:Automapper Mapping for Localization Resolver in a Multi-Language Website

カスタム属性ルートを下る行う場合は、あなたが対処する必要があります反射のものと文字列の解析私は恐れています。 AFAIKでは、.NETで提供されているローカライゼーション機能でこれを行う方法はありません。 AutoMapperはそれをあなたから隠します。

この場合のカスタム属性の問題は、まだNameプロパティにアクセスしようとしていることです。他のプロパティにアクセスすることによって、プロパティのデフォルト動作を「シャドー」しようとしています。それが正しいなら、あなたは属性が知っておくことは決してありませんという理由だけで、属性で簡単にそれを行うことができなくなります

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

:私が正しく理解していれば、あなたはMultilingualカスタム属性がにあなたの財産を有効にしますName_Deプロパティの存在。

+0

ありがとう - 確かに私はこれを行うことができます - しかし、いくつかのクラスでこれを行うと、各クラスのプロパティの最大3つのグループはあまりにも退屈なようです。そして、はい - 私はその属性でリフレクションを使用することを考えていました。 'Name'プロパティにアタッチされているので、' Name_De'プロパティなどを探して「正しい」値を返します。しかし、私は 'Attribute'の適切な基底クラスが見つからないので、そのプロパティのゲッタが呼び出されたときに何らかの通知を受けることができます.... –

+0

実際には、これらは2つの別々のファイルですが、どちらも' public C#コンパイラはこれらをまとめて1つのエンティティにまとめます。 –

+1

これは確かに面倒です。カスタムアトリビュートはプロパティの上部にあるメタデータなので、 'Object.Name'を実行することができず、そのカスタムアトリビュートコードを呼び出すことができます。オートマトンなしでこれを行う別の方法を試してみよう –

1

まだあなたが探しているものはかなりではないその他のオプション:

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() 
    { 

    } 
} 

私はあなたが、残念ながら探しているもののためにカスタム属性を使用するように、より強力な方法を知りません。確かに、私はこれが良い解決策だとは思わない、私はカスタム属性で何ができるか見ようとしていたので投稿しただけだ。同じコードを(属性を持たない)より明確な方法で実行する "通常の"プロパティよりも、このコードを使用する上での重要なポイントはありません。あなたの元の質問で言うように、あなたの目標はNameプロパティの呼び出しを傍受し、これはそれを達成しません。

+0

ありがとうございます。これまでのところ私が達成したことです。それはうまくいきます。それぞれのプロパティごとに面倒なコードを書かなくても簡単です。したがって、ASP.NET Webformsには、(ASP.NET MVCの 'HandleError'属性のような)属性を持つアクションを処理する方法がありません - 正しいですか?入力いただきありがとうございます! –

+0

正しい。 MVCのActionFiltersは、実際にコードを実行する属性(これはここで達成しようとしているもの)のように見えるため、誤解を招くようなものです。これはそうではありません。 ActionFiltersは、MVCエンジンが属性を検索し、その存在に応じてコードを実行する(またはしない)イベントをトリガーするため動作します。 –

関連する問題