6/7/2010 3:06:47 PM

По поводу предыдущей заметкипро FlowChart.

Как совершенно правильно заметил Паша в баззе, проблема всего этого великолепия с “долгоиграющими” workflow заключается в том, их нельзя менять.

При попытке что-то добавить или удалить запущеные и сохранённые в БД экземпляры просто не будут оттуда загружаться, а Workflow Runtime будет выдавать страшное сообщение о том, что “дерево Activities изменено, и поэтому состояние не может быть восстановлено”.

Как это решается? А никак. Просто никак. Официально предложен следующий механизм решения конфликта: името параллельно несколько версий и настроить роутинг WCF-сообщений. Чтобы сообщения, содержащие контракт “v1” доставлялись на сервис V1, а сообщения, содержащие контракт “v2” доставлялись на сервис V2.

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

Далее предлагается поступить так, как в КВН у команды Астаны (Казахстан) было: “Ну их!” :)
То есть, “старые” процессы дорабатывают по старой схеме, а те, которые начинаются новые – идут по схеме новой.

Иногда это не лишено смысла, допускаю. Однако, что делать, если нужно банально исправить ошибку? Особенно, если у нас имеются “бесконечные” workflow, как, например, документы в системе: они просто переходят из одного статуса в другой, туда, обратно, раз в два месяца…
Ответа на этот вопрос, видимо, не существует :)

Как вариант можно попробовать (только мысли, сам не ковырялся) написать свой вариант сохранения/загрузки workflow в/из БД.
Делается это, вроде бы, совершенно не сложно: надо просто создать своего наследниеп System.Runtime.DurableInstancing.InstanceStore. А вот насколько будет сложно там, внутри, разобраться, что данные у нас от V1 и построить на основе них V2 – непонятно, надо пробовать :) Наверное, однозначно ответить нельзя: когда-то это сделать легко, а когда-то и невозможно просто потому, что данных не хватит…

Пример того, как сделать собственную “сохранялку” в XML есть в библиотеке примеров для WF и WCF, здесь.

Паша ещё предложил как вариант делать stateless workflows. Чтож, вариант, хотя и очень-очень сильно компромисный и не всегда приемлемый. К тому же, в WF4 нет State Machines, и как “сказать” Workflow, что сейчас она находится не вот в этом состоянии, а вон в том – я не знаю. Допустим, она “висит” на Delay где-нибудь в середине. Или на ждёт, что кто-то “дёрнет” WCF-метод.

По поводу сохранения ещё, раз уж Паша эту тему тоже затронул.
В WF4 это тоже переделано относительно 3.5. Теперь Workflow Runtime не сохраняет сам Instance, а сохраняет только некие его состояния, переменные, в результате чего объёмы получаются гораздо меньше, нежели они были раньше. Что, в принципе, правильнее и логичнее. Но вот поднять именно код из сохранённого состояния больше не выйдет.

По поводу ошибок теперь.
В WF4 есть activities для транзакций и обработки ошибок (try..catch). То есть, всё можно делать непосредственно там – о отлов, и компенсацию, и обработку.
Если же всё-таки где-то недосмотрели и “выпали” в событие UnhandledException, то в этом случае мы “теряем” только то состояние, которое находилось на момент ошибки в памяти. То есть, в следующий раз workflow будет продолжена с момента последнего сохранения в БД.
Кстати, есть там ещё замечательная Persist Activity. Понятно, что она делает ;) Так вот, сначала Persist, потом делаем перевод денег :) Если что-то не получилось – в следующий раз выполнение продолжится с того же самого места, как и было указано в Пашином примере.

Но с версионностью – засада, конечно. Надо ещё будет попробовать, возможно ли её разрешать автоматически хоть в простых случаях… Тогда, может быть, комбинация stateless (or minimum state) + такая вот собственная сохранялка хоть как-то сможет помочь…

6/6/2010 2:39:02 PM

Два дня потратил на то, чтобы более-менее разобраться в Workflow Foundation 4-й версии.

Из новых замечательных возможностей – FlowChart диаграмма и возможность выставить содержащую её Workflow в сеть в виде “обычного” WCF-сервиса.

