この記事は機械翻訳されたものです。

予測: クラウド

クラウドと MEF を分離する (機械翻訳)

Joseph Fultz
クリス Mabry

コード サンプルのダウンロード

Joseph Fultz同僚と私はプロジェクトの Microsoft 拡張機能フレームワーク (MEF) を活用し、過去数ヵ月間に取り組んでいます。 この記事では、我々 は、MEF、もう少し管理し、柔軟なクラウドの配置を使用して方法で見ていきます。 MEF — などのフレームワークなど統一 — 開発者は依存関係の解決、オブジェクトの作成、インスタンス化の管理からの解放ソフトウェア ファブリックです。 今、もう一度自分のファクトリ メソッドを書くかもしれませんまたは、コンス トラクターまたは必要な初期化メソッドがそのような作業の大部分の内部依存オブジェクトの作成は、MEF などのフレームワークのおかげでもはや必要ありません。

MEF で当社の展開と共に、StorageClient API を使用して、展開し、リサイクルまたは Web の役割を再配置せずに利用可能な新しいクラスを作ることができます。 また、更新のバージョンの種類を展開する、クラウドにおけるの再展開せずにし単に代わりに、アプリケーションをリサイクルすることができます。 我々 は、ここでは、団結を使用して同様の構造を次の MEF を使用している間ウィンザー城、StructureMap またはその他の類似のコンテナーのいずれかの同じ結果構文とタイプ登録セマンティクスをされている主な違いを純べきであることに注意してください。

デザインと展開

諺行く。つは少し詳細を取得するには、少し置くことがあります。 この場合は、特定建設基準といくつか追加の作業、展開の周りが必要です。 まず、依存関係の注入 (DI) または構成コンテナーを使用するを使用している場合は、チャンス実装とインターフェイスのコード内での分離を維持することにかなりに熱望しているです。 私たちは、ここでの目標から逸脱していない-私たちのすべての具象クラス実装継承はインターフェイス型トレース バックがあります。 それは、すべてのクラスはインターフェイスから直接継承されますがクラス インターフェイス “ 仮想 “ コンクリートのようなパターンに従う抽象化レイヤーに戻ることは一般的に意味しません。

図 1 だけでなく興味のプライマリ クラスをしないことを示すようなチェーンが実際には、必要なプロパティの 1 つも抽象化されています。 すべての抽象化の簡単部品を交換してください (この例では、インターフェイス) で目的のコントラクトをエクスポート、新しいライブラリの形式で機能を追加したりできます。 組成を超えては、抽象クラスのデザインについて、マルティネ中のいい副作用はより良いモックのインターフェイス経由でテストできることです。

Class Diagram
図 1 クラス図

要件の難しい部分は、アプリケーションの展開モデルの変更です。 輸入品のカタログを構築したいし、輸出で実行時に、それを再度展開することなくが更新するので、我々 コンクリートのクラス外 Web の役割の展開を保持するバイナリを展開するがあります。 少し余分な作業の起動時にアプリケーションを強制します。 図 2 MEFContext という名前は、私たちが作成したをヘルパー クラスに呼び出しとして起動作業、Global.asax で描いています。

Building the Catalog at Startup
図 2 の起動時にカタログを構築

ランタイムの構成

我々 はカタログにストレージ内のファイルからロードされるので、私たちのクラウド ストレージ コンテナーにそれらのファイルを取得する必要があります。 したがって、Windows Azure ストレージにファイルを得る場所展開プロセスの一部になるする必要があります。 これはおそらくほとんどが簡単に行える Windows Azure の PowerShell コマンドレットを使用して (wappowershell.codeplex.com) といくつかのビルド後のステップ。 私たちの目的のために、私たちは、Windows Azure ストレージ ・ エクスプ ローラーを使用してバイナリを手動で移動よ (azurestorageexplorer.codeplex.com)。

共通の診断クラス、顧客エンティティといくつかのルールのライブラリを含むプロジェクトを作成します。 すべてのルールのライブラリから継承し、t に対して規則が適用されるエンティティを表します場所 IBusinessRule <t> の種類のインターフェイスをエクスポートする必要があります。 ルールのクラス宣言のインポート部分はここにあります。

