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

我实施了两次。创建目录并像这样组成

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

当我运行它时,两个“持有者”对象最终都持有同一个插件实例,因为使用同一个容器来制作两者,并且 CreationPolicy 设置为共享,这意味着它在编写时总是使用单个实例班级。这意味着我理论上可以在一个持有者类中“设置”插件并在另一个类中再次使用它(如您所见,我使用笨拙的字符串 getter/setter 作为建立会员数据库连接或无论你想做什么)。

我在另一篇文章(线程安全和 MEF CompositionContainer)中读到容器不是线程安全的,所以我尝试了使用静态目录和每个实例 CompositionContainer 的解决方案,但这导致“持有人”之间的插件的单独实例" 类实例。我认为这是意料之中的,因为尽管使用了相同的目录,但容器不会以任何方式连接。

不过,在我看来,您可以使用静态 CompositionContainer 构建控制器基类,您已经使用某种类型的锁定机制使线程安全。然后,此容器可用于通过共享创建策略将单个控制器与成员服务的相同实例组合在一起。

当然,我不知道这是否违反了 MEF 架构的一个或多个原则,所以人们应该随时纠正我。

于 2013-02-12T14:52:30.283 回答