Сама по себе FlowChart диаграмма очень удобна, прежде всего своей наглядностью (сразу понятно, как протекает процесс), а так же тем, что практически в точности отражает те блок-схемы, которые вырисовываются на досках и бумажках при продумывании схемы работы. Наиболее счастливые разработчики сразу получают задание от специалиста по требованиям в виде примерно такой вот схемы с фразой “я хочу, чтобы было так!” в заголовке :)

Программисту остаётся только открыть Visual Studio, выбрать там проект, который называется “WCF Workflow Service Application”, и начать определять свой сервис в файле Service1.xamlx (лучше переименовать, или создать новый ;))

Я попробовал сделать небольшой сервис по обработке tickets (извините, я буду писать “тикетов”, так как не сумел придумать нормальный перевод).
Система примерно такая: тикет регистрируется в системе, после чего может изменяться до тех пор, пока не перейдёт в состояние Cancelled или Closed.
При этом он может попасть в состояние WaitingForCustomer. В этом состоянии он может ожидать неделю. Если клиент ничего не ответил, то тикет закрывается.

В результате получается что-то вроде вот такой диаграммы:

FlowChart 

Блок “Receive and Update Ticket” – это просто Activity, определённая в отдельном .xaml-файле.
Он отвечает за то, чтобы получить тикет посредством WCF-метода, сохранить его где-то, возможно, изменив, и отправить изменённый тикет обратно (для отображения).
Выглядит это так:

 Получение тикета через сервис

Здесь я просто “перетянул” мышкой в дизайнере ReceiveAndSendReply Activity, в результате чего образовались два блока, отмеченные стрелками. Первый – это получение WCF-сообщения, второй – возвращение значения.
Между получением значения и возвращением результата можно делать какие-то действия. Любые, в общем-то. Можно туда ещё один workflow вставить, который будет что-то важное делать, подготавливая данные к отправке, например, ещё одну FlowChart диаграмму :)
В моём случае всё предельно просто: я только добавляю запись в коллекцию History у тикета и возвращаю его обратно. Хотя, неплохо было бы сначала изменить историю, а потом уже сохранить ;)
Понятно, что если значение возвращать не надо, то можно воспользоваться просто Receive Activity.

Важно здесь то, что прямо в этих avtivities указывается имя метода (ProcessTicket), тип контракта, который будет принимать/получать метод (или можно указать кучку параметров) и что этот метод будет возвращать (это в SendReplyToReceive). Всё остальное будет сделано автоматически, метод станет виден WCF-клиентам как самый обычный WCF-метод.

Конфигурация WCF-метода.

Здесь MessageType = Ticket – это тип принимаемого сообщения (я принимаю Ticket), в Message data = _ticket – это имя переменной, куда я хочу положить принятый результат.

А ещё, поскольку мы получаем данные, производим над ними работу, а потом отправляем результат назад, нам нужно обеспечить для каждого такого процесса свой собственный, выделенный экземпляр workflow. Сделать это просто: нужно в свойствах Receive Activity включить галку CanCreateInstance. Впрочем, если Вы забудете это сделать, то при запуске Вам напомнят, да.
Итак, после этого у нас каждый тикет будет обрабатываться собственным экземпляром workflow. Что нам, собственно, и надо, ибо жизненные пути тикетов различны…

LogTicketInfo Activity я описывать не буду, скажу только, что это просто класс, activity, унаследованная от CodeActivity и она не делает ничего полезного, кроме Debug.WriteLine(..).
В WF4 предполагается наследоваться от CodeActivity и CodeActivity<T> для выполнения каких-то программных действий, либо от NativeActivity и NativeActivity<T>, если нужно как-то при этом взаимодействовать с Workflow Runtime. Generic-версии используются в том случае, если нужно вернуть какой-то результат заданного типа.

Блок, отвечающий за ожидание ответа клиента в течение недели выглядит так:

Ожидание ответа клиента в течение 7 дней

Тут я использовал стандартную Pick Activity для выбора одного из “направлений движения”. Их у меня всего два: либо клиент ответил, и тогда ничего делать не надо (анализируем новый статус как обычно), либо клиент НЕ ответил в установленный срок, и тогда закрываем тикет.

