вторник, 13 марта 2012 г.

$(SiteURL) variable in Post-deployment Command Line for SharePoint projects




На форуме озвучил проблему, с получением переменной $(SiteURL) в Post-deployment Command Line для SharePoint проектов. Зачем это нужно, как получить значение этой переменной с помощью PowerShell и как поднять пул приложений после развертывания вашего решения из Visual Studio 2010, а не ждать отклика от IE 9 читайте в посте.




 

F5 в IE9


Во время разработки решения и особенно его отладки приходится часто выполнять развертывание пакета на локальную машину. В Visual Studio 2010 для этого предусмотрены встроенные средства под названием Active Deployment Configuration.



Список конфигураций может дополняться после установки расширений (например, CKSDev). Стандартная конфигурация (Default) выполняет следующий состав шагов:

1) Run Pre-Deployment Command;

2) Recycle IIS Application Pool (этот шаг необходим для загрузки обновленной сборки решения в пул приложения);

3) Retract Solution;

4) Add Solution;

5) Activate Features;

6) Run Post-Deployment Command; 
 
Во время развертывания выполняется шаг (2) и пул приложений перезапускается. В этом и есть вся проблема. После развертывания необходимо нажимать F5 в браузере на странице сайта с целью его «оживить» и ждать обновления страницы (примерно 20 секунд, зависит от вашего локального компьютера). Достаточно утомительная операция, если выполнять развертывание больше десяти раз за день (а так и происходит, когда наращиваешь функционал).

Пришла мысль автоматизировать этот шаг. Для этого необходимо добавить команду отправки первого HTTP GET запроса к вашему сайту по адресу $(SiteURL) в Post-deployment Command Line.

 
Если воспользоваться инструментом TinyGet 5.2, то Post-deployment Command Line будет таким.

tinyget.exe -srv:localhost -uri:"$(SiteURL)" -h -auth:2 -loop:1 -u:CurrentUser
  
Проблема в том, что переменной $(SiteURL) нет. Список переменных можно посмотреть в статье Pre-build Event / Post-build Event Command Line Dialog Box или в настройках проекта. 



О том, как получить значение $(SiteURL) и отправить первый HTTP GET запрос, описано ниже.

PowerShell


В Post-deployment Command Line можно вызывать PowerShell скрипты. Как это делать и для чего это может нужно описано в статье Visual Studio Pre / Post Deployment PowerShell for SharePoint.

Функция VS-SiteURL (чтение $(SiteURL) из конфигурации)

Значение $(SiteURL) храниться в файле $(ProjectName).user (настройки проекта с привязкой к пользователю).



