REPL WebPart для SharePoint

Intro

logoСегодня я расскажу о прототипе первого компонента под ярлычком Sapphire. Это REPL WebPart. Эта веб-часть предназначенная для производства оперативных изменений на серверной стороне SharePoint, так же для удаленного исполнения скриптов и тестирования некоторых кусков кода.

PreBody

Производство данной веб-части было инициированно в довольно таки частых потребностях исполнения серверного кода с достаточной оперативностью, в недоступности средств разработки под рукой.

Здесь есть небольшая презетнация, в которой я постарался отобразить принципы работы Repl WebPart:

В добавок к слайдам расскажу о том, что веб-часть представляет собой классический хостинг Dynamic Languages Runtime языков, пока из которых доступен только Python.

Body

Далее хотелось поговорить о том, как же всё это у меня получилось, итак проект включает в себе несколько основных модулей:

  • Веб-часть и контролы представления
  • Хостинг языков

Далее о них поподробнее

Language Hosting

В связи с тем, что языков, которые я захочу реализовать в данном проекте является неограниченное множество, то конечно же мне необходима абстрактная фабрика для их создания, которая будет скрывать иерархию всех доступных языков и инкапсулировать их под интерфейсом:

  public interface ILanguagesFactory
  {
    ILanguage Create(string name);
  }

  public interface ILanguage
  {
    string Name { get}

    object Execute(string input);

    void SetVar(string name, object value);
    
    object GetVar(string name);
  }

Отлично, далее к нашему проекту присоединяются сборки, необходимые для имплементации скриптовых языков:

Всё готово для того, чтобы реализовать Python, как среду для исполнения кода, отлично, приступим:

  public class PythonLanguage : ILanguage
  {
    private readonly ScriptScope _scope;
    
    public string Name
    {
      get { return «Python»}
    }

    public PythonLanguage()
    {
      _scope = Python.CreateEngine().CreateScope();
    }

    public object Execute(string input)
    {
      ScriptSource source = _scope.Engine.CreateScriptSourceFromString(input);
      return source.Execute(_scope);
    }
  }

Далее немного усложним задачу, в связи с тем, что нам будет необходимо реализовать контекст для работы с SharePoint, выглядеть это должно примерно так:

    [Test]
    private void python_should_assume_sharepoint_variables()
    {
      SPWeb fakeWeb = Isolate.Fake.Instance<SPWeb>();
      Isolate.WhenCalled(() => fakeWeb.Title).WillReturn(«I’m fake web»);
      var python = _factory.Create(«Python»);
      python.SetVar(«__x__»«123»);
      python.SetVar(«__web__», fakeWeb);
      python.Execute(«__x__ = __web__.Title»);
      var x = (string)python.GetVar(«__x__»);
      Assert.AreEqual(x, «I’m fake web»);
    }

Для работы с объектами SharePoint в из IronPython, нам необходимо добавить несколько библиотек:

      _scope.Engine.Runtime.LoadAssembly(typeof(string).Assembly);
      _scope.Engine.Runtime.LoadAssembly(typeof(Uri).Assembly);
      _scope.Engine.Runtime.LoadAssembly(typeof(SPList).Assembly); 

Это будет основой нашей работы с динамическими языками

WebPart + WebControls

Создадим проект с помощью SPVisualDev, добавим в него feature, внутри которой создадим веб-часть Repl WebPart, всё остальные действия стандартные, однако есть небольшой нюанс, нам нужен будет объект, с помощью которого можно будет выводить строковые значения после исполнения. Я решил создать для этих целей объект с классическим названием Console, его реализация предельна проста:

  public class Console
  {
    private readonly StringBuilder _messageBuilder = new StringBuilder();

    public void Write(object message)
    {
      _messageBuilder.Append(message);
    }

    public void WriteLine(object message)
    {
      _messageBuilder.AppendLine(message.ToString());
    }

    public string Message
    {
      get
      {
        return _messageBuilder.ToString();
      }
    }
  }

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

EndBody

Все исходники проекта доступны на github: http://github.com/butaji/Sapphire

Так же предварительную версию Sapphire.Environment (решение поставляется в WSP) можно слить на CodePlex: http://sapphire.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34895


Языки предметной области Domain-Specific Languages (DSL)

Что это?

Это некоторая форма компьютерных языков, разрабатываемых для специфичной предметной области. Это то, что позволяет вам (разработчикам ПО) лучше взаимодействовать с носителями “доменных знаний”. А так же позволяет более лаконично оформлять бизнес-логику. Это то, что представляет собой, к примеру, SQL, Linq, многое из синтаксиса Ruby On Rails.

Зачем мне это?

Если вы согласны с утверждением: “Языки общего назначения порой слишком красноречивы”, вы разрабатываете на .NET, либо сильно интересуетесь программированием, то наш доклад будет вам интересен.

Что я узнаю?

Ответы на следующие вопросы:

  • Что такое DSL?
  • Откуда это понятие пришло к нам?
  • Какие бывают DSL?
  • Какие “языки общего употребления (GPL)”  предоставляют возможности построения DSL? Какие из них есть на .NET?
  • Почему я должен использовать DSL? Какие плюсы от этого?
  • Какие шаблоны используются при построении DSL?
  • А можно увидеть примеры?

