【问题标题】:Application scoped parts in ASP.NET MVC with MEF带有 MEF 的 ASP.NET MVC 中的应用程序范围部分
【发布时间】:2013-01-27 19:38:38
【问题描述】:

我是 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 结合起来?

【问题讨论】:

    标签: asp.net-mvc mef


    【解决方案1】:

    我也在学习 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 作为建立会员数据库连接或不管你想做什么)。

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

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

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

    【讨论】:

    • 您的观察很有趣,但对我来说没有解决方案。问题是我使用的是非共享创建策略。我这样做是因为我需要具有多个配置/设置的单个插件的多个实例。就像在控制多个不同类型的锁的应用程序中一样,但一些(门)锁可能属于相同类型但位置不同。现在我只使用一个在应用程序启动时初始化的单例类。现在似乎可以工作。
    猜你喜欢
    • 2013-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-30
    • 2015-05-26
    • 2016-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多