Кстати, для получения ответа клиента я использую ту же самую activity, что в самом начале, то есть, в моём случае, используется тот же самый WCF-метод. Что уже, в принципе, должно навести на мысли… ;)

Ну вот, а после получения тикета и записи лога (см. flowchart, первую картинку) всё стекается в блок Switch по полю Status тикета, который и решает, что мы должны делать дальше.

Казалось бы – должно работать! И если мы запустим проект и откроем любимый WcfTestClient.exe, то увидим, что оно и работает! Но если поиграться чуть дольше (или догадаться чуть раньше), то станет понятно, что работает оно неправильно.

Неправильно по двум причинам:

  1. Все Workflow, находящиеся в статусе отличном от Cancelled или Closed, висят в памяти неопределённое время (пока ресурсы не кончатся).
  2. Сколько бы мы ни пытались сказать, что тикет такой-то переходит из состояния WaitingForCustomer в любое другое – мы всё время попадаем в начальный блок “Receive And Update Ticket”, а не в тот, что находится в “Wait For Customer”. Иначе говоря, каждое обращение к методу у нас фактически активирует новый процесс, так как наш сервис не понимает, что это тот же самый тикет продолжает свой жизненный путь, а не просто новый “с неба свалился”. Таким образом, экземпляры всё копятся и копятся в памяти.

Самое время решить эти проблемы.

Первую решить довольно-таки просто и очевидно: воспользоваться стандартным persistence service, который уже есть в WF4. Сделаем так, что если workflow не активна, то она сохраняет себя в базе данных SQL Server и не занимает места в памяти и прочих ресурсов. Там, в базе, она может лежать годами, и никому от этого плохо не будет.
Для этого нам всего лишь нужно подготовить таблицы в БД, выполнив последовательно вот эти два (отмечены галочками, в том же порядке) скрипта:

Схема БД

Они создадут структуру таблиц и необходимые процедуры. Делать это можно в любой базе данных, например прямо в БД Вашего приложения, ничего там не сломается, просто добавятся новые таблички :)

Далее нужно просто пойти в web.config файл и прописать там следующие строки (понятное дело, строка подключения к БД у каждого своя):
Web.Config

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

Хорошо, что в .NET 4.0 всё, что только можно, уже прописано в “базовые” конфигурационные файлы :) Все конфигурационные файлы стали на порядок легче. Поэтому он уже “знает”, что такое эти два тега и может их использовать.

Со второй проблемой несколько сложнее.
Она ведь в чём состоит, проблема-то? Состоит она в том, что для обработки каждого тикета Workflow Runtime создаёт отдельный экземпляр workflow, но когда в метод ProcessTicket приходит “тот же самый” тикет, Workflow Runtime снова создаёт экземпляр, вместо того, чтобы использовать уже существующий.
Почему это происходит? Да потому, что Workflow Runtime просто не знает, что значит “тот же самый”. Как только она научится это знать – так сразу всё встанет “на свои места”.

Такой процесс “узнавания” называется “кореляцией” (correlation). Иными словами, мы должны провести кореляцию между нашим тикетом и экземпляром workflow.
Делается это тоже несложно: в Workflow для этого предусмотрен специальный тип переменной, называемый CorrelationHandle.

Так, как я использовал ReceiveAndSendReply Activity, то он создал мне такую переменную автоматически.
Я не буду тут отвлекаться на различные аспекты кореляции, (коих несколько, и есть дажа пара activities на данную тему), это отдельный разговор, здесь мы просто решим “насущную” задачу: укажем, что кореляция проводится по идентификатору тикета.

Для этого достаточно пойти в свойства Receive Activity, кликнуть там поле CorrelatesOn и указать нужный нам correlation handler (был создан автоматически, смотрите список переменных) и параметр для кореляции (Id):

Кореляция по полю Id 

В результате получится что-то такое:

Опять кореляция

