-->

пятница, 27 мая 2016 г.

Кэширование в Entity Framework

Встроенные возможности

Как многим давно известно из этой замечательной статьи, в средствами Entity Framework кэшируются следующие объекты:
  1. Планы выполнения запросов; 
  2. Метаданные;
  3. Скомпилированные запросы.
Можно ли контролировать этот кэш? Увы, кэширование планов можно отключить при помощи ObjectQuery.EnablePlanCaching, а более тонкие настройки (размер хранилища, expiration policy) - недоступны.
Есть в EF и кэш данных, известный многим: в пределах одного DbContext с доступом через метод Find, что весьма ограничивает возможности его применения. Да и управлять этим кэшем напрямую - по-прежнему невозможно.

Сторонний кэш данных

К счастью в Entity Framework есть возможность использования стороннего кэша для полученных из БД данных (second level cache). И как мы видим из этой статьи, подключить кэш данных не так уж и сложно. А еще проще использовать уже существующий проект, коих немало:

EntityFramework-Plus
NCache
EntityFramework.Cache

Есть, из чего выбрать!

понедельник, 22 февраля 2016 г.

Тестирование WCF через SoapUI

Обращение через SoapUI к веб-сервису WCF с привязкой WSHttpBinding и авторизацией оказалось не самой очевидной задачей. Вот привязка:
<wsHttpBinding>
   <binding name="FooBinding" >
      <security mode="TransportWithMessageCredential">
         <transport clientCredentialType="None"> </transport>
         <message clientCredentialType="UserName"
                        algorithmSuite="Default"
                        negotiateServiceCredential="false"
                        establishSecurityContext="false"/>
      </security>
   </binding>
</wsHttpBinding>

Прежде всего создаем SOAP-проект и скармливаем ему WSDL. Открываем созданный SOAP Request для нужного метода. Добавляем авторизацию HTTP Basic:

 Там же включаем WS-A Adressing:


В свойствах запроса устанавливаем WSS-Password Type: Password Text:


А в настройках SoapUI (Tools -> Preferences -> HTTP Settings) ставим
Authenticate Preemptively: true.


Этого должно быть достаточно, чтобы обращение к веб-сервису было успешным.

Полезные советы:
1. В SoapUI любой элемент от реквеста до проекта можно склонировать.