Материалы нашего выступления

Слайды презентации

Building DSLs on CLR and DLR (.NET)

Видео:

http://video.yandex.ru/users/thecoffee/collection/1/

Видео в более пригодном к рассматриванию надписей на доске качестве можно слить по ссылкам ниже:

http://narod.ru/disk/9278634000/01.wmv.html

http://narod.ru/disk/9279885000/02.wmv.html

Все рассмотренные примеры доступны здесь:

http://spbalt.net/Content/Baum_Moiseev_DSL.zip


Учимся проектировать на основе предметной области (DDD: Domain Driven Design)

1. Введение

В данной статье я хотел бы рассказать об этих трёх буквах, постоянно находящихся на слуху, но для многих являющихся тайной за семью печатями, а так же привести ряд ресурсов, с которыми неплохо было бы познакомиться при желании продолжить развитие в проектировании на основе предметной области (DDD: Domain Driven Design).

2. Так почему же DDD?

Есть несколько шаблонов реализации предметной области (Domain Logic) или бизнес-логики (Business Logic):

1) Table Module – представляет собой объект, в единственном экземпляре, обрабатывающий бизнес логику для всех записей в таблице базы данных, либо представления.

2) Transaction Script – организует взаимодействие с бизнес-логикой посредствам процедур, принимающих запросы с уровня представления.

3) Domain Model – непосредственно, объектная модель предметной области, включающая в себя как поведение, так и данные.

Эти шаблоны описаны более подробно Мартином Фаулером, в его книге “Архитектура корпоративных программных приложений. Шаблоны корпоративных приложений(Patterns of Enterprise Application Architecture (P of EAA)). В данной книге он показывает, что первые два шаблона более привлекательны в начале работы с предметной областью, однако так же обращает внимание, что при наращивании сложности логики предметной области стоит больше внимания уделять сопровождению инфраструктуры, используя первые два подхода, это время можно уменьшить, если обратиться в своём решении к третьему из вышеперечисленных шаблонов, так называемой “Модели предметной области”.

На основе этого сделаем небольшой вывод о том, что данный шаблон (“Модель предметной области”) лучше всего подойдёт, к примеру, для такой непростой области, как финансовый рынок. Большинство, создаваемого в наши дни программного обеспечения предназначено для различных нужд бизнеса, следовательно какие-то абстрактные, обобщенные решения находят своё место на рынке (с довольно таки высокой конкуренцией) всё реже и реже. К чему я пишу про всё это? Потому что DDD – это не только качественное проектирование, но так же и показательный пример того, как следует выделить предметную область в программном обеспечении, для того, чтобы проще преодолевать сложности, частые изменения, проблемы коммуникации и прочие недуги предметной области, вместо того чтобы разрабатывать уродливую, сложную для понимания систему, в которой любое изменение или исправление способно обрушить на вас лавину всё новых и новых дефектов.

DDD ни в коем случае не отрицает наследия практик разработки, таких как:

DDD лишь дополняет их. Поиск подходящей модели и абстракций в сложных сценариях требует значительных знаний в сфере объектно-ориентированного подхода, и достаточного опыта применения различных принципов, шаблонов и практик, а не просто DDD, как может показаться.

3. С чего можно начать?

Если мой “нудный PR”  проектирования на основе предметной области (DDD) вас до сих пор не утомил, то думаю нам стоит продолжить, если же иначе, то посмотрите хотя бы ссылки на материалы.

Первой книгой пролившей свет на DDD для широкой публики была так называемая “Большая синяя книга” (мем. BBB: Big Blue Book): Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans (на русский язык пока не переведена).

Книга довольна подробно рассказывает о том, что из себя представляет DDD, и все связанные аспекты, такие как: язык предметной области, шаблоны, практики проектирования, рефакторинг, моделирование, как сделать разработку гибкой и многое другое. Но даже если вы ознакомитесь со всеми вопросами, поднятыми в книге (что является не совсем простым занятием), вы обратите внимание, что вопросы рассматриваются только с теоретической точки зрения, оставляя весь простор для практики (книга не привязана к конкретной платформе разработки). Для большинства из нас чтение чистой теории, без подкрепления практическими примерами не нравится, в связи с этим можно обратить своё внимание на сокращенную (и свободную для доступа) версию этой книги, подготовленную порталом InfoQ: Domain Driven Design Quickly.

Есть так же несколько хороших презентаций Эрика Ивенса (Eric Evans), с которых можно начать:

1) DDD: putting the model to work

2) Eric Evans on DDD: Strategic Design

На портале InfoQ можно найти множество других презентаций, статей и интервью, посвященных DDD.

Итак, с теоретической частью мы разобрались, где же можно найти примеры практического применения DDD? Отличной книгой для этого является .NET Domain-Driven Design with C#, Problem – Design – Solution написанная Tim McCarthy. 

В этой книге вы наёдете практические примеры:

1) Как проходит процесс проектирования и разработки, от определения требований, до написания кода

2) Как организовывать архитектурные слои в своих решениях

3) Как применять шаблоны и практики DDD

4) Как построить небольшой каркас для DDD

5) Как изолировать домен предметной области от модели