Задача очень простая, прочитать значение из этого файла. Реализация функции ниже. Как читать XML из PowerShell описано в статье Using PowerShell to read xml-files.

  1. function VS-SiteURL{  
  2.   
  3.   <#  
  4.     .SYNOPSIS  
  5.   
  6.       Read $(SiteURL) value from the user options file.  
  7.         
  8.     .DESCRIPTION  
  9.         
  10.       Read $(SiteURL) value from the user options file for Visual Studio 2010 SharePoint   
  11.       project. If the user options file does not exists, function will return empty string.  
  12.         
  13.     .PARAMETER ProjectPath  
  14.       
  15.       $(ProjectPath) the absolute path name of the project (defined with drive, path, base name,   
  16.       and file extension, see also http://msdn.microsoft.com/en-us/library/42x5kfw4.aspx).  
  17.         
  18.     .OUTPUTS  
  19.         
  20.       $(SiteURL) value.  
  21.         
  22.     .EXAMPLE  
  23.         
  24.       VS-SiteURL -ProjectPath:'C:\SPSample.csproj';  
  25.         
  26.     .NOTES  
  27.         
  28.       Revision History:  
  29.           
  30.         2012-03-12 : Roman Itakaev - Created.  
  31.   #>  
  32.     
  33.   param(  
  34.     
  35.     [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $ProjectPath  
  36.   )  
  37.     
  38.   # the absolute path name of the user options file (.user file)  
  39.   $ProjectUserPath = $('{0}.user' -f $ProjectPath);  
  40.     
  41.   # $(SiteURL) value  
  42.   $SiteURL = [String]::Empty;  
  43.     
  44.   # .user file exists  
  45.   if(Test-Path -Path:$($ProjectUserPath)){  
  46.     
  47.     # read xml (see also http://blogs.msdn.com/b/kalleb/archive/2008/07/19/using-powershell-to-read-xml-files.aspx)  
  48.     [xml]$ProjectUser = Get-Content -Path:$ProjectUserPath;  
  49.       
  50.     # read $(SiteURL) value  
  51.     $SiteURL = $ProjectUser.Project.PropertyGroup.SharePointSiteUrl;  
  52.   }  
  53.     
  54.   # $(SiteURL) value  
  55.   return $SiteURL;  
  56. }  
Функция HTTP-Get (отправка HTTP GET запроса по указанному адресу)

Можно воспользоваться инструментом TinyGet 5.2, как писал выше, а можно написать простейший код с использованием класса WebRequest. Подробнее описано в статье How to make a GET request by using Visual Basic .NET or Visual Basic 2005. Реализация функции ниже.

  1. function HTTP-Get{  
  2.   
  3.   <#  
  4.     .SYNOPSIS  
  5.         
  6.       Make a HTTP GET request to specified $(Url).  
  7.         
  8.     .DESCRIPTION  
  9.       
  10.       Make a HTTP GET request to specified $(Url) and dump $(Response) headers like   
  11.       tinyget.exe utility (see also http://support.microsoft.com/kb/840671).  
  12.         
  13.     .PARAMETER Url  
  14.       
  15.       $(Url) a address for request.  
  16.         
  17.     .OUTPUTS  
  18.         
  19.       No output.  
  20.         
  21.     .EXAMPLE  
  22.         
  23.       HTTP-Get -Url:'http://msdn.microsoft.com/en-us/';  
  24.         
  25.     .NOTES  
  26.         
  27.       Revision History:  
  28.           
  29.         2012-03-12 : Roman Itakaev - Created.  
  30.   #>  
  31.   
  32.   param(  
  33.     
  34.     [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Url  
  35.   )  
  36.     
  37.   # uniform resource identifier  
  38.   $Uri = New-Object -TypeName:'Uri' -ArgumentList:$Url;  
  39.     
  40.   # web request  
  41.   $Request = [Net.WebRequest]::Create($Uri);  
  42.     
  43.   # use default proxy  
  44.   $Request.Proxy = [Net.WebProxy]::GetDefaultProxy();  
  45.     
  46.   # use default credentials  
  47.   $Request.UseDefaultCredentials = $true;  
  48.     
  49.   # web response  
  50.   $Response = $null;  
  51.   
  52.   # receive web response  
  53.   try{  
  54.     
  55.     # receive web response from request  
  56.     $Response = $Request.GetResponse();  
  57.     
  58.   } catch [Net.WebException]{  
  59.     
  60.     <  
  61.       Receive web response from exception (see also   
  62.       http://msdn.microsoft.com/en-us/library/system.net.webexception.response.aspx).  
  63.     #>  
  64.     $Response = $_.Exception.Response;  
  65.   }  
  66.     
  67.   <  
  68.     HTTP status code (see also   
  69.     http://msdn.microsoft.com/en-us/library/system.net.httpstatuscode.aspx).  
  70.   #>  
  71.   $StatusCode = $Response.StatusCode;  
  72.     
  73.   <#  
  74.     Dump $(Response) like tinyget.exe utility (see also http://support.microsoft.com/kb/840671).  
  75.   #>  
  76.     
  77.   # protocol  
  78.   Write-Host -Object:$('{0}/{1} {2} {3}' -f $Uri.Scheme.ToUpper(), `  
  79.     $Request.ProtocolVersion, [Int32]$StatusCode$StatusCode);  
  80.       
  81.   # headers  
  82.   $Response.Headers.Keys | ForEach-Object {  
  83.     
  84.     # header  
  85.     Write-Host -Object:$('{0}: {1}' -f $_$Response.Headers[$_]);  
  86.   }  
  87. }  

Функция SP-WakeUp (разбудить перезапущенный пул приложения)

Отправка первого запроса по адресу $(SiteURL)/_layouts/settings.aspx. Первый запрос на страницу Параметры сайта, потому что там удобно смотреть, что изменилось на сайте после активации возможности, или отладить активацию, если использовалась конфигурация No Activation.

  1. function SP-WakeUp{  
  2.   
  3.   <#  
  4.     .SYNOPSIS  
  5.         
  6.       Read $(SiteURL) value from the user options file and make a HTTP GET   
  7.       request to site settings page ($(SiteURL)/_layouts/settings.aspx).  
  8.         
  9.     .DESCRIPTION  
  10.       
  11.       Read $(SiteURL) value from the user options file for Visual Studio 2010 SharePoint   
  12.       project and make a HTTP GET request to site settings page ($(SiteURL)/_layouts/settings.aspx).  
  13.         
  14.     .PARAMETER ProjectPath  
  15.       
  16.       $(ProjectPath) the absolute path name of the project (defined with drive, path, base name,   
  17.       and file extension, see also http://msdn.microsoft.com/en-us/library/42x5kfw4.aspx).  
  18.         
  19.     .OUTPUTS  
  20.         
  21.       No output.  
  22.         
  23.     .EXAMPLE  
  24.         
  25.       SP-WakeUp -ProjectPath:'C:\SPSample.csproj';  
  26.         
  27.     .NOTES  
  28.         
  29.       Revision History:  
  30.           
  31.         2012-03-12 : Roman Itakaev - Created.  
  32.   #>  
  33.     
  34.   param(  
  35.     
  36.     [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $ProjectPath  
  37.   )  
  38.   
  39.   # site url  
  40.   $SiteURL = $(VS-SiteURL -ProjectPath:$ProjectPath).TrimEnd('/');  
  41.   
  42.   # site url is not null or empty  
  43.   if($SiteURL){  
  44.       
  45.     # site settings page address  
  46.     $Url = $('{0}/_layouts/settings.aspx' -f $SiteURL);  
  47.     
  48.     # make HTTP GET request  
  49.     HTTP-Get -Url:$Url;  
  50.   }  
  51. }  

Скрипт SP-WakeUp.ps1

Все функции собраны в одном файле. Скачать скрипт можно по ссылке.

Post-deployment Command Line


Венец всего этого программирования. Нам необходимо добавить скрипт SP-WakeUp.ps1 (скачать скрипт можно по ссылке) в корень проекта и прописать следующие команды в Post-deployment Command Line.

powershell.exe -Command "&{Set-ExecutionPolicy Unrestricted}"
powershell.exe -Command "&{$(ProjectDir)SP-WakeUp.ps1 -ProjectPath:'$(ProjectPath)'}"
ВАЖНО! Ваш проект должен лежать по пути, который НЕ содержит кириллицу, иначе будет ошибка.
Если ошибок нет, то журнал развертывания будет иметь вид.

Ремарка

Внимательный читатель заметил, что можно было «захардкодить» значение $(SiteURL) в Post-deployment Command Line изначально.

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

Итоги


Пул приложений будет подниматься сразу после развертывания. Времени на развертывание пакета будет потрачено на 20 секунд больше, но нам не придется делать дополнительный шаг (F5 на странице и ожидание), что радует, когда нужно делать частое развертывание и отладку.

2 комментария:

  1. Решение красивое, но всё равно экономии времени нет, разве что если не пойти пить чай, а когда возвращаешься, то уже всё готово (не надо ждать долго реакции после нажатия F5)

    ОтветитьУдалить
  2. Времени тратится столько же, но зато сразу можно подключаться к рабочему процессу “w3wp.exe” и начинать отладку не выходя из IDE. Лишние клики отвлекают от решения задачи по предметной области. А так ты знаешь, Deploy без активации длится 30 секунд. Нажал одну кнопку, подождал, подключился к “w3wp.exe” и продолжай работать :)

    ОтветитьУдалить