[Export(typeof(IBusinessRule<ICustomer>))]
public class CustomerNameRule : IBusinessRule<ICustomer>
{
  [Import(typeof(IDiagnostics))]
  IDiagnostics _diagnostics;
    ...
}

エクスポートとして我々 の rule オブジェクトを求めるときに MEF が私たちのために注入する診断の依存関係を見ることができます。 何その意志として順番にエクスポートされている目的のインスタンスによって解決契約するを知ることが重要です。 Microsoft .net Framework 4.5 いくつか強化するジェネリック コンテナーの周り現在制約のいくつかのゆるみを許可 MEF をもたらすでしょう。 たとえば、現在できます登録し何か IBusinessRule <ICustomer> などを取得がない何かのように含めルール <t>。 時に、実際のテンプレート型以外の型のすべてのインスタンスをします。 現在、これを実現する最も簡単な方法は合意された規則をプロジェクトまたはソリューションです、文字列のコントラクト名を登録することです。 このサンプルでは、上記のような宣言を動作します。

我々 は、2 つのルール、1 つの電話番号と名前と診断のライブラリは、それぞれが MEF コンテナーを通じて可能があります。 私たちを行う最初のものが Windows Azure ストレージ ライブラリを取得し、それらをローカルにもたらすにはリソース (ローカル ディレクトリ) ので、私たちは DirectoryCatalog にそれらを読み込むことができます。 これを行うには、関数呼び出しのカップルを Global.asax の Application_Start に含めます。

// Store the local directory for later use (directory catalog)
MEFContext.CacheFolderPath = 
  RoleEnvironment.GetLocalResource("ResourceCache").RootPath.ToLower();
MEFContext.InitializeContainer();

