1

私はMEFを初めて使用し、理解するのに苦労しています。複数のユーザー ストアを動的にサポートする ASP.NET MVC アプリケーションを作成したいと考えています。これにはMEFを使用できると思いました。次の契約を定義しました。

public interface IUserProvider
{
    List<ConfigurationOption> SupportedConfigurationKeys { get; }

    void Start(List<ConfigurationOption> configuration);

    List<UserInfo> GetUsers(UserInfo userInfo);

    UserInfo GetUser(string id);

    UserInfo Save(UserInfo userInfo);

    bool Delete(UserInfo userInfo);

    List<UserProperty> SupportedUserProperties { get; }
}

これを2回実装しました。カタログの作成とそのような構成

[ImportMany(typeof(IUserProvider))]
public IEnumerable<Lazy<IUserProvider, IDictionary<string, object>>> UserProviders { get; set; }
ApplicationCatalog userProviderCatalog = new ApplicationCatalog();
CompositionContainer container new CompositionContainer(userProviderCatalog);
container.ComposeParts(this);

次のようにインスタンスを作成できます。

UserProviders.Where(x => x.Metadata.ContainsKey("SystemName") && x.Metadata["SystemName"].ToString() == "ActiveDirectory").FirstOrDefault();

作成後、プロバイダーを構成して使用します。ただし、リクエストごとにこれらの手順を繰り返したくはありません。そこで疑問が生じます。

カタログ コンテナとその利用可能なすべてのアプリケーションをどのように作成しますか? 私が見つけることができるのは、参照がコントローラーファクトリーによって保持されているコントローラーの例だけですが、今回は関係ありません。別のユース ケースは、さまざまなファイル タイプを操作するためのコンテンツ プラグインです。私もすべてのリクエストに対してそれらを作成したくありません。application_start でこれを行い、それらを維持したいと思います。静的クラスについて考えましたが、それを container.compose と組み合わせるにはどうすればよいですか?

4

1 に答える 1

0

私も MEF を学んでいます。あなたの質問に興味をそそられ、いくつかのサンプル コードをいじりました。私はコンソールアプリとDllプロジェクトを次のように作成しました:

DLL プロジェクト:

namespace ClassLibrary1
{
    [Export(typeof(IPlugIn))]
    [ExportMetadata("Name", "TestPlugIn")]
    public class PlugIn : IPlugIn
    {
        private string _myStringVal;

        public string GetStringVal()
        {
            return _myStringVal;
        }

        public void SetStringVal(string val)
        {
            _myStringVal = val;
        }
    }
}

コンソール アプリ:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var holder1 = new PlugInHolder();
            var plugInInstance1 = holder1.PlugIns.FirstOrDefault().Value;
            plugInInstance1.SetStringVal("blarg");

            var holder2 = new PlugInHolder();
            var plugInInstance2 = holder2.PlugIns.FirstOrDefault().Value;
            var stringVal = plugInInstance2.GetStringVal();
        }
    }

    public class PlugInHolder
    {
        [ImportMany(RequiredCreationPolicy = CreationPolicy.Shared)]
        public IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> PlugIns;

        private static CompositionContainer _container;

        private void ComposeMe()
        {
            if (_container == null)
            {
                var catalog = new AggregateCatalog();
                catalog.Catalogs.Add(new DirectoryCatalog(System.AppDomain.CurrentDomain.BaseDirectory));
                _container = new CompositionContainer(catalog);
            }

            _container.ComposeParts(this);
        }

        public PlugInHolder()
        {
            ComposeMe();
        }
    }

    public interface IPlugIn
    {
        string GetStringVal();
        void SetStringVal(string val);
    }

    public interface IPlugInMetadata
    {
        string Name { get; }
    }
}

これを実行すると、両方の「ホルダー」オブジェクトが同じコンテナーを使用して PlugIn の同じインスタンスを保持することになり、CreationPolicy が Shared に設定されます。クラス。これは、理論的には、あるホルダー クラスで PlugIn を「セットアップ」し、別のホルダー クラスで再度使用できることを意味します (ご覧のとおり、メンバーシップ データベース接続をセットアップするための代役として、役立たずの文字列ゲッター/セッターを使用しています。あなたがやりたいことは何でも)。

別の投稿 ( Thread safety and the MEF CompositionContainer ) で、コンテナーがスレッドセーフではないことを読んだので、静的catalogとインスタンスごとの CompositionContainer を使用してこのソリューションを試しましたが、「ホルダー」間の PlugIn のインスタンスが別々になりました。 "クラスのインスタンス。同じカタログを使用しているにもかかわらず、コンテナがまったく接続されないため、これは当然のことだと思います。

ただし、ある種のロック メカニズムを使用してスレッドセーフにした静的な CompositionContainer を使用して、コントローラーの基本クラスを設計できるように思えます。このコンテナーは、共有作成ポリシーを介してメンバーシップ サービスの同じインスタンスを持つ個々のコントローラーを構成するために使用できます。

もちろん、これが MEF アーキテクチャの 1 つまたは複数の原則に違反しているかどうかはわかりません。そのため、気軽に訂正してください。

于 2013-02-12T14:52:30.283 に答える