1

Тема: MEF створення елементів в різних потоках.

Є наступна модель: ASP.NET MVC 4 проект, в контроллерах використовуються самописні class Service, котрі виконують операції (вибірка/додавання/редагування). За створення цих об'єктів відповідаеє MEF. В дуже спрощенному вигляді виникає ось така проблема: при одночасному створені двох об'єктів виникає виключення: Выполняется составление другого пакета в этом ComposablePartExportProvider. Одновременное составление нескольких пакетов не поддерживается.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
 
namespace ConsoleApplication1
{
    class Program
    {
        static CompositionContainer container;
 
        static void Main(string[] args)
        {
            container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            var tasks = new TaskFactory();          
            var t1 = tasks.StartNew(Run);
            var t2 = tasks.StartNew(Run);
            t1.Wait();
            t2.Wait();
            Console.WriteLine("complite...");
            Console.ReadKey();
        }
 
        private static void Run()
        {
            var service  = new Service();
            container.ComposeParts(service);
            service.PrintData();
            Thread.Sleep(10000);
            service.PrintData();
        }
    }
 
    public class Service
    {
        [Import(typeof(Repository))]
        private Repository Repository { get; set; }
 
        public void PrintData()
        {
        }
    }
 
    [Export(typeof(Repository))]
    public class Repository
    {
    }
}

2

Re: MEF створення елементів в різних потоках.

Одновременное составление нескольких пакетов не поддерживается.

Вам чітко написали що така операція не підтримується, доречі ви одночасно хочете виконати абсолютно одинакові дії, по моєму ви занадто спростили ваш приклад. Доречі чому mef, в вебі якось більше використовують ninject, unity і йому подібні ioc.

3

Re: MEF створення елементів в різних потоках.

truesupport написав:

ви одночасно хочете виконати абсолютно одинакові дії, по моєму ви занадто спростили ваш приклад.

Падає саме на етапі компоновки, котра в вебі викликається в ControllerFactory та FilterProvider (можу їх і показати, але проблема пов'язана не з ними, і лише погіршить сприйнятя моделі проблеми). Тобто якщо два користувача одночасно надішлють запит, то є ймовірність що потрапимо на таку ситуацію.

truesupport написав:

Вам чітко написали.

Читати я вмію, мене більш цікавить як це обійти. Ставити лок не бажано.

truesupport написав:

чому mef.

До цього працював лише зі spring.net, якось не сподобалось, вирішив спробувати щось нове. Прочитавши базові приклади, здалося досить зручним.

4

Re: MEF створення елементів в різних потоках.

витяг з документації https://msdn.microsoft.com/en-us/librar … 10%29.aspx

A CompositionContainer object that can be accessed from multiple threads must be constructed with the isThreadSafe parameter set to true, using the CompositionContainer(ComposablePartCatalog, Boolean, ExportProvider[]) constructor. Performance will be slightly slower when isThreadSafe is true, so we recommend that you set this parameter to false in single-threaded scenarios. The default is false.

Переробив приклад на:

class Program
    {
        static CompositionContainer container;
        static object locker = new object();

        static void Main(string[] args)
        {
            //var catalog = new DirectoryCatalog("\\", "ConsoleApplication1.exe");
            var catalog = new System.ComponentModel.Composition.Hosting.AssemblyCatalog(Assembly.GetExecutingAssembly());
            container = new CompositionContainer(catalog, true);
            var tasks = new TaskFactory();
            var t1 = tasks.StartNew(Run);
            var t2 = tasks.StartNew(Run);
            t1.Wait();
            t2.Wait();
            Console.WriteLine("complite...");
            Console.ReadKey();
        }

        private static void Run()
        {
            var service = new Service();
            container.ComposeParts(service);
            service.PrintData();
        }
    }

    public class Service
    {
        [Import(typeof(Repository))]
        private Repository Repository { get; set; }

        public void PrintData()
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }
    }

    [Export(typeof(Repository))]
    public class Repository
    {
    }

Все одно падає з тією же помилкою =(