ちょうど Web の役割の一部として構成されている、必要なリソースのパスを取得してコンテナーを設定するメソッドを呼び出します。 初期化メソッドは順番に UpdateFromStorage ファイルを取得して、カタログをクリックし、[MEF のコンテナーを作成する BuildContainer を呼び出します。

UpdateFromStorage メソッドは所定のコンテナーを検索し、それらの各ローカル リソース フォルダーにダウンロードして、コンテナー内のファイルを反復します。 このメソッドの最初の部分で示されている図 3

図 3 UpdateFromStorage の最初の半分

// Could also pull from config, etc.
string containerName = CONTAINER_NAME;
// Using development storage account
CloudStorageAccount storageAccount = 
  CloudStorageAccount.DevelopmentStorageAccount;
// Create the blob client and use it to create the container object
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Note that here is where the container name is passed
// in order to get to the files we want
CloudBlobContainer blobContainer = new CloudBlobContainer(
  storageAccount.BlobEndpoint.ToString() + 
  "/" + containerName,
  blobClient);
// Create the options needed to get the blob list
BlobRequestOptions options = new BlobRequestOptions();
options.AccessCondition = AccessCondition.None;
options.BlobListingDetails = BlobListingDetails.All;
options.UseFlatBlobListing = true;
options.Timeout = new TimeSpan(0, 1, 0);

最初の半分に必要なものをフェッチするストレージ クライアントを設定します。 このシナリオでは、我々 に何があるかを求めています。 ここで、ファイル ストレージからはローカル リソースをいるダウンの場合、完全パスを行うと、すべてを得る価値があるかもしれない。 ファイルのよりタールに対応したフェッチについては、オプションをいくつか IfMatch 条件を割り当てることができます。AccessCondition プロパティ。 これはその etags アップロードすると、blob に設定する必要があります。 さらに、MEF コンテナー最終更新時間を保存して、IfModifiedSince の AccessCondition を適用することによって再構築の更新側を最適化できます。

図 4 、2 番目の UpdateFromStorage の半分を示しています。

図 4 2 番目の半分の UpdateFromStorage

// Iterate over the collect
// Grab the files and save them locally
foreach (IListBlobItem item in blobs)
{
  string fileAbsPath = item.Uri.AbsolutePath.ToLower();
  // Just want the file name ...
fileAbsPath = 
    fileAbsPath.Substring(fileAbsPath.LastIndexOf('/') + 1);
  try
  {
    Microsoft.WindowsAzure.StorageClient.CloudPageBlob pageblob =
      new CloudPageBlob(item.Uri.ToString());
    pageblob.DownloadToFile(MEFContext.CacheFolderPath + fileAbsPath, 
      options);
  }
  catch (Exception)
  {
    // Ignore exceptions, if we can't write it's because
    // we've already got the file, move on
    }
}

ストレージ クライアントが準備できたら、私たちは単に、blob アイテムの反復処理し、リソースにダウンロードします。 条件と全体のダウンロードの目的によっては、この操作のローカルのフォルダー構造を複製または条約に基づき、フォルダー構造を構築できます。 名前の衝突を回避するための要件は、フォルダー構造があります。 ちょうど散弾銃方法に行くとすべてのファイル取得して私たち、このサンプルのちょうど 2 つまたは 3 つの Dll を知っているそれらの 1 つの場所で付着します。

これでは、ファイルの場所があるし、だけコンテナーを構築する必要があります。 MEF では、構成コンテナーは 1 つまたは複数のカタログから構築されています。 この場合、これは単に、カタログ ディレクトリにポイントし、使用可能なバイナリをロードする容易ため、DirectoryCatalog を使用するつもりです。 したがって、タイプを登録し、コンテナーを準備するコードは、短い、簡単なです。

// Store the container for later use (resolve type instances)
var catalog = new DirectoryCatalog(CacheFolderPath);
MEFContainer = new CompositionContainer(catalog);
MEFContainer.ComposeParts();

今我々 は、サイトを実行し、私達に示すように、コンテナーで使用できる種類のダンプを見るべき図 5

Initial Exports
図 5 初期の輸出

コンテナー全体をここでは、ダンプありませんけど具体的に IDiagnostics インターフェイスや、すべての輸出型 IBusinessRule <ICustomer> のためではなく求めます。 このように、我々 はそれぞれのビジネス ルールの新しいライブラリが保存容器にアップロードする前にこれらの 1 つがあります。

私たちは NewRules.dll の格納場所に配置した、今それをアプリケーションにロードを取得する必要があります。 理想的には、ファイルのストレージ コンテナーを見ての少しをすることによって、コンテナーの再構築をトリガーしたいと思う。 もう一度、この IfModifiedSince AccessCondition を使用して簡易アンケートを簡単にします。 しかし、我々 更新カタログのテスト アプリケーションをクリックするより手動プロセスをオプトインしています。 図 8 は結果を示しています。

Updated Rules Exports
図 8 輸出規則の更新

私たちだけのカタログを作成し、コンテナーの初期化手順を繰り返してして今は強制する新しいルールのライブラリがあります。 私たち haven't、アプリケーションが再起動または再展開しますが、私たちの環境で実行する新しいコードに注意してください。 我々 コード参照を交換している間に、構成コンテナーを使用しようとすることはできませんだけ端ここでいくつかの同期手法が必要であること、です。

var catalog = new DirectoryCatalog(CacheFolderPath);
CompositionContainer newContainer = 
  new CompositionContainer(catalog);
newContainer.ComposeParts();
lock(MEFContainer)
{
  MEFContainer = newContainer;
}

セカンダリ コンテナーを構築し、参照をちょうど交換する主な理由は、ロック量子を削減し、すぐに使用するコンテナーを返すことです。

コード ベースをさらに進化するには、次のステップ、独自のカスタム カタログの型を実装することです — で示すように、AzureStorageCatalog、 図 9。 残念ながら、継承としていくつかのカプセル化のビットを使用しては、おそらく最善の方法ですので現在のオブジェクト モデルは、適切なインタ フェースまたは定義を簡単に再利用可能な基本を持っていません。 AzureStorageCatalog と同様のクラスを実装するリスト、カスタム カタログのインスタンスを作成し、構成コンテナーに直接使用の簡単なモデルを可能にします。

図 9 AzureStorageCatalog

public class AzureStorageCatalog:ComposablePartCatalog
{
  private string _localCatalogDirectory = default(string);
  private DirectoryCatalog _directoryCatalog = 
    default(DirectoryCatalog);
  AzureStorageCatalog(string StorageSetting, string ContainerName)
    :base()
  {
    // Pull the files to the local directory
    _localCatalogDirectory = 
      GetStorageCatalog(StorageSetting, ContainerName);
    // Load the exports using an encapsulated DirectoryCatalog
    _directoryCatalog = new DirectoryCatalog(_localCatalogDirectory);
  }
  // Return encapsulated parts
  public override IQueryable<ComposablePartDefinition> Parts
  {
    get { return _directoryCatalog.Parts; }
  }
  private string GetStorageCatalog(string StorageSetting, 
    string ContainerName)
  {  }
}

既存の機能の更新

当社の展開に新しい機能を追加が非常に簡単だったが、我々 は既存の機能やライブラリの更新を同じ良いニュースを持っていません。 プロセスは、完全な再展開よりもより良いですが、私たちのファイル ストレージと関連の Web ロールに、ローカル リソース フォルダーを更新する必要が移動するが、まだかなりかかわっています。 我々 はアンロードして、コンテナーに格納されている型の定義を更新するには、AppDomain を再読み込みする必要がありますのでただし、私達ロール リサイクルすることもよ。 コンポ分節コンテナーとの種類をセカンダリの AppDomain にロードし、そこからロードしようとしても、型を要求している AppDomain それ以前読み込まれたメタデータからロードされます。 周りを見ることができる唯一の方法は、セカンダリの AppDomain にエンティティを送信し、プライマリの AppDomain にエクスポートされた型を使用するのではなく、いくつかのカスタム マーシャ リングを追加することです。 そのパターンは私たちに問題があるようです。 自体で二重の AppDomain は、問題のあるようです。 したがってより簡単なソリューションは、新しいバイナリが利用した役割をリサイクルします。

Windows Azure 更新ドメインに関する良いニュースです。 私 2012 年 2 月のコラムは、Windows Azure 展開「ドメイン」を見て (msdn.microsoft.com/magazine/hh781019)、更新ドメインを歩いてそれぞれインスタンスを再起動します。 正の側では、サイトが完全な再展開の必要はありませんが起きています。 ただし、更新中に 2 つの異なる動作可能性のある経験でした。 これは許容可能なリスクは、完全展開をした場合は、ローリングの更新中に真のだろうためにです。

この展開内に発生するを構成することができますが、調整の問題であります。 インスタンスのリーダーを選出するまたはいくつかの投票システムがするか、これを行うにインスタンスの再起動調整、ことが必要でしょう。 いくつかの人工知能、Web ロールに作成する代わりに、タスクより簡単に監視プロセスと以前参照 Windows Azure コマンドレットによって処理されるを感じる。

私たちがここで強調表示機能の狭いビットを超えて MEF などのフレームワークを使用する多くの理由があります。 強調したかった Windows Azure の固有の機能の組み合わせは組成・ ディ/反転と制御型フレームワークを使用して、常にポップアップするよう最後の分の変更に容易に対応できる動的なクラウド アプリケーションを作成できること、です。

Joseph Fultz 、ヒューレット ・ パッカード株式会社グッドエイチピードットコム グローバル IT グループの一部としての作業でするソフトウェア アーキテクトです。 以前、彼は Microsoft、その一流企業と ISV のお客様の建築とデザインのソリューションを定義するためのソフトウェアアーキテクトだった。

Chris Mabry ヒューレット ・ パッカード株式会社でのリード開発者です 経験にリッチな UI を提供するためのチームをリードの現在焦点をサービスが有効なクライアント フレームワークに基づきます。

この記事のレビュー、技術スタッフのおかげで:クリス ・ ブルックス