6) Современные паттерны представления данных и взаимодействия с ними (Model-View-ViewModel) в такой среде как WPF (так же применимы к Silverlight) в практики.

Эта книга – отличный практикум по DDD, содержащий очень широкий пласт идей. Начинается книга с разработки требований, а заканчивается реализацией промышленного приложения, исходные коды которого доступны на Codeplex.

Вся концепция книги построена на 3 книгах-столпах DDD:

  1. PoEAA Мартина Фаулера
  2. DDD Эрика Ивенса
  3. Applying Domain — Driven Design and Patterns by Jimmy Nilsson’s (“Применение шаблонов проектирования: проблемно-ориентированное проектирование приложений с примерами на C# и .NET” Джимми Нильссона )

В этой книге поверхностно рассмотрены все вопросы, техники и паттерны, применяемые в DDD, все примеры сопровождаются кодом, что упрощает понимание. Книга превосходная, однако русский перевод подкачал, поэтому, рекомендую прочитать оригинал.

 

 

Однако DDD – это не просто практические решения или шаблоны, это мышление и подход, и есть великое множество нюансов, которые необходимо учитывать, если вы решили следовать DDD, таких как: фокусирование на высокий приоритет отдается модели, выработка языка предметной области, контекст модели, процесс моделирования, разделение знаний, рефакторинг, стратегический дизайн и т.д…это является  основной причиной ознакомиться с книгой Эрика Ивенса, так как она даст вам более объемное и глубокое понимание философии DDD.

DDD не привязанны к конкретной технологии, однако соблюдать DDD будет не так просто, без наличия хороших средств и практик в вашем арсенале, таких как: TDD-фреймворк, ORM, возможность реализации независимости сохраняемости (Persistence Ignorance), IoC-контейнер (Inversion of Control), и возможностей AOP (Аспектно-Ориентированного Программирования), конечно не значит, что все эти инструменты нам понадобятся, однако они приблизят нас к реализации DDD на практике. Практичная ценность этих средств в том, что они позволять изолировать модель предметной области, что является ключевой целью DDD. Книга Джимми Нильссона может познакомить вас с возможностями и видами данных инструментов. Джимми так же показывает как использовать шаблоны реализации корпоративных приложений, и строить, благодаря им, цельное решение, основанное на современных инструментах и практиках.

Некоторые реализации шаблонов DDD на Ruby On Rails:

Some DDD (Domain Driven Design) Concepts implemented in Rails

4. Актуальные вопросы DDD

C DDD так же тесно связана такая тема, как DDDD: Distributed Domain Driven Design (Распределенный DDD). DDDD – это DDD в распределенных сценариях. В настоящее время существует не так много ресурсов, посвященных DDDD, в нескольких словах о DDDD: покрывает проблему реализации сообщений и DDD, разделение команд и запросов (Command Query Separation (CQS)) помогает реализовать данный подход. Грег Янг (Greg Young) сообщил, что готовит книгу, посвященную DDDD.

SOA и DDD – это ещё одна объемная тема, часто обсуждаемая Udi Dahan

5. DDD шаблоны, концепции и понятия

В промышленных приложениях DDD использует ряд шаблонов, часть которых описана в книге Эрика Ивенса, но, это не отменяет применение объектно-ориентированного подхода, включающего GoF-шаблонышаблоны Мартина Фаулера, описанные в его PoEAA, Шаблоны интеграции корпоративных приложений и т.д.…

Вот некоторые из них:

6. Примеры приложений

Найти хорошие примеры реализации DDD очень сложно, не потому что их не существует, а потому что реальная сила DDD реализуется в приложениях, используемых в довольно сложных областях, и, как правило, являющихся коммерческими проектами. Однако можно найти несколько неплохих проектов, в которых можно проследить некоторые идеи реализации шаблонов DDD.

Вот они:

1) Приложение Тима Маккарти его проект, описанный в деталях в его книге. Он описывает не только применение шаблонов, но так же акцентирует внимание в разработке модели предметной области с точки зрения DDD.

Проект так же интересен тем, что построен на .NET 3.5 и демонстрирует всю силу современного подхода связывания данных с моделью предметной области (data binding, реализация шаблона MVVM). Так же его стиль примечателен умением выделять абстракции и повторно используемый код.      

2) Следующий проект, на который следует обратить внимание – это приложение разработанное Yves Goeleven, создание данного приложения описано в его блоге (так же посвященному основным концептам DDD). Другим его приложением является DDD-каркас. Следует обратить внимание на его реализацию взаимодействия шаблонов Repository и Specification

3) Billy McCafferty разрабатывает потрясающий open source фреймворк, сфокусированный на DDD, под названием S#arp Architecture. У него есть очень хорошее описание, включающее в себя описание шаблонов и подходов, заключенных в фреймворке. Фреймворк нацелен на разработку ASP.NET MVC приложений с применением NHibernate.

4) C# Domain-Driven Design sample application ( ndddsample ), это приложение, разрабатываемое Джимми Нильссоном, демонстрирует разбиение приложения на ключевые слои с точки зрения DDD. Так же демонстрируется практическое применение шаблонов building block в предметной области перевозки грузов, описанной в его книге.

