Managed Extensibility Framework

    (Заранее извините за мой русский)

    MEF это новый подход разработанный Майкрософт, который позволяет загружать расширения для вашего приложения очень легко. Он позволяет обнаруживать и составлять части, которые должны быть включены в приложение, и все это во время выполнения. Вы можете расширить поведение аппликации простим добавлением новых плагинов. Managed Extensibility Framework сделает все это за вас.
    «Hello MEF World!»

    Допустим, мы уже имеем действительно простое приложение, и мы хотим, чтоб оно приветствовало нас с "Привет MEF мир!":



        class Program
        {
            static void Main(string[] args)
            {
                var program = new Program();
                program.Run();
            }

            private void Run()
            {
                ProgrammGreeter.SayHello();
            }

            protected IGreeter ProgrammGreeter{ get; set;}
        }


        public interface IGreeter
        {
            void SayHello();
        }

        public class Greeter:IGreeter
        {
            public void SayHello()
            {
                Console.WriteLine(«Hello MEF World!»);
            }
        }
    Основная проблема заключается в имении инстанса в проперте ProgrammGreeter. У нас есть желание, чтоб это бил инстанс класса Greeter. 
    Давайте сделаем это с помощью MEF

    Для этого нужно включить ссылку на System.ComponentModel.Composition.

    Соответственно с MSDN: «MEF является неотъемлемой частью. NET Framework 4 Beta 1, и используется везде, где может NET Framework используется».

    Скорее всего, MEF будет включен в NET Framework 4.0, пока можно скачать его с сайта CodePlex здесь


    После того как мы добавили ссылку можно добавить импорт (Import) и экспорт (Export) атрибуты. 
    Экспорт предназначен для указания на некоторые возможности, которые ми хотим где-то использовать. И импорт выступает за указание зависимостей от каких-либо возможностей. 

    Наш класс Greeter предоставляет некоторые возможности, таким образом, мы добавляем Export:

        [Export(typeof(IGreeter))]
        public class Greeter : IGreeter

    Мы хотим использовать эту возможность в нашем классе Programm, т.е. мы зависим от этой функциональности. Добавляем Import:

            [Import]
            protected IGreeter ProgrammGreeter { get; set; }

    Обычно наши возможности живут в других асемблях. Но также они могут жить и в вызываемой ассембли. В любом случае мы должны указать MEF, как сконфигировать все наши зависимости. 
    Это может быть сделано с помощью метода Compose() которой мы вызовем прежде, чем мы будем использовать наши возможности, как правило такой сетап делается где-то в начале исполнения: 

            private void Run()
            {
                Compose();
                ProgrammGreeter.SayHello();
            }

            private void Compose()
            {
                var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
                var compositionContainer = new CompositionContainer(assemblyCatalog);
                compositionContainer.ComposeParts(this);
            }


    Я запустил мою программу и получил:



    Как работает Managed Extensibility Framework? 

    Я думаю, что вы несколько заинтересовались методом Compose(). Просто прочтите комментарии в коде этого метода, я сделал метод более подробным:

            //We have to guide MEF how to Compose all we need
            private void Compose()
            {
                //Catalog says where to search for capabilities (Where do exports live)
                var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
                //CompositionContainer holds defined dependencies and coordinates creation
                var compositionContainer = new CompositionContainer(assemblyCatalog);

                //CompositionBatch object holds references to all objects that need to be composed
                var compositionBatch = new CompositionBatch();
                //one of such objects is Programm instance (this), it needs to be composed
                compositionBatch.AddPart(this);

                //And finally Container has method called Compose to do actuall Composing
                compositionContainer.Compose(compositionBatch);
            }



    В Managed Extensibility Framework есть примитивы называемее ComposablePart, которые содержат расширения для вашего приложения собрание из каталога (Catalog). Но также он может содержать зависимости, которые также нуждаются в компоновке. 

    Посмотрите на этот график со страницы Managed Extensibility Framework. 



    Более сложный пример 

    В этом примере мы будем иметь приложение, которое анализирует XML-файлы (которые содержит информацию о некоторых разработчиках). После того как мы поставили нашу программу Клиентам, мы хотим, чтобы этот XML поддавался проверке некоторых правил, но они могут отличаться от клиента к клиенту. Для этого разрабатываемо правила в отдельных Dll, которые поставляются различным клиентам. Работаем с правилами как с плагинами. 


    У нас есть две сборки:
    • MEF.DEMO которая определяет ISecurityRule и IDataRule.
    • MEF.Rules имеет имплементацию этих интерфейсов.


    Структура классов как показано на картинке ниже. Я просто не хочу утомлять вас с объяснением логики всех правил. (Если вам нужны сорсы просто дайте мне знать.)



    Наш класс Programm хочет загружать правила из другой сборки, поэтому мы отмечаемо их с помощью Import в MEF.Rules:

            [Import]
            public ISecurityRule SecurityRule { get; set; }

            [ImportMany]
            public IDataRule[] DataRules { get; set; }

            public void Run()
            {
                Console.WriteLine(«Programm run.»);
                Compose();
                Console.WriteLine(«Composition completed.»);

                var document = XDocument.Load(«developer.xml»);
                Console.WriteLine(document.ToString());

                var passesValidation = SecurityRule.PassesValidation(document);
                Console.WriteLine(string.Format(«Rule {0}: {1}», SecurityRule.GetType(), passesValidation));

                foreach (var d in DataRules)
                {
                    var valid = d.IsValid(document);
                    Console.WriteLine(string.Format(«Rule {0}: {1}», d.GetType(), valid));
                }          
            }

    Как вы заметили, мы используем ImportMany, надеюсь что название говорит само за себя. 

    Мы должны изменить наш метод компоновки Compose для того чтоб он искал Export-с в директории где наше приложение расположено, для этого мы используем DirectoryCatalog.

            private void Compose()
            {
                var catalog = new DirectoryCatalog(Environment.CurrentDirectory);
                var container = new CompositionContainer(catalog);
                container.ComposeParts(this);
            }


    После того как я положил эти DLL в одной папке и запустил MEF.DEMO, я получил:



    Целью MEF является беспрепятственно склеить классы, которые импортируют функционал из других частей приложения, а также классы, которые экспортируют этот функционал. Пожалуй вы решите что MEF еще один DI контейнер. Да, он может все те же что и DI контейнеры, но Managed Extensibility Framework в первую очередь сосредоточен на композиции. Также важно, что композиция может быть сделана во время выполнения программы в любой момент времени, когда вам это удобно. Вы можете сделать ре-композицию, когда вы хотите сделать. Вы также можете загружать возможности по требованию (Lazy load) или добавлять метаданные к экспорту. Поиск зависимостей в папке может быть сделано с фильтрацией. Также есть много других возможностей не присущих DI контейнерам.


    Managed Extensibility Framework очень интересный и нужный функционал, что был добавлен в NET 4.0 Framework.


    Sources: Download MEF.DEMO.ZIP — 118.46 KB

    Комментарии 31

      +3
      Под кат?
        +4
        Это мой перевод моей же статьи:
        andriybuday.blogspot.com/2010/01/managed-extensibility-framework.html
          +6
          что не освобождает от ката :)
            +5
            Но позволяет лишний раз кинуть ссылку:)
              +2
              Я не скрываю что это перевод. Но перевод моей же работы.
              Я на Хабре новый. Чем это плохо, что я честный?
                +1
                Ничем, кроме того, что кат надо ставить, чтобы текст не расползался на всю ленту!
                «Кат» (от англ слова «cut» — резать) это поставить один тег после 6ой строчки этой статьи, не более.
                Это превратится в аккуратное «Читать далее -->»
                Надеюсь я понятно объяснился…
                  +1
                  В дополнение, чтоб уж совсем понятно было

                    +9
                    Да, спасибо. Интересно почему на Хабре сих пор это не делается автоматически.
                      +4
                      Sorry, guys.
                      DONE.
              +13
              Мне интересно сколько из тех кто поставили минус прочитали эту статью.
                0
                Надо сократить статью при помощи тега habracut, чтобы она половину главной не занимала.
                  –2
                  убери под хабракат, тебе же говорят. и не будут минусовать
                    –3
                    Вы пробовали читать написанное перед тем как публиковать?
                      +4
                      Да, но русский язык не является моим родным. Извините еще раз.
                        0
                        Хотя бы знайте, что assembly — это сборка, а не «ассембля»…
                    • НЛО прилетело и опубликовало эту надпись здесь
                      • НЛО прилетело и опубликовало эту надпись здесь
                        +4
                        спасибо за статью, вам, которому русский не родной, я считаю удалось хорошо справиться с переводом.

                        у меня две просьбы:
                        первое — вы не могли бы выложить исходные коды из примеров?
                        второе — не могли бы вы перенести топик в блог .NET (сначала нужно подписаться на него, затем в редактировании топика просто задать блог)

                        и еще: если можете, продолжите тему MEF. Я как раз хотел бы поближе с ней познакомиться, да думаю и другим было бы интересно.

                        Спасибо.
                          +6
                          Сделал: Ссылка на исходные коды внизу статьи.
                            +5
                            Я также перенес топик в. NET блог.
                              0
                              Очень хочется понять, как это соотносится с Unity. Вроде как, одному производителю странно делать два инструмента с одинаковым функционалом, так что какая-то разница в назначении должна быть.
                                0
                                Ну еще и Add-In есть. Пишут що намного полегчает разработку.
                                  0
                                  Насколько я помню, addin — это больше механизм подгрузки модулей в рантайме, нежели чем автоматического связывания (dependency injection).
                              +1
                              MEF — это действительно здоровская технология, которая делает разработку проще, а главное, позволяет оформить это в виде красивого кода.

                              Наверняка статья хорошая, но без подсветки кода статья выглядит как огромный кусок сплошного текста.

                              Попробуйте применить хабра-редактор:
                              www.bankinform.ru/HabraEditor/
                                +2
                                Спасибо. Если нужна подсветка то тут с ней: andriybuday.blogspot.com/2010/01/managed-extensibility-framework.html
                                  +1
                                  ооо… да эти статьи не сравнить.
                                  Увидев оригинал, мне сразу захотелось его прочитать.
                                    0
                                    И все же, что мешает сделать подсветку и тут.
                                    0
                                    Очень напоминает часть их фреймворка Prism (Composite WPF), а именно подход Modularity :)
                                      0
                                      Мне больше напоминает Dependency Injection фреймворки.
                                    0
                                    Забавно что всем пох на статью, хотя на самом деле это не просто пара классов к фреймворку, а целая готовая функциональность, которой так не хватало.

                                    Насколько мне известно, библиотека требует жесткой структуры каталогов плагинов. Это так?
                                      0
                                      Да, спутал… Это был Add — Ins, ихняя вторая библиотека

                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                    Самое читаемое