Saturday, April 24, 2010

Компилируем ASP.NET Dynamic Data MVC Preview для работы с MVC 2

Давайте сегодня скачаем и разберём превью Dynamic Data для MVC. Хотя этому превью уже скоро стукнет два года, мы попробуем им воспользоваться. К сожалению, эта библиотека работает только с MVC версии 1, но у нас же есть исходный код, поэтому мы, как настоящие индейцы, попробуем подружить этот код с MVC 2.


Открываем скаченный солюшен (я это делаю в VS 2008 Professional), и сразу видим, что проект BlogSamle внутри него отрываться не станет, поскольку он зависит от первой версии MVC. Нам, если честно, он не очень интересен, поскольку блог — не лучшая иллюстрация приложения, которому действительно нужен скафолдинг. Зато открывается проект, содержащий исходный код DynamicData for MVC.

При попытке скомпилировать этот код, мы получим несколько ошибок, связанных с отсутствием полной обратной совместимости кода под MVC1 и MVC2. Попробуем их как-нибудь исправить. Честно говоря, я не уверен, что предложенные мною исправления жизнеспособны и не приведут к ошибкам во время выполнения, но мы всё-равно попробуем :)


Начнём с ошибок в DynamicFieldExtensions.cs и DynamicEntityExtensions.cs. Конструктору ViewContext нужно теперь не 4, а 5 аргументов. Теперь в него нужно передавать ещё и TextWriter. Для DynamicFieldExtensions возьмём его строкой ниже из параметров result.View.Render(), а именно второй параметр html.ViewContext.HttpContext.Response.Output. Адекватность этого шага у меня вызывает некоторые подозрения, но должно сработать. Для DynamicEntityExtensions возьмём его из response.Output.

Осталось две ошибки в DynamicDataModelBinder.cs. Разработчики решили упразднить метод TryGetValue из ModelBindingContext.ValueProvider. Мотивы их поступка остаются загадкой, но в ValueProvider остался метод GetValue(). Смею предположить, что он всегда что-нибудь да возвращает и не выбрасывает исключения, в связи с чем необходимость в Try-методе отпала. Поэтому мы уберём условный оператор, и напишем:
// для первой ошибки
vpr = context.
         ValueProvider.
         GetValue(GetFieldName(context,
                          column.Name));

vpr = context.ValueProvider.GetValue(fieldName);
// для второй

Возможно, GetValue всё-таки выбрасывает эксепшен, поэтому, если хотите, оберните всё в try-catch блок, но я пока этого делать не буду — сделаю, если появятся исключения.

Теперь попробуем избавиться от зависимости от старых реализаций System.Web.DynamicData и System.ComponentModel.DataAnnotations. Опять же не гарантирую работоспособность исправления, поэтому можно оставить те библиотеки, что поставляются вместе с Dynamic Data MVC Preview (в папке CommonFiles). Если чего не заработает, то всё вернём, а пока удаляем ссылки на эти библиотеки в References и добавляем вместо них более свежие. Из-за этого код перестанет компилироваться, поскольку «'System.Web.DynamicData.MetaTable' does not contain a definition for 'TryGetTable'» в DynamicDataModelBinder. Мы заменим весь условный оператор на нижеследующее:

if (!MetaModel.Default.TryGetTable(
     bindingContext.ModelType.FullName,
     out table)) 
{
    return defaultBinder.
              BindModel(controllerContext,
                        bindingContext);
}

Поскольку класс MetaTable лишился метода TryGetTable, мы попытаемся получить таблицу с помощью того же метода, но уже через MetaModel.Default.TryGetTable.

Отлично. Теперь всё компилируется. Если смущают два оставшихся варнинга в DynamicFieldForeignKeyUserControl и DynamicFieldChildrenUserControl, то просто поменяйте модификаторы свойства Model на public.

No comments:

Post a Comment