Этот проект основан на совместной работе компании Эрика Ивенса “Domain Language” и шведской консалтинговой компании “Citerus”.

Цель этого проекта:

  • Показать практическое применение использования DDD с применением .NET.
  • Использование актуальных утилит, технологий и методологий разработки в области .NET, обсуждаемых ALT.NET-коммунити.
  • Привести практические примеры реализации типовых DDD приложений.
  • Показать способ реализации DDD на конкретной платформе, что позволит без труда осуществить тоже самое на любой другой платформе.
  • Помочь в выборе реализуемых практик. Различные подходы позволят сообществу обсудить их и выбрать соответствующий для конкретной реализации.

здесь более подробная информация.

7. Ресурсы по Domain Driven Design

Официальный сайт — http://domaindrivendesign.org/

Группа обсуждений — http://tech.groups.yahoo.com/group/domaindrivendesign/ это взрослая группа, очень хороший источник идей, место для обсуждений всех видов проблем в области DDD. В ней на ваши вопросы могут ответить опытные в DDD люди, даже Эрик Ивенс :-).

Блог Jimmy Bogard’а — http://www.lostechies.com/blogs/jimmy_bogard/default.aspx

Блог Colin Jack’а — http://colinjack.blogspot.com/

Блог Greg Young’а — http://codebetter.com/blogs/gregyoung/default.aspx

Блог Casey Charlton’а — http://devlicio.us/blogs/casey/

Блог Udi Dahan’а — http://www.udidahan.com/

Введение в Domain-Driven Design — http://msdn.microsoft.com/ru-ru/magazine/dd419654.aspx

8. Заключение

Если вы заинтересованы в расширении ваших “объектно-ориентированных горизонтов” в сложных корпоративных системах и изучении новых способов разработки и проектирования, то DDD – именно то что нужно.

http://weblogs.asp.net/arturtrosin/archive/2009/02/09/domain-driven-design-learning.aspx


Как создать ассоциацию workflow и списка программно

Цель поста

Данный пост призван продемонстрировать как выполнять ассоциацию workflow и списка программно. Workflow может быть стандартной, либо созданным в Visual Studio. Что касается workflow, он будет использовать стандартные списки задач и список истории workflow.

Примеры

Договоримся, что переменная web – это объект SPWeb, содержащий список, который нам необходим для ассоциации с workflow.

1. Объявим переменные, которые будем использовать

  1. SPList myList = null;                              // Лист для ассоциации с workflow
  2. string myListName = null;                          // название нашего спика
  3. SPList historyList = null;                         // список истории workflow
  4. SPList taskList = null;                             // список задач workflow
  5. string workflowTemplateGuid = null;                 // Guid шаблона worklfow
  6. SPWorkflowTemplate workflowTemplate = null;         // шаблон Workflow
  7. SPWorkflowAssociation workflowAssociation = null// ассоциация с workflow
  8. string workflowAssocName = null;                    // имя ассоциации с workflow

* This source code was highlighted with Source Code Highlighter.

2. Инициализация

Убедитесь, что используете internal name списка. И установите имя ассоциации с workflow, он может соответствовать наименованию соответствующего workflow.

  1. myListName = "My list name";
  2. workflowAssocName = "My Workflow";

* This source code was highlighted with Source Code Highlighter.

3. Получить шаблон workflow

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

  1. workflowTemplateGuid = "BAD855B1-32CE-4bf1-A29E-463678304E1A";
  2. workflowTemplate = web.WorkflowTemplates[new Guid(workflowTemplateGuid)];

* This source code was highlighted with Source Code Highlighter.

Так же вы можете получить GUID шаблона, используя метод GetTemplateByName.

  1. // Пытаемся получить список истории workflow
  2. try
  3. {
  4.      historyList = web.Lists["Workflow History"];
  5. }
  6. catch (ArgumentException exc)
  7. {
  8.      // Создаем список истории workflow
  9.      Guid listGuid = web.Lists.Add("Workflow History", "", SPListTemplateType.WorkflowHistory);
  10.      historyList = web.Lists[listGuid];
  11.      historyList.Hidden = true;
  12.      historyList.Update();
  13. }

* This source code was highlighted with Source Code Highlighter.

4. Получить, либо создать списки истории и задач workflow.

Список истории, используемый workflow, должен быть унаследован от шаблона списка WorkflowHistory. В большинстве случаев вам не понадобиться его создавать.

  1. workflowTemplate = web.WorkflowTemplates.GetTemplateByName(        "Template name",        System.Globalization.CultureInfo.CurrentCulture);

* This source code was highlighted with Source Code Highlighter.

Список задач – это обычный список, унаследованный от шаблона списка задач. Если вы хотите создать специфичный список задач для workflow, не стоит называть его “Задачи” (“Tasks”). R примеру мы можем назвать его “Задачи рабочего процесса” (“Workflow tasks”).

  1. // Пытаемся получить список задач для workflow
  2. try
  3. {
  4.      taskList = web.Lists["Workflow Tasks"];
  5. }
  6. catch (ArgumentException exc)
  7. {
  8.      // Создаём список задач для workflow
  9.      Guid listGuid = web.Lists.Add("Workflow Tasks", "", SPListTemplateType.Tasks);
  10.      taskList = web.Lists[listGuid];
  11.      taskList.Hidden = true;
  12.      taskList.Update();
  13. }