Это означает, что когда в наш сервис в метод ProcessTicket приходит сообщение, то происходит его анализ по полю, указанному вот в этом вот XPath выражении, что было построено автоматически. Если значение этого выражения совпадает с каким-либо экземпляром workflow, то это экземпляр будет “поднят” из базы данных и это сообщение и будет обрабатываться именно этим экземпляром, что нам и нужно было сделать :)
Поэтому, когда в экземпляр, ждущий ответа от клиента, приходит такое сообщение, он продолжает свою работу именно с блока “Жду клиента”, а не попадает в начало процесса.

И, вроде бы, всё должно работать. И всё будет работать! :) И всё будет хорошо!

Но недолго. Кто знает, до каких пор? ;)

11/18/2009 9:52:42 PM

Интересно здесь. Не то, чтобы совсем, но неожиданно.

Майкрософт объявили направление: веб-приложения, которые (одинаково) доступны на лаптопах, десктопах и мобильных устройствах.
Основной платформой (по крайней мере для UI) объявлен Сильверлайт.

И вот тут начинается интересное, с анонса Silverlight 4.
Silverlight 4 содержит очень много замечательных вещей, начиная с drag-n-drop и заканчивая тем, что теперь он может работать вне пределов браузера, как нормальное приложение.
При этом его можно назначить trusted – и он может иметь доступ к железу, файловой системе, другим веб-сайтам и сервисам, да мало ли.
Например, внутри сильверлайта можно запускать всякие другие вещи. В качестве примера – adobe flash. Ребята запускали youtube на демо.

В общем, похоже, сильверлайт придётся осваивать.

P.S.
Сижу сейчас на секции, посвящённой будущему программирования. Докладчики – их пятеро – рассуждают.. о чём бы вы думали? О распараллеливании, о том, что в функциональных языках этих проблем нет и о том, как с этим быть :) Проблема серьёзно назрела.

11/17/2009 9:41:00 AM

Сегодня весь день слушал workshop по паттернам параллельного программирования.
Мероприятие состояло из трёх частей.

В первой части нам подробно рассказали зачем именно и в каком виде нужно “параллелить”. Какие бывают виды распараллеливания и т.п.
Это была самая сложная часть. В том плане, что я за ночь спал часа три только (а нечего было в самолёте высыпаться), только к утру уснул. Так что жутко хотелось спать. А так как о проблемах параллельности, мультиядерности и т.д. я уже много раз думал, и даже в этом блоге писал три года назад практически то же самое, что они сегодня говорили, то нового для меня в этой части было крайне мало, приходилось буквально заставлять себя держать глаза открытыми и открывать их, если всё же закрылись.

Хотя и из этой “философской” части несколько вещей показалось интересными:

  1. И Майкрософт, и Интел признают, что “затык” и проблема производительности сейчас лежит не на уровне “железа”, а на уровне софта. Представитель Майкрософт сказал прямо со сцены: виноваты мы с вами (все разработчики): мы просто не используем оптимально тех возможностей, которые даёт нам “железо”. А оно без проблем (и даже с меньшими затратами) может дать больше.
  2. Количество транзисторов в каком-нибудь Итаниуме отличается от количества транзисторов в Пентиум-4 примерно в 100 раз.
    Это значит, что вместо того, чтобы выпускать всякие Итаниумы на 2-4 ядра, Интел с тем же успехом и на том же количестве транзисторов мог (и может) выпустить процессор содержащий 100 ядер Пентиума-4. Про 80-ядерный процессор от Интел, впрочем, я тогда же писал.
    Если отвлечься от существующих проблем с софтом и вообразить, что мы можем их равномерно нагрузить – отдача во многом была бы куда лучше, чем от того Итаниума. Но такой процессор не выпускают потому, что мы сейчас не знаем, что с ним делать. Потому, что мы писали и продолжаем писать “однопоточный” софт. Поэтому Интел вынужден делать достаточно малое количество ядер (несколько-то потоков мы всё же делаем, да и несколько приложений одновременно запускаем), продолжая изголяться с частотой и другими параметрами.
  3. Но подвижки всё-таки есть: гибридные ядра вот уже появляются (это когда из четырёх ядер два “нормальные”, а ещё два состоят из микроядер, соотношение может быть 1:3 или 3:1, а могут и все 4 микроядерными быть). А это в свою очередь означает уже совсем другое количество потоков (посчитайте, по два на [микро]ядро хотя бы). Ну и количество ядер растёт – 8 есть, 16 ожидается.
  4. Софт, который пишется сейчас, скорее всего расчитывает продержаться на рынке пару-тройку лет. Даже с такими темпами роста прикиньте, то, что Вы пишете сейчас, способно ли эффективно использовать возможности процессоров, способных исполнять 128-256 нитей в параллели?
    Сколько Вы используете в своём приложении? Максимум три? Вам не кажется это смешным? То, что Ваше приложение будет точно так же тормозить на любой машине? Может пора перестать “изголяться” и пора начать думать и писать “нормально”? :)
    А ведь всё равно каждый, кто прочитает, через 10 минут откроет Visual Studio и продолжит клепать однопоточный код, подумал я. Ибо так проще и думать не надо. И это проблема.
  5. В Майкрософт серьёзно занимаются этой проблемой. Из тех примеров, что я помню: Visual Studio 2010 (которая сама написана на .NET с WPF-интерфейсом) очень активно использует Task Parallel Library (TPL), включёную в .NET 4.0 теперь. Это далеко не единственный пример был, просто я не проспал и запомнил :)

