2011-01-10 6 views
5

私はローカライズと国際化が必要なWebアプリケーションを開発中です。依存性注入フレームワークを使用してこれを行うことができたことが私には分かりました。DIフレームワークを使用したローカリゼーション - 良いアイデアですか?

interface ILocalResources { 
    public string OkString { get; } 
    public string CancelString { get; } 
    public string WrongPasswordString { get; } 
    ... 
} 

と、このインタフェースの実装で、私がサポートする必要がある各言語のための1つを作成しますのは、私は(この例ではC#を使用してそれが本当に重要ではありません)インターフェースILocalResourcesを宣言しましょう。次に、DIフレームワークをセットアップして、静的にまたは動的に(たとえば、要求するブラウザーの優先言語に基づいて)適切な実装をインスタンス化します。

私はDIフレームワークをこの種のものに使用すべきではありませんか?とにかくWebアプリケーションでDIフレームワークを使用しているのであれば、国際化にも同様に使用することができますか?

答えて

2

(ASP.Netに組み込まれているような)既存のリソースフレームワークを使用できず、独自のリソースフレームワークを構築する必要がある場合は、ローカライズされたリソースを提供するサービスを公開する必要があると見なします。

DIフレームワークは、サービスのインスタンス化を処理するために使用されます。ローカリゼーションフレームワークは、ローカリゼーションを提供するサービスを公開します。そのサービスがフレームワークによって提供されるべきではないのはなぜですか?

DIを目的として使用していないのは、「私はCRMアプリケーションを構築していますが、DIは顧客関係管理用に構築されていないためDIを使用できません。

はい、既に他のアプリケーションでDIを使用している場合は、ローカリゼーションを処理するサービスにIMOを使用しないことは間違いです。

2

「リソース」を更新すると、リソースを含むアセンブリを再コンパイルする必要があるという唯一の欠点があります。また、プロジェクトによっては、値自体ではなく、何らかのResourceServiceを解決するためのDIフレームワークのみを使用することをお勧めします。

6

依存関係注入を行うためにDIフレームワークが構築されており、ローカリゼーションはあなたのサービスの1つにすぎないので、ではなく、というDIフレームワークIMOを使用する必要はありません。おそらく、提供されたILocalResourcesインターフェイスについて議論する必要があります。私はコンパイル時間をサポートするのが好都合ですが、付属のインターフェイスが役立つかどうかは分かりません。そのインターフェイスはおそらくシステム内で最も変更の多いタイプになるからです。そしてそのインタフェースでは、それを実装する型/型があります。おそらく、あなたは別のデザインで行ってください。

ほとんどのローカリゼーションフレームワーク/プロバイダ/ファクトリ(または何でも)を見ると、それらはすべて文字列ベースです。このため、次のデザインについて考えてみてください。

public interface ILocalResources 
{ 
    string GetStringResource(string key); 
    string GetStringResource(string key, CultureInfo culture); 
} 

これにより、インターフェイスを変更せずに、キーとカルチャを基になるメッセージデータストアに追加することができます。もちろん、鍵は決して​​変えてはいけないということは、おそらく地獄だろうからです。キーは「勝ったので、このアプローチは、両方の長所を取る

public sealed class SqlLocalResources : LocalResources 
{ 
    protected override string GetStringResource(string key, 
     CultureInfo culture) 
    { 
     using (var db = new LocalResourcesContext()) 
     { 
      return (
       from resource in db.StringResources 
       where resource.Culture == culture.Name 
       where resource.Key == key 
       select resource.Value).FirstOrDefault(); 
     } 
    } 
} 

別のアプローチは、抽象基本型である可能性があり

public abstract class LocalResources 
{ 
    public string OkMessage { get { return this.GetString("OK"); } } 
    public string CancelMessage { get { return this.GetString("Cancel"); } } 
    ... 

    protected abstract string GetStringResource(string key, 
     CultureInfo culture); 

    private string GetString(string key) 
    { 
     Culture culture = CultureInfo.CurrentCulture; 

     string resource = GetStringResource(key, culture); 

     // When the resource is not found, fall back to the neutral culture. 
     while (resource == null && culture != CultureInfo.InvariantCulture) 
     { 
      culture = culture.Parent; 
      resource = this.GetStringResource(key, culture); 
     } 

     if (resource == null) throw new KeyNotFoundException(key); 

     return resource; 
    } 
} 

そして、このタイプの実装は、このようになります。アプリケーション全体に分散され、新しいプロパティを追加するだけで、1つの場所で行う必要があります。

container.RegisterSingleton<LocalResources>(new SqlLocalResources()); 

そしてLocalResourcesタイプは、すべての作業を行い、正確に1つの抽象メソッドを持っているので、要求しないようにするキャッシュを追加するデコレータを作成することは簡単です:あなたのfavorite DIライブラリを使用すると、あなたはこのような実装を登録することができます次のように、デコレータを適用することができます

public sealed class CachedLocalResources : LocalResources 
{ 
    private readonly Dictionary<CultureInfo, Dictionary<string, string>> cache = 
     new Dictionary<CultureInfo, Dictionary<string, string>>(); 
    private readonly LocalResources decoratee; 

    public CachedLocalResources(LocalResources decoratee) { this.decoratee = decoratee; } 

    protected override string GetStringResource(string key, CultureInfo culture) { 
     lock (this.cache) { 
      string res; 
      var cultureCache = this.GetCultureCache(culture); 
      if (!cultureCache.TryGetValue(key, out res)) { 
       cultureCache[key] = res= this.decoratee.GetStringResource(key, culture); 
      }     
      return res; 
     } 
    } 

    private Dictionary<string, string> GetCultureCache(CultureInfo culture) { 
     Dictionary<string, string> cultureCache; 
     if (!this.cache.TryGetValue(culture, out cultureCache)) { 
      this.cache[culture] = cultureCache = new Dictionary<string, string>(); 
     } 
     return cultureCache; 
    } 
} 

:データベースから同じデータ

container.RegisterSingleton<LocalResources>(
    new CachedLocalResources(new SqlLocalResources())); 

しないでくださいこのデコレータは文字列リソースを無期限にキャッシュするため、メモリリークの原因となる可能性があります。そのため、文字列をWeakReferenceインスタンスにラップするか、何らかの有効期限があります。しかし、既存の実装を変更することなくキャッシングを適用できるというアイデアです。

こちらがお役に立てば幸いです。

+0

また、 'ILocalResources'インタフェース用の拡張メソッドを実装することもできますが、その欠点はプロパティの代わりにメソッドがあることです。しかし、それはおそらくそれほど悪くはありません。 – Steven

関連する問題