* This source code was highlighted with Source Code Highlighter.

5. Создаем ассоциацию с workflow, конфигурируем её и привязываем к списку.

  1. // Включаем небезопасные обновления для узла (web)
  2. web.AllowUnsafeUpdates = true;
  3. try
  4. {
  5.         // Создаем ассоциацию workflow
  6.         workflowAssociation = SPWorkflowAssociation.CreateListAssociation(                workflowTemplate,                workflowAssocName, taskList, historyList);
  7.  
  8.         // Устанавливаем параметры workflow
  9.         workflowAssociation.AllowManual = false;
  10.         workflowAssociation.AutoStartCreate = true;
  11.         workflowAssociation.AutoStartChange = false;
  12.  
  13.         // Связываем workflow со списком
  14.         myList.AddWorkflowAssociation(workflowAssociation);
  15.  
  16.         // Активируем ассоциацию
  17.         workflowAssociation.Enabled = true;
  18. }
  19. finally
  20. {
  21.         web.AllowUnsafeUpdates = false;
  22. }

* This source code was highlighted with Source Code Highlighter.

Источник

Данная статья является переводом данного поста:

http://blogs.prexens.com/Lists/Posts/Post.aspx?List=7a299699-f8da-4559-920c-bda481608691&ID=9


Шаблоны сохраняемости

Отличная статья в MSDN Mag April 2009, посвященная шаблонам сохраняемости:

http://msdn.microsoft.com/ru-ru/magazine/dd569757(en-us).aspx

Обзору подверглись следующие шаблоны:

Active Record
Data Mapper
Using a Repository
Identity Map
Lazy And Eager Loading
Virtual Proxy Pattern

Так же о шаблонах сохраняемости можно прочесть в блоге у Александра Кондуфорова:

http://merle-amber.blogspot.com/2009/02/orm.html


Создание простейшего DI контейнера с использованием TDD

Введение

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

Требования

Нам понадобится Visual Studio 2008, 15-20 минут свободного времени и желание узнать как же сделать свой DI контейнер.

Начнём. Funq1

  • Для начала создадим проект Class Library в Visual Studio, назовём его Funq1
  • Далее добавим в решение проект тестов (мы будем использовать TDD на базе тестов Visual Studio) и назовём его Funq1.Tests, создадим ссылку из него на наш проект Funq1

Funq1.Tests

  • В проекте Funq1.Tests создадим тестовый класс ContainerFixture, который будет проверять функционал нашего контейнера.
  • Добавим объявление интерфейсов IFoo, IBar, а так же соответственно классов Foo, Bar, для тестирования нашего контейнера:

  1. public interface IBar { }
  2. public interface IFoo { }
  3.  
  4. public class Bar : IBar { }
  5.  
  6. public class Foo : IFoo
  7. {
  8.     public IBar Bar { get; private set; }
  9.  
  10.     public Foo(IBar bar)
  11.     {
  12.         Bar = bar;
  13.     }
  14. }

* This source code was highlighted with Source Code Highlighter.

  • Создадим тестовый метод, который проверит умеет ли наш контейнер регистрировать и возвращать объекты, выглядеть он будет примерно следующим образом:

  1. [TestMethod]
  2. public void RegisterTypeAndGetInstance()
  3. {
  4.     var container = new Container();
  5.  
  6.     container.Register<IBar>(() => new Bar());
  7.  
  8.     var bar = container.Resolve<IBar>();
  9.  
  10.     Assert.IsNull(bar);
  11.     Assert.IsTrue(bar is Bar);
  12. }

* This source code was highlighted with Source Code Highlighter.

  • Итак, на тестовый класс ContainerFixture выглядит следующим образом:

  1. using Microsoft.VisualStudio.TestTools.UnitTesting;
  2.  
  3. namespace Funq1.Tests
  4. {
  5.     [TestClass]
  6.     public class ContainerFixture
  7.     {
  8.         [TestMethod]
  9.         public void RegisterTypeAndGetInstance()
  10.         {
  11.             var container = new Container();
  12.  
  13.             container.Register<IBar>(() => new Bar());
  14.  
  15.             var bar = container.Resolve<IBar>();
  16.  
  17.             Assert.IsNull(bar);
  18.             Assert.IsTrue(bar is Bar);
  19.         }
  20.  
  21.         public interface IBar { }
  22.         public interface IFoo { }
  23.  
  24.         public class Bar : IBar { }
  25.  
  26.         public class Foo : IFoo
  27.         {
  28.             public IBar Bar { get; private set; }
  29.  
  30.             public Foo(IBar bar)
  31.             {
  32.                 Bar = bar;
  33.             }
  34.         }
  35.     }
  36. }

* This source code was highlighted with Source Code Highlighter.

Funq1.Container

  • Наш тест не проходит, так как Container остается не объявленный, в связи с этим в проекте Funq1 добавляем класс Container
  • Объявляем поле, в котором будут храниться соответствия типов:

  1. Dictionary<Type, object> factories = new Dictionary<Type, object>();