Да, про распараллеливание был ещё хороший пример приведён: докладчик показал последовательно три картинки. На первой был изображён молоток, на второй – воткнутый в доску гвоздь, на третьей – белка. И сказал замечательную фразу: “Когда у Вас в руках молоток, всё вокруг кажется гвоздём. Но не с точки зрения белки.” :)
Сказал он это к тому, что “мы дадим вам молоток, в виде TPL, OpenMP, F# с его immutable типами и т.д, но пользоваться им надо тогда, когда это имеет смысл и так, как это имеет смысл делать”.
По-русски это можно перевести как “дурная голова ногам покоя не даёт” и сказать, что броситься и заменить во всём приложении for на Parallel.For, а IEnumerable на IEnumerable.AsParallel() и “с чистой совестью” думать, что задачи распараллеливания выполнены – глупо.

Вторая часть была гораздо более интересной. Она была дивелоперской.
Человек, который непосредственно из команды разработки TPL, сделал отличный доклад, практически не имея слайдов презентации. Вместо этого он просто открыл Visual Studio и показывал, как делать нужно, как можно, как не нужно, что работает, что нет… Отлично объяснял почему именно и как оно работает, отвечал на вопросы, иллюстрируя ответы тут же кодом, запуская его и демонстрируя результат.
Мне понравилось.
Так, как тема была “паттерны параллельного программирования”, он объяснил, какие паттерны используются при разработке таких приложений, что эти паттерны из себя представляют, как они реализованы в TPL и как пользоваться этой реализацией.

Книжку по этим паттернам можно свободно скачать вот тут: http://www.microsoft.com/downloads/details.aspx?FamilyID=86b3d32b-ad26-4bb8-a3ae-c1637026c3ee&displaylang=en

Третья часть была посвящена Microsoft Windows HPC.
Мне она показалась малоинтересной, за исключением того, что я вообще узнал, что у Майкрософт есть такая версия системы, как HPC. Более того, ожидается вторая версия.
HPC – это аббревиатура от High Performance Computing, а операционная система расчитана на кластеры с большим количеством нод. Текущая версия поддерживает до 256 машин в кластере (я так понял, что не важно, сколько у каждой сокетов и ядер), вторая версия (R2 они теперь взяли моду всё называть) будет поддерживать толи тысячу, толи тысячи, я не понял. Но это всё равно много.
Оттуда можно WCF-сервисы “наружу” выставлять, обработка будет вестись на кластере (или куске кластера, как захочется). И они там тоже использовали те же паттерны параллельного программирования, хотя и без использования TPL, а гораздо на более низком уровне.

Это был просто workshop. Завтра начинается PDC.
Looking Forward.