2. Для задания логина/пароля и любых других свойств на уровне проекта достаточно создать для проекта Custom Property, к примеру PASSWORD. Обращение к свойству:
${#Project#PASSWORD}
Вбиваем в поле Password вкладки Auth, и готово!

3. Формат проекта SoapUI - обычный XML-файл. К примеру тот же самый пароль сохраняется в проекте как plain text, пригодный для редактирования через Find/Replace. Только не забудьте после сохранения файла во внешнем редакторе перезагрузить проект в SoapUI через клавишу F5.



понедельник, 15 февраля 2016 г.

Снятие бэкапа TeamCity через PowerShell

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

Простейший способ получить резервную копию содержимого сервера TeamCity - это зайти в админке в Administration - Backup, указать, что мы собираемся копировать и нажать Start Backup. В зависимости от количества билд-конфигураций, упаковка файла может занять несколько минут, а результат работы будет сохранен в указанную папку на сервере TeamCity.
К сожалению, этот билд-сервер не предоставляет "из коробки" функциональности по автоматизации снятия бэкапа. Поискав в сети, конечно же я наткнулся на широко известный PowerShell-скрипт от Ivan Leonenko, позволяющий запустить бэкапирование удаленно посредством отправки HTTP POST-запроса.

Вместо того, чтобы складывать бэкапы на той же машине, где развернут TeamCity (что совершенно неправильно) и писать службу по их миграции в надежное хранилище, мы решили сразу получать файл в свое распоряжение. Для получения файла достаточно GET-ом с той же авторизацией обратиться по адресу:
{server}/get/file/backup/{filename}
поэтому наша доработка скрипта Ivan'a свелась к периодическому опросу этого URL и скачиванию файла (как подписаться на событие "бэкап готов" даже смотреть не стали).

Готовый скрипт на GitHub. Остается настроить периодический запуск скрипта через любой планировщик задач, и файлы с бэкапами начнут поступать в ваше распоряжение. Если собираетесь делать через SQL Server Agent - прочитайте предыдущую заметку, поскольку у агента свои причуды выполнения PowerShell-скриптов.

Кстати, скачать файл через PowerShell несложно, достаточно использовать командлет Invoke-WebRequest:

function Save-FileFromWeb()
{
param(
[string] $url,
[string] $username,
[string] $password,
[string] $targetFile
)
$authInfo = $username + ":" + $password
$authInfo = [System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($authInfo))
$Headers = @{ Authorization = "Basic $authInfo" }
Invoke-WebRequest -Uri $url -Headers $Headers -OutFile $targetFile
}

понедельник, 8 февраля 2016 г.

Бэкап БД SQL Server по-расписанию через PowerShell и SQL Server Agent job

Задача: автоматизировать снятие BACPAC пакета с базы данных SQL Server (для Azure SQL Database тоже работает). Напомню, BACPAC не содержит transaction log, соответственно для point-in-time restore не подойдет. В нашем случае нужен для быстрого развертывания "по требованию" копии базы с нужными данными, для проведения интеграционного тестирования.

Идеальным решением оказался скрипт на PowerShell. Код простейший, я взял гуляющую по интернету версию (к сожалению, ссылка на исходный скрипт затерялась) и немного ее доработал в нужную сторону. Создание бэкапа выполняется следующими командлетами:

$Services = new-object Microsoft.SqlServer.Dac.DacServices $ConnectionString
$Services.ExportBacpac($OutputFile, $DatabaseName)

Есть полный работоспособный пример на GitHub.  Для работы необходим PowerShell 3.0+ и Microsoft® SQL Server® Data-Tier Application Framework, желательно последней версии. На х64 машине необходимо установить как х86, так и х64 версию данной библиотеки.

Куда больше времени пришлось потратить на запуск скрипта через SQL Server Agent, когда я решил автоматизировать создание пакета с помощью периодически выполняемой задачи (job). Как оказалось, SQL Server  может использовать различные версии powershell для выполнения скрипта, в зависимости от версии самого SQL Server и step type у нашей задачи. Вообще говоря, выполнить PowerShell от лица SQL Server Agent возможно из нескольких типов шагов:
  • Operating System (CmdExec)
  • Powershell
Вот здесь есть таблица зависимости версий. Например, SQL Server 2012 с типом шага "Powershell" будут использовать PowerShell версии 2.0, что приведет к ошибке выполнения скрипта (нужен 3.0+). Независимо от наличия более свежих версий PS.
Сразу приведу workaround: для успешного выполнения Powershell скрипта через агента SQL Server 2012-2014 необходим шаг Operating System (CmdExec) со следующей командой:

powershell.exe -version 3.0 -ExecutionPolicy Bypass -file "C:\yourscript.ps1"

вторник, 2 февраля 2016 г.

Подменяем DbContext, изолируем базу данных для тестирования

Многие, использующие Entity Framework сталкиваются с проблемой изоляции внешних зависимостей (в данном случае БД) при написании юнит-тестов. В этом примере я покажу, как подменить DbContext прозрачно для вызывающего кода, и заполнить поддельный DbSet тестовыми данными. Такой прием полезен для тестирования кода доступа к данным в изоляции от БД. Актуально для Entity Framework 6.

Мы будем тестировать популярный паттерн: некий класс-"репозиторий", инкапсулирующий в себе запрос к DbSet, транслируемый в запрос к базе данных:
public class ReportRepository
{
 [Inject]
 public IContextFactory ContextFactory { getset; }
 
 public List<Report> GetReports()
 {
  using (var context = new FooContext())
  {
   return context.Reports.ToList();
  }
 }
}
Этот код не назовешь слабосвязанным, так как присутствует зависимость от конкретной реализации контекста - класса FooContext. Нам необходимо в первую очередь избавиться от этой зависимости. Для этого модифицируем наш контекст, выделив необходимые методы и свойства в интерфейс (например, путем модификации шаблонов T4, генерирующих контекст):
public partial class FooContext : DbContextIFooContext
{
 public IDbSet<Report> Reports { getset; }
}
Однако, класс-репозиторий сам управляет временем жизни контекста, поэтому прямое внедрение интерфейса не подходит. Вместо этого, используем паттерн "абстрактная фабрика" (все подробности - в известной книге "Dependency Injection on .NET", сейчас практически стандарту по DI в дотнете). Итак, наша фабрика будет создавать новые экземпляры контекста:
public class ContextFactory : IContextFactory
{
 public IFooContext Create()
 {
  return new FooContext();
 } 
}
Внедрим фабрику в "репозиторий":
public class ReportRepository
{
 [Inject]
 public IContextFactory ContextFactory { getset; }
 
 public List<Report> GetReports()
 {
  using (var context = ContextFactory.Create())
  {
   return context.Reports.ToList();
  }
 }
}
Теперь использующий контекст не знает ничего о конкретной реализации контекста. Осталось только сконфигурировать наш DI контейнер (здесь и далее используется Ninject):
public class AppModule : NinjectModule
{
 public override void Load()
 {
  Bind<IContextFactory>().To<ContextFactory>();
 }
}
Самое время выполнить интеграционный тест, запрашивающий данные из реальной БД:
[Test]
public void RealRepository_WhenCalled_ReturnsEmpty()
{
 var kernel = new StandardKernel();
 kernel.Load<AppModule>();
 
 var repo = kernel.Get<ReportRepository>();
 
 var reports = repo.GetReports();
 
 Assert.IsEmpty(reports);
}

Переходим непосредственно к подмене контекста. Для этого нам понадобится еще один модуль Ninject, который достаточно создать в проекте с изолированными от БД тестами:
public class MockModule : NinjectModule
{
 public override void Load()
 {
  Rebind<IContextFactory>().To<MockContextFactory>();
 }
}
Для создания поддельных объектов используется фреймворк Moq. Обратите внимание на реализацию MockContextFactory: вся хитрость - в методе MockDbSet<T>, который создает мок-объект, реализующий IQueryable<T>:
public class MockContextFactory : IContextFactory
{
 public IFooContext Create()
 {
  var mockRepository = new MockRepository(MockBehavior.Default);
 
  var mockContext = mockRepository.Create<IFooContext>();
 
  mockContext.Setup(x => x.SaveChanges())
   .Returns(int.MaxValue);
 
  List<Report> mockReports = MockReports();
 
  var mockDbSet = MockDbSet<Report>(mockReports);
 
  mockContext.Setup(m => m.Reports).Returns(mockDbSet.Object);
 
  return mockContext.Object;
 }
 
 private List<Report> MockReports()
 {
  List<Report> mockReports = new List<Report>();
 
  mockReports.Add(new Report {Id = 1, Name = "Mock Report #1"});
 
  return mockReports;
 }
 
 private Mock<DbSet<T>> MockDbSet<T>(List<T> data = nullwhere T : class
 {
  if (data == null) data = new List<T>();
 
  var queryable = data.AsQueryable();
 
  var mock = new Mock<DbSet<T>>();
 
  mock.As<IQueryable<T>>().Setup(m => m.Provider)
   .Returns(queryable.Provider);
  mock.As<IQueryable<T>>().Setup(m => m.Expression)
   .Returns(queryable.Expression);
  mock.As<IQueryable<T>>().Setup(m => m.ElementType)
   .Returns(queryable.ElementType);
  mock.As<IQueryable<T>>().Setup(m => m.GetEnumerator())
   .Returns(queryable.GetEnumerator());
 
  return mock;
 }
}
Этого достаточно! Мы можем обращаться к поддельному DbSet, получать тестовые данные через LINQ, при этом подмена контекста останется незамеченной для использующего контекст кода. Для проверки напишем еще один тест:
[Test]
public void RealRepository_WhenCalled_ReturnsMockData()
{
 var kernel = new StandardKernel();
 kernel.Load<AppModule>();
 //Order is important. In MockModule we rebind IContextFactory.
 //Another option is to load MockModule only.
 kernel.Load<MockModule>(); 
 
 var repo = kernel.Get<ReportRepository>();
 
 var reports = repo.GetReports();
 
 Assert.IsNotEmpty(reports);
}

Данный способ - не 100% пацея и побочные эффекты могут возникнуть, поскольку в LINQ-запросе к DbSet будет использоваться LINQ to Objects, а не LINQ to Entities.
Полный пример для EF6 + SQL Server доступен на GitHub.

понедельник, 1 февраля 2016 г.

Логируем метод вместе с аргументами при помощи аспектов и DI

Очередной совет из серии "хорошо за 5 минут" - логируем вызов метода вместе со списком и значениями входных параметров!

Пусть будет для примера старинный ASMX клиент:
public partial class LegacyClient : System.ServiceModel.ClientBase<Legacy>, Legacy
у которого большое количество методов, переплетенных в причудливые макаронины вместе с остальным кодом. Писать свою обертку долго и больно, а логировать вызовы надо. Будем делать на аспектах с помощью DI-контейнера! В данном примере - Ninject. Конкретный контейнер не так важен. Важно, поддерживает ли он "перехватчики" - interceptors. На том, что такое Dependency Injection и DI-контейнеры - останавливаться не буду, все уже жевано-пережевано до меня.

Поехали, выделяем интерфейс с нужными методами (R# спешит на помощь):
public partial class LegacyClient : ILegacyClient {}
В конфиге контейнера указываем наш interceptor:
Kernel.Bind(typeof(ILegacyClient))
    .To<LegacyClient>()
    .Intercept()
    .With<LogRequestInterceptor>();
А вот и реализация interceptor'а:
using Ninject;
using Ninject.Extensions.Interception;

public class LogRequestInterceptor : IInterceptor 
{
    public void Intercept(IInvocation invocation)
    {
        MethodInfo method = invocation.Request.Method;

        var parameters = method.GetParameters();

        var builder = new StringBuilder();

        for (int index = 0; index < parameters.Length; index++)
        {
            object argument = invocation.Request.Arguments[index];

            ParameterInfo parameterInfo = parameters[index];

            if (!parameterInfo.IsOut)
            {
                //use any serialization you like
                string text = $"{parameterInfo.Name} = {argument.ToJson()}, ";

                builder.Append(text);
            }
        }

        string joinedParameters = builder.ToString();

        YourLogging(method.Name, joinedParameters); 

        //LegacyClient method call
        invocation.Proceed();
    }
}
Дополнительно к нашему "перехватчику" необходимо реализовать сериализацию аргументов метода (я предпочитаю JSON).

Получение объекта с дополнительными аспектами ничем не отличается от обычного resolve'а с помощью DI:
ILegacyClient client = Kernel.GetService<ILegacyClient>();
client.AnyMethodCall(...);
Самое важное в этом примере - мы не меняем интерфейс класса LegacyClient, поэтому вызывающий методы данного класса код остается нетронутым, и измениться не может в принципе. Необходимо лишь изменить способ создания объекта, что зачастую является куда менее трудоемкой задачей, чем написание прокси-класса. На этом всё, побольше удачи и поменьше рутины!




понедельник, 25 января 2016 г.

Пишем простейший плагин для ReSharper

Многие знают, что ReSharper, помимо собственной логики, предоставляет возможности для ее дальнейшего расширения с помощью плагинов. Разработка расширений осуществляется с помощью ReSharper SDK - официального набора инструментов и библиотек от JetBrains. Довелось мне использовать данную технологию, и было это непросто, скажу я вам. Несмотря на высокое качество официальной документации, она все же не в состоянии объять необъятное. API библиотек зачастую неочевиден, а гайдов и мануалов от сторонних исследователей в сети очень мало, да и те устаревают с выходом каждой следующей мажорной версии. Искать нужную информацию на русском языке практически бесполезно, по моему опыту. Плагинов написано немного, и всенародной популярностью вряд ли пользуется хоть один - наверняка не последнюю роль в этом сыграл огромный и самодостаточный набор фич самого ReSharper, да еще и растущий с каждым релизом.

В итоге, когда я решил поделиться накопленными знаниями с общественностью, материала с лихвой хватило для размещения на habrahabr.ru:


На данный момент это единственный известный мне актуальный материал на русском языке (да и на английском тоже - остальное устарело), освещающий полный цикл разработки и тестирования простейшего плагина-расширения ReSharper.

Краткое содержание:
  1. Настройка среды разработки
  2. Пример №1: простейшее расширение-заглушка
  3. Установка плагина
  4. Отладка, полезные советы
  5. Пример №2: модификация кода с помощью R# API
  6. Функциональное тестирование плагинов средствами R# API
Выстраиваемое ReSharper синтаксическое дерево - уникальная технология, позволяющая творить невероятные вещи с кодом. Желаю этому продукту дальнейшего развития, больше полезных плагинов, и конечно же - больше интересных публикаций! 

пятница, 22 января 2016 г.

Запускаем исполняемые файлы через PowerShell. Боли нет.

Часто ли вам приходится запускать исполняемые файлы с десятком-другим параметров? Например:
"C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" ^ -source:package='long\way\to\package\foo.zip' ^
-dest:auto,computerName="https://another-app.scm.azurewebsites.net/msdeploy.axd?site=aaa",userName="bbb",password="ccc7",authtype="basic",includeAcls="False" ^
-verb:sync ^
-setParamFile:"long\way\to\package\foo.SetParameters.xml" ^
-AllowUntrusted ^
-setParam:"IIS Web Application Name"=homesweethome ^
-verbose
Если мне предстоит запустить подобного монстра более 2 раз за всю свою жизнь, я пишу скрипт на PowerShell, который сформирует список параметров, соединит список в результирующую строку, выполнит команду, да и еще поделится со со мной полезной отладочной информацией. Будь то шаг развертывания приложения через билд-сервер, запуск какой-либо тестовой утилиты - подобный подход в сочетании с системой управления версиями снижает сложность разработки и поддержки на порядки.

Начнем с того, что PowerShell предлагает различные способы запуска исполняемых файлов, такие как:
  • оператор &
  • Start-Process
  • Invoke-Expression
  • Start-Executable 
Приведу пример вызова Start-Process, т.к. обычно использую этот командлет:

Start-Process $msdeploy_exe -ArgumentList $params -NoNewWindow -Wait

Видите? Всё просто! А если список параметров собрать, используя знакомый любому .NET разработчику класс List<T>, то и код будет понятен любому коллеге (я надеюсь):

$list = New-Object -TypeName "System.Collections.Generic.List[string]"
 
$dest_template = '-dest:auto,computerName="https://{0}.scm.azurewebsites.net/msdeploy.axd?site={0}",userName="aaa",password="bbb",authtype="basic",includeAcls="False"'
 
$list.Add([string]::Format($dest_template, $web_url))
$list.Add([string]::Format("-source:package={0}", $package_path))
$list.Add([string]::Format("-setParamFile:{0}", $setparameters_path))
$list.Add([string]::Format("-setParam:'IIS Web Application Name'={0}", $web_url))
$list.Add("-verbose")
$list.Add("-verb:sync")
$list.Add("-AllowUntrusted")
 
# ensure space between params
$params = [string]::Join(" ", $list)

Да, интеграция со всей платформой .NET Framework - это неоспоримый плюс PowerShell-скриптов! По сравнению с первоначальным вариантом, читабельность и легкость сопровождения повысились в разы! На этом я заканчиваю пятиминутку в стиле Капитана Очевидность, и желаю всем поменьше рутины и побольше интересных задач!


понедельник, 18 января 2016 г.

Visual Studio 2015 и кириллица

Проблема: Visual Studio 2015 некорректно отображает кириллические комментарии в коде, заменяя их на "кракозябры" вида Äæèãóðäà. При этом в Visual Studio 2013 комментарии отображаются нормально. Дискуссия о пользе и вреде кириллицы в комментариях стоит отдельного поста, а сейчас я бы хотел описать способ решения данной проблемы, который сработал для нашей небольшой команды.

Прежде всего, в глаза бросилось то, что "пораженные" файлы с присутствием кириллицы сохранены в кодировке Windows-1251, тогда как вся остальная часть проекта - в UTF-8. А "кракозябры" возникают потому, что Visual Studio читает файл, ранее сохраненный в кодировке Windows-1251 как файл в кодировке Windows-1252 (Western European). Этот баг достаточно просто эмулировать в Notepad++:

  1. Создаем новый файл, пишем кириллический текст;
  2. Устанавливаем кодировку в Windows-1251: Encoding - Character sets - Cyrillic - Windows-1251;
  3. Сохраняем и закрываем файл;
  4. Вновь открываем файл;
  5. Устанавливаем кодировку в Windows-1252: Encoding - Character sets - Western European - Windows-1251;
Вот так привычное русское "Джигурда" превращается в загадочное "Äæèãóðäà". Отсюда вытекает первый способ решения проблемы: ручная или программная конвертация пораженных файлов в UTF-8. Что малопригодно для больших проектов, поэтому сразу перейду к следующим способам:
  • Оказывается, в компиляторе VS2015 есть баг, связанный с кодировкой, для его устранения необходимо установить Visual Studio 2015 Update 1 (доступен в Extentions and Updates). Пруф: https://github.com/dotnet/roslyn/issues/4022
  • Студия по-умолчанию использует настройки ОС для решения проблем с кодировкой. Необходимо настроить Windows: для русскоязычной версии (о ужас) идем «Языки и рег. стандарты - Дополнительно - Изменить язык системы» и устанавливаем русский язык.
Вышеописанных двух действий оказалось достаточно, чтобы полностью устранить проблему с кодировкой внутри команды, при этом на некоторых компьютерах с уже установленным сервис-паком баг не наблюдался вовсе, У нас даже остался неиспользованный туз в рукаве: установка расширения ForceUTF8, позволяющего принудительно сохранять в UTF-8 файлы, редактируемые Visual Studio. К сожалению, в штатном функционале Студии такая настройка отсутствует, да и перед использованием этого расширения пораженные Windows-1251 файлы придется перекодировать самостоятельно.

(Бес)полезная информация:
  • Visual Studio позволяет вручную задать кодировку для сохраняемого файла через Save As - Save with Encoding (жмем на стрелочку возле клавиши Save);
  • Есть настройка Options - Environment - Documents - Save documents in Unicode when data cannot be saved in codepage. Пользы от нее не замечено.
На этом на сегодня всё, да не коснутся вас проблемы с кодировкой!

понедельник, 11 января 2016 г.

Подсветка и форматирование кода на веб-страницах за 5 минут

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

Начну с насущной задачи: в ходе работы над очередным проектом (MVC 6, кстати) потребовалось "красиво" подсветить (highlight) выводимый посредством razor view кусок кода на языках XML/HTML. Как вы оцените трудозатраты на подобное решение? Поиск нужной библиотеки, интеграция, тестирование? На самом деле, работающий прототип можно получить уже через минуту.
Размещаем на странице код (интерпретируемый как текст, естественно) внутри тега <pre class="prettyprint"></pre>, рядом размещаем скрипт:
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
Всё! Несколько строк кода, и подсветка кода работает! google/code-prettify определяет язык автоматически и содержит правила для большинства популярных языков, в том числе C family, SQL, CSS и еще несколько десятков других. Все подробности - в публичном репозитории https://github.com/google/code-prettify.
Конечно же, данная библиотека доступна для скачивания и установки, как в традиционном для Visual Studio ручном режиме, так и через Bower. О втором способе чуть позже, а сейчас я про форматирование расскажу - этим  google/code-prettify не занимается. Для автоматического форматирования выводимого на странице кода использовался vkBeatufy ‑ еще один js скрипт, размещенный на GitHub: https://github.com/vkiryukhin/vkBeautifyУмеет vkBeatufy и обратную операцию - минификацию кода. Поддерживаемых языков куда меньше: XML, JSON, CSS, SQL, но для моей задачи этого хватило вполне. Подключаем скрипт, пользуемся:
vkbeautify.xml(text);
Приведу законченный пример обработки с использованием jQuery. После получения с сервера кодированного в HTML-encoded string текста, последующие раскодирование, форматирование и подсветка могут быть выполнены следующим образом:
var encoded = '&lt;pages&gt; &lt;namespaces&gt; &lt;add namespace=&quot;System.Web.Helpers&quot; /&gt; &lt;add namespace=&quot;System.Web.Mvc&quot; /&gt; &lt;add namespace=&quot;System.Web.Mvc.Ajax&quot; /&gt; &lt;/namespaces&gt; &lt;/pages&gt;';
var decoded = $("<div/>").html(encoded).text();
var formatted = vkbeautify.xml(decoded);
var element = $('pre.prettyprint');
//классом prettyprinted помечаются уже обработанные тэги <pre>
element.removeClass('prettyprinted');
element.text(formatted);
//ручной вызов google/code-prettify
prettyPrint();
Видимый результат на странице:
<pages>
    <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
    </namespaces>
</pages> 
Кстати, в MVC 6 для кодирования HTML-encoded string используется класс HtmlEncoder:
using Microsoft.Extensions.WebEncoders;
HtmlEncoder.Default.HtmlEncode(content);
И пару слов о работе с Bower в Visual Studio. Мне не понравился встроенный менеджер пакетов: установить тот же  google/code-prettify с его помощью мне так и не удалось. Пожелаем Visual Studio дальнейшего развития и больше классных инструментов, а для текущей работы я могу порекомендовать надстройку Package Installer. Бесплатная, поддерживает Bower, npm, JSPM, TSD и NuGet (!), работает быстро и по-моему опыту безотказно. Жаль, что для vkBeatufy вообще не оказалось подходящего Bower-пакета, поэтому пришлось устанавливать по старинке. На этом всё, удачи вам, и поменьше рутины!