* This source code was highlighted with Source Code Highlighter.

  • Добавим метод для регистрации типа в контейнере:

  1. public void Register<TService>(Func<TService> factory)
  2. {
  3.     factories.Add(typeof(TService), factory);
  4. }

* This source code was highlighted with Source Code Highlighter.

  • А так же метод, для извлечения типа из контейнера:

  1. public TService Resolve<TService>()
  2. {
  3.     object factory = factories[typeof(TService)];
  4.  
  5.     return ((Func<TService>)factory).Invoke();
  6. }

* This source code was highlighted with Source Code Highlighter.

  • На данный момент наш Container выглядит следующим образом:

  1. using System;
  2. using System.Collections.Generic;
  3.  
  4. namespace Funq1
  5. {
  6.     public class Container
  7.     {
  8.         Dictionary<Type, object> factories = new Dictionary<Type, object>();
  9.  
  10.         public void Register<TService>(Func<TService> factory)
  11.         {
  12.             factories.Add(typeof(TService), factory);
  13.         }
  14.  
  15.         public TService Resolve<TService>()
  16.         {
  17.             object factory = factories[typeof(TService)];
  18.  
  19.             return ((Func<TService>)factory).Invoke();
  20.         }
  21.     }
  22. }

* This source code was highlighted with Source Code Highlighter.

Funq1.Tests

  • Пробуем запустить тесты, но они не проходят, т.к. мы умышленно внесли ошибку  в описании метода RegisterTypeAndGetInstance() в строке 17: Assert.IsNull(bar), чтобы убедиться, что тест срабатывает
  • Для того, чтобы тест прошёл, следует изменить эту строчку на Assert.IsNotNull(bar);
  • Далее нас интересует, а что же с зависимостью в конструкторе, как её необходимо зарегистрировать, для этого мы объявляем тестовый метод ResolveGetsDepedenciesInjected() и заносим следующие объявления:

  1. container.Register<IBar>(() => new Bar());
  2. container.Resolve<IFoo>(() => new Foo(container.Resolve<IBar>()));

* This source code was highlighted with Source Code Highlighter.

  • Однако данное объявление не понравится нашему компилятору, т.к. в области видимости замыкания не присутствует container, в связи с этим данное объявление придётся немного изменить:

  1. container.Register<IBar>(c => new Bar());
  2. container.Register<IFoo>(c => new Foo(c.Resolve<IBar>()));

* This source code was highlighted with Source Code Highlighter.

Funq1

  • Соответственно необходимо будет немного изменить наш контейнер, добавив в функции аргумент Container:

  1. public void Register<TService>(Func<Container, TService> factory)
  2. {
  3.     factories.Add(typeof(TService), factory);
  4. }
  5.  
  6. public TService Resolve<TService>()
  7. {
  8.     object factory = factories[typeof(TService)];
  9.  
  10.     return ((Func<Container, TService>)factory).Invoke(this);
  11. }

* This source code was highlighted with Source Code Highlighter.

Funq1.Tests

  • После внесенных в контейнер изменений необходимо будет немного поправить наш первый тестовый метод RegisterTypeAndGetInstance() строку 13 на выражение:

  1. container.Register<IBar>(c => new Bar());

* This source code was highlighted with Source Code Highlighter.

  • Далее вернемся к нашему методу ResolveGetsDepedenciesInjected() и добавим к нему извлечение объекта и утверждение-проверку на null, в результате получим:

  1. [TestMethod]
  2. public void ResolveGetsDepedenciesInjected()
  3. {
  4.     var container = new Container();
  5.  
  6.     container.Register<IBar>(c => new Bar());
  7.     container.Register<IFoo>(c => new Foo(c.Resolve<IBar>()));
  8.  
  9.     var foo = container.Resolve<IFoo>() as Foo;
  10.  
  11.     Assert.IsNotNull(foo);
  12.     Assert.IsNotNull(foo.Bar);
  13. }

* This source code was highlighted with Source Code Highlighter.

Заключение

Вот и подошёл к концу наш увлекательный (надеюсь) урок по созданию с нуля простейшего DI контейнера, что же мы приобрели в процессе:

  1. Базовое понимание функционирования DI контейнера
  2. Практические навыки разработки с использованием TDD

Цикл статей о N-уровневой реализации Веб-приложений на основе ASP.NET 3.5

Введение

 

Наверное большинство читателей, использующих ASP.NET создают многоуровневые приложения, кто же этого не делает, рекомендую начать, т.к. это, как минимум, облегчит Вам жизнь.

Содержание

 

Хотелось бы обратить внимание на цикл статей, написанных Imar Spaanjaars, подробно описывающих создание многоуровневых приложений на ASP.NET 3.5, а так же сопровожденных большим количеством практических примеров.

Previous Series
Building Layered Web Applications with Microsoft ASP.NET 2.0 — Part 1 (3)
Building Layered Web Applications with Microsoft ASP.NET 2.0 — Part 2 (4)
Building Layered Web Applications with Microsoft ASP.NET 2.0 — Part 3 (5)
Custom Sorting with N-Layer Design Classes and the GridView (6)