P.S. Лос Анджелес удивил. Ладно мне коллега и босс говорили, что опасный город, я думал – австралы, не местные, побаиваются. Но когда сегодня обедал с одним местным, он открыл карту метро, провёл пальцем по половине города и сказал: “сюда вообще не надо ездить и выходить на этих станциях”… И потом когда тебе говорят “я в ЛА не использую общественный транспорт, у меня семья, дети, работа, я перемещаюсь или на машине или на такси” – это уже не просто настораживает ;)

11/11/2009 1:48:00 PM

В нашем проекте мы используем Entity Framework. Разумеется в первой, существующей ипостаси. Штука эта интересная и мощная, но имеет несколько существенных недостатков и неудобностей, среди которых и необходимость наследования всех классов от базового класса EF, и невозможность избавиться от Navigational Properties, и полное отсутствие контроля над поведением (да и интерфейсом) сгенерированных классов, и невозможность юнит-тестирования…

И если с классами немного удалось сладить, написав собственную утилиту-генератор, то вот всё остальное – просто беда. Да, существует такая штука, как TypeMock для юнит-тестирования, но во-первых, она платная для коммерческого использования, а во-вторых, работает через profiling API… Но хоть что-то.

В общем, поскольку нам была обещана приватная встреча с двумя ведущими разработчиками Entity Framework, я решил посмотреть немного, что обещается в следующей версии.

Очень приятным моментом для меня стало то, что Navigational Properties теперь из модели можно просто выкинуть.
Обратите внимание на скриншот: в классе Member нет свойства Member_Properties, в классе Member_Properties нет свойства Member. Это я их удалил :) При этом EF по-прежнему знает о связи этих двух сущностей и даже отображает её в дизайнере.

Navigational Properties можно удалить

Ещё одна приятная мелочь: “нормальные” ID-поля для ключей. Смотрите на Member_Addresses, свойства MemberId и AddressId - “обычные” int-свойства. Navigational Properties для Address и Member тоже есть, я их просто не удалял.

Вторым очень приятным моментом стала поддержка “обычных” классов. “POCO-классов”, как теперь модно говорить. POCO – это “Plain Old CLR Object”. То есть, в качестве entity теперь может выступать класс, не унаследованный от “специального” базового класса.
Это очень, очень, очень здорово!

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

Add Code Generation Item

Таких генераторов для модели можно иметь столько, сколько захочется и генерировать совершенно разные вещи.
Я в своём тестовом проекте просто удалил .designer.cs файл тестовой модели и отключил в свойствах .edmx-файла регенерацию. То есть, .edmx-файл теперь для меня просто описывает модель, которая может быть обновлена из БД, содержит все маппинги и т.д, но не генерирует сама по себе никаких .NET-классов.

Вместо этого я добавил Generation Item, который делает всю эту работу. Этот Generation Item представляет собой обычный .tt-файл, то есть, тот самый обычный темплейт, который существует в Visual Studio ещё с 2005-й версии, но о котором мало кто знает :) темплейт представляет собой простой текстовый файл, в котором на простом и понятном языке (например C#) просто и понятно описывается, как и что должно быть сгенерировано.
Вот, их даже два в моём проекте:

Templates Template file

Я не писал эти темплейты с нуля, но редактировать файл темплейта, например, дописать туда что-то нужное или убить что-то ненужное, очень легко, никаких особых знаний для этого не требуется.

В моём случае первый файл генерирует, собственно, контекст и всё, что с ним связано. Второй – сами entities.

Результат работы темплейтов Сгенерированный класс

При этом Entities, как я уже сказал, можно делать POCO-классами и, например, метить их DataContract/DataMember атрибутами, что позволяет использовать их в WCF и избежать часто ненужного маппинга между DTO и Entities. По сути мы имеем возможность сразу из БД получить нужные нам бизнес-объекты и DTO, что тоже очень здорово и очень облегчает жизнь.

Я уже сказал, что темплейты очень легко переделать на свой лад, чтобы они генерировали то, что нужно. Контроль над генерацией и возможность сгенерировать так, как нужно – важная вещь.
Генерируя те же entities можно ещё каких-то атрибутов навесить, или реализовать геттеры-сеттеры так, как хочется, или переопределить ToString(), или ещё методов добавить…

Я вот, задумавшишь о тестировании, добавил несколько строк в темплейт, чтобы он генерировал мне тот самый “TestModel.Context.Interfaces.cs”, который видно на картинке. Изначально его не было.
В этом файле я просто определяю интерфейс для контекста. Ну, ещё я поправил, чтобы класс контекста реализовал этот интерфейс, дописав “, ITestDbEntities” в сигнатуру класса :) 
Этот интерфейс будет используется при юнит-тестировании.