Current Series
N-Layered Web Applications with ASP.NET 3.5 Part 1: General Introduction (7)
N-Layered Web Applications with ASP.NET 3.5 Part 2: Introducing the Validation Framework (8)
N-Layered Web Applications with ASP.NET 3.5 Part 3: Advanced Validation Topics (9)
N-Layered Web Applications with ASP.NET 3.5 Part 4: Sorting, Paging and Filtering (10)
N-Layered Web Applications with ASP.NET 3.5 Part 5: Dealing with Concurrency
N-Layered Web Applications with ASP.NET 3.5 Part 6: Security


Что такое ALT.NET?

Введение

По многочисленным WTF от коллег, хотел бы вкратце прояснить, а что же это такое. А дальше решайте сами, интересно Вам это или нет.

Содержание

 

ALT.NET — Альтернативные инструменты и подходы к разработке на .NET.

Инструменты и подходы перечислены ниже в табличке HOTorNOT.

Hot Not
Castle, ActiveRecord,
NHibernate
DataSets, Dataset Designer, Entity Framework, MS Application Blocks
MVC,NUnit,MonoRail Web Forms, SCSF, VSTS, MSTest
XP, TDD, Scrum MSF Agile, MSF For CMMI
Evolutionary Design and Development Big Design Up Front
Ruby + IronRuby, Python + IronPyton, DLR, Silverlight(?) ?
OR\M (NHibernate, LLBLGen  etc..) DLinq, Data Access Block, DataSets, Plain ADO. NET
Open Source (Mono, SourceForge) Application Blocks, CodePlex
MVC and MVP (RoR, MonoRail..) Web Forms, CAB, Smart Client Factory
CVS, SVN VSS, VSTS Source Control
Build Automation and CI
(CI Factory, NAnt, FinalBuilder, CruiseControl..)
Team Build
TDD and Unit Testing
NUnit, MbUnit, RhinoMocks, NMock, TypeMock
MSTest for unit testing, VSTS
Subtext, DasBlog, WordPress, TypePad, Blogger, FeedBurner Microsoft MSN Spaces, Community Server(?)
Simplicity in Design P&P
Working at Google Working at MS
Google Gears Smart Client, MS Ajax
.NET 3.X (WF, WPF. Silverlight) .NET 2.0
DI, IoC, Spring for .NET Object Builder
Conferences:
OSCon, RubyCon, Code Camps, DevTeach..
VSLive, TechEd, DevConnections..

Считаю, что необходимо как минимум ознакомиться со всеми перечисленными понятиями как в правой, так и в левой колонках, следуя принципу анализ-синтез-best practices.

Материалы по теме

 

  1. Табличка любезно позаимствована здесь http://weblogs.asp.net/rosherove/archive/2007/06/04/alt-net-alternative-tools-and-approaches-to-mainstream-net.aspx
  2. Страница сообщества ALT.NET http://altdotnet.org/
  3. Статья в журнале MSDN “Что такое ALT .NET?” by Джереми Д. Миллер (Jeremy D. Miller) http://msdn.microsoft.com/ru-ru/magazine/cc337902.aspx
  4. Активно развивающаяся группа ALT.NET на Yahoo Groups http://tech.groups.yahoo.com/group/altdotnet/

Головоломки на C# (Ответы)

Введение

Итак, в предыдущем посте мною были приведены 6 вариантов необычного поведения языковых конструкций на C#. В этом посте я постараюсь дать более-менее внятное объяснение данных особенностей происходящего.

Ответы

Далее я продублирую приведенные фрагменты кода, а так же дополню их описанием нюансов

  1. Перегрузка

    Как вы думаете что выведет данный код и почему?

    using System;
    
    class Base
    {
        public virtual void Foo(int x)
        {
            Console.WriteLine ("Base.Foo(int)");
        }
    }
    
    class Derived : Base
    {
        public override void Foo(int x)
        {
            Console.WriteLine ("Derived.Foo(int)");
        }
        
        public void Foo(object o)
        {
            Console.WriteLine ("Derived.Foo(object)");
        }
    }
    
    class Test
    {
        static void Main()
        {
            Derived d = new Derived();
            int i = 10;
            d.Foo(i);
        }
    }

    Результат: Derived.Foo(object).Мы получили его таким, т.к. при выборе подходящего перегруженного метода в наследуемом типе компилятор игнорирует определенный в базовом типе метод, даже если он был переопределен в наследуемом!

  2. Порядок! Порядок!

    В каком порядке напечатаются строки на экране?

    using System;
    
    class Foo
    {
        static Foo()
        {
            Console.WriteLine ("Foo");
        }
    }
    
    class Bar
    {
        static int i = Init();
        
        static int Init()
        {
            Console.WriteLine("Bar");
            return 0;
        }
    }
    
    class Test
    {
        static void Main()
        {
            Foo f = new Foo();
            Bar b = new Bar();
        }
    } 

    Результат: В варианте Джона он получает следующую последовательность: “Bar, Foo”, однако при воспроизведении на своей машине у меня получилось: “Foo, Bar”. Я думаю, что причина различий лежит в разнице версий исполняющей среды (CLR, я исполнял код на версии 2.0.50727.3053). Он объясняет свои результаты тем, что у Foo конструктор статический, следовательно он не будет выполнен до точки первой инициализации этого класса. У Bar же нет статического конструктора, что позволяет CLR инициализировать его раньше. Однако, нет гарантии, что Bar будет напечатан вовсе, так как в нашем примере у CLR в принципе нет надобности инициализировать это статическое поле. Более подробно все эти нюансы описаны здесь!

  3. “Глупая” арифметика

    Компьютеры призваны помочь нам с арифметическими вычислениями, но почему тогда это выражение выводит false?

    double d1 = 1.000001;
    double d2 = 0.000001;
    Console.WriteLine((d1-d2)==1.0); 

    А такой вариант?

    double sum = 0;
    for (int i =0;i<10 ;i++ )
    {
      sum+=0.1;    
    }
    Console.WriteLine(sum==1.0); 

    Результат: Все значения в данных примерах хранятся в двоичном виде, хотя 1.0 может хранится как точное значение, 1.000001 будет храниться примерно как 1.0000009999999999177333620536956004798412322998046875, и 0.000001 так же будет сохранено в виде 0.000000999999999999999954748111825886258685613938723690807819366455078125. В связи с этим нельзя утверждать о равенстве в предыдущих примерах. Почитать подробнее о числах с плавающей точкой.

    На заметку: В связи с указанными выше особенностями работы с типами с плавающей точкой, однозначно рекомендуют не использовать их при работе с денежными единицами, в данном случае рекомендуют определять собственные денежные типы (так называемые типы объект-значение [Object-Value]) с собственной логикой округления и прочих арифметических операций, а так же межвалютных операций.

  4. Печать, печать, печать

    Ниже приведен код, использующий анонимные методы, каков будет результат его исполнения?

    using System;
    using System.Collections.Generic;
    
    class Test
    {
        delegate void Printer();
        
        static void Main()
        {
            List<Printer> printers = new List<Printer>();
            for (int i=0; i < 10; i++)
            {
                printers.Add(delegate { Console.WriteLine(i); });
            }
            
            foreach (Printer printer in printers)
            {
                printer();
            }
        }
    } 

    Результат: О эта радость от фиксированных переменных. В данном примере всего одна переменная и её значение изменяется при каждой итерации в цикле. Анонимные методы фиксируют переменную, а не её значение, следовательно в результате мы получим десть раз число 10 на выводе!

  5. Ничего странного с компилятором тут не случилось

    Этот код скомпилится? Как это? Что бы это значило?

    using System;
    
    class Test
    {
        enum Foo { Bar, Baz };
        
        static void Main()
        {
            Foo f = 0.0;
            Console.WriteLine(f);
        }
    }

    Результат: Это не должно компилироваться, однако это происходит. Это не должно копилироваться, в связи с тем, что только значение 0 может быть конвертированно в значение по умолчанию для enum. В примере же значение 0.0 имеет место быть корректным в связи с небольшой недоработкой компилятора. В результате будет напечатано Bar, т.к. 0 будет значением Foo.

    using System;
    
    class Test
    {
        enum Foo { Bar, Baz };
        
        const int One = 1;
        const int Une = 1;
        
        static void Main()
        {
            Foo f = One-Une;
            Console.WriteLine(f);
        }
    } 

    Результат: Данный пример не будет компилироваться под C#2.0, но прекрасно компилируется под C#3.0. Это известная особенность, объяснить это можно тем, что оптимизированный алгоритм выполняет вычисления значения One-Une раньше, а следовательно перечисление даёт своё значение по-умолчанию 0.

  6. Вывод типа

    Какой же вариант будет выведен на экран?

    using System;
    
    class Test
    {
        static void Main()
        {
            Foo("Hello");
        }
        
        static void Foo(object x)
        {
            Console.WriteLine("object");
        }
        
        static void Foo<T>(params T[] x)
        {
            Console.WriteLine("params T[]");
        }
    } 

    Результат: params T[] будет напечатан. Но почему же компилятор выбирает создание массива, хотя в этом нет надобности? Этому есть две причины. Во-первых при выборе перегруженных методов T будет рассматриваться как System.String. Ничего страшного пока в этом нет.

    Однако при выборе “лучшего” метода среди параметров string x and params string[],x формально будет приоритетнее. Однако с нашей точки зрения эффективности выбор между object x и params string[] x падёт на метод с params string[] x в связи с тем, что он не требует преобразований типов.

Материалы

 

  1. Подготовлено по материалам http://www.yoda.arachsys.com/csharp/teasers-answers.html
  2. А так же http://martinfowler.com/

Новая возможность .NET Reflector™

Вступление

Какой же всё-таки отличный этот Codeplex, чего там только нет. Сегодня обнаружил очень полезный плагин для рефлектора – он генерирует проекты для Visual Studio из сборки, загруженной в рефлектор, думаю переоценить насколько это полезно очень сложно.

Демонстрация

Так выглядит этот плагин в рефлекторе

Установка

Для того, чтобы воспользоваться этим замечательным дополнением нужно:

  1. Скачать поселднюю версию плагина по адресу http://www.codeplex.com/FileGenReflector
  2. Извлечь содержимое архива в папку с рефлектором
  3. Добавить FileGenerator.dll в Add-In’ы
  4. Попробовать и удивиться, что это работает 😉

Всем приятного кодинга!