Интерфейс, он простой, смотреть сюда незачем

Предыдущая версия EF использовала в контексте некий класс EntitySet<>, который был абсолютно неудобен в случае юнит-тестирования, новая версия использует ObjectSet<>, который реализует интерфейс IObjectSet<>. А если есть интерфейс – значит можно делать мок! А раз можно делать мок – значит можно писать юнит-тесты!
То, что надо!

Да, нужно отметить, что каждый раз, когда меняется темплейт или меняется .edmx-файл модели, все относящиеся к ней темплейты перегенерируют то, что они там генерируют. То есть, следить за этим совершенно не надо.
Вы просто меняете то, что хотите поменять, остальное делается “само”: обновляются классы бизнес-модели, DTO, возможно классы менеджеров с примитивными методами типа LoadById, Save, какие-то рутинные классы преобразований и хелперов и т.д, и т.п.

Надо будет посмотреть на это дело поближе.

7/24/2009 5:59:00 AM

Прислали ссылку: http://habrahabr.ru/blogs/silverlight/65191/

Почитал новость, потом комментарии к оной.
Самое смешное это, конечно, как всегда комментарии линуксоидов. “Я отнюдь не за распространение этой технологии”, как красиво и смешно сказано! Отож, призрак Microsoft маячит за “технологией”, ничего, что mono-ребята реализовывали всё open source и с нуля по спецификациям. И призрак этот ну просто откровенно мешает людям жить! Поэтому технологию, конечно, распространять не надо.
Смешно.

Причем проблемы себе создают сами.
- Попробуйте установить мунлайт? Работает.
- Какой дистрибутив, какой репозиторий?

Ужас. То, что в цивилизованном мире делается совершенно неподготовленным пользователем с помощью одного клика по большому баннеру “сильверлайт”, в однопроцентном мире требует знания понятий “дистрибутив”, “репозиторий”, понимания разницы между различными репозиториями и т.д. Ужас.

По-моему же проблема ситуация формулируется гораздо проще даже безо всяких допущений, сгребём всех в одну коробку: не работает на одном проценте клиентских машин, у пользователей которые всё равно параллельно установлена виндовс в качестве операционной системы, куда они и переключаются, устав от бесконечного “администрирования” (ух, Линукс настроил, а что с ним дальше делать?) для решения реальных задач (от “поиграть” до “курсовик допинать”).
Решение проблемы ситуации: да и хрен с ними! :) У кого заработает (как они говорят “руки из того места растут”) – хорошо, остальные – хрен с ними. Ибо их всё равно в разы меньше чем тех, кто тупо отключает Javascript в браузерах. Статистически, а статистика - вещь упрямая. Поэтому глупо притягивать за уши HTML5+JS к Сильвер/Мунлайту.

P.S. Про призрак. Недавно прочитал, MS планирует опубликовать в основную ветку ядра Линукса несколько тысяч строк кода различных дополнений. Интересно, эти чистые душою и идеологией люди перестанут пользоваться некошерной и осквернённой веткой ядра? :)

P.P.S. Поставил Silverlight 3 на Mac OS X. Просто, ради посмотреть, как оно там живёт. Живёт оно точно так же: нажал кнопарь – установилось. Отлично показываются видеоролики и всё остальное. Про “репозиторий” и “дистрибутив” меня никто не спросил. Всё просто работает. И, что показательно, выбор между HTML5+JS и сильверлайтом делать не заставляют.
Бедные однопроцентники, даже жалко их :) Мыши плакали, кололись, но продолжали есть кактус, не иначе…

Powered by BlogEngine.NET 1.6.0.0

About the author

Alexey Raga Alexey Raga
.NET software developer.

E-mail me Send mail

Twitter


Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

Sign in