Andrey on .NET | Использование NuGet. Часть 3 – Создаем установочный пакет

Использование NuGet. Часть 3 – Создаем установочный пакет

NuGet logoВ прошлой части было рассмотрено как подключить к NuGet локальный репозиторий. Это удобное решение для установки библиотек собственной разработки. Осталось разобраться как создать свой пакет.

Для его создания потребуется утилита "NuGet.exe Command Line", которую можно загрузить с официальной страницы проекта на CodePlex.Скопируем её в папку, доступную из командной строки. В качестве подходящего места может выступить "(Program files)\Microsoft Visual Studio 10.0\Common7\Tools\".

Создаем проект библиотеки

Прежде чем создать установочный пакет, необходимо подготовить библиотеку, которая будет в него включена. В неё включим атрибуты проверки данных, созданные в цикле статей "ASP.NET MVC 3 в деталях". Обратите внимание, что для подключения этой библиотеки к проекту необходимо не только добавить её сборку, но и скопировать дополнительные JavaScript-файлы.

Имя решения (solution) возьмем произвольное. А вот название проекта будет совпадать с используемым в библиотеке пространством имен MVCDemo.Attributes.Validation. Включем в него следующие исходные файлы атрибутов проверки данных:

  • BlockHtmlAttribute.cs
  • EqualAttribute.cs
  • StringLengthRangeAttribute.cs

Кроме того, в папке Scripts\Validation разместим JavaScript-файлы для поддержки проверки данных на стороне клиента:

  • BlockHtmlAttribute.js
  • EqualAttribute.js

Чтобы не акцентировать внимание на создании библиотеки (class library), можно сразу загрузить готовый проект. Соберем его в режиме Release. Все готово для создания установочного пакета NuGet.

Создаем установочный пакет

Чтобы лучше понять принципы работы NuGet, соберем установочный пакет вручную. Для этого в корневой папке решения создадим папку nuget-package (имя произвольное) для размещения его файлов.

Структура папок

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

  • tools – папка для утилит, которые должны быть доступны из командной строки. После установки её путь добавляется в список, расположенный в переменной среды Path.
  • lib – хранилище сборок проекта. Именно сюда необходимо скопировать их DLL файлы.
  • content – место хранения дополните��ьных файлов. Его внутренняя структура может быть любой. При этом она один в один будет перенесена в корневую папку проекта при установке пакета.

Кроме того, папка lib имеет дополнительное соглашение. Сборки, размещенные непосредственно в ней, будут подключены к проекту для любой версии .NET Framework. Но при необходимости DLL файлы можно разделить в зависимости от версии .NET или Silverlight для которых они предназначены. Для этого файлы необходимо разместить в подпапке с названием и номером версии платформы. Для интерпретации этого имени NuGet использует класс FrameworkName. Поэтому возможно использовать как полные имена, так и сокращения. Кроме того, при отсутствии имени считается что подразумевается .NET Framework. Таким образом, "4.0" эквивалентно ".NetFramework 4.0".

Может возникнуть вопрос: а что будет если расположить файлы и самой lib и в подпапках для различных версий .NET? В этом случае, файлы из основной папки всегда будут добавляться в проект, а из подпапок – только в проект, ориентированный на указанную платформу и её версию.

Таким образом структура может выглядеть следующим образом:

  • content
  • lib
    • .NetFramework 1.1
    • .NetFramework 2.0
    • .NetFramework 4.0
    • Silverlight 3.0
    • Silverlight 4.0
  • tools

Разумеется, необходимо создавать только те папки, в которых будут размещены файлы.

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

  • в content скопировать папку Scripts;
  • сборку MVCDemo.Attributes.Validation.dll из папки Release проекта перенести в lib;
  • папки tools в данном примере не будет.

Описываем спецификацию библиотеки

Теперь необходимо создать описание установочного пакета. Это будет файл в формате XML с именем библиотеки и расширением ".nuspec". Создадим CustomValidationAttributesLib.nuspec в папке install-package. Его структура достаточно понятная, поэтому давайте сразу посмотрим на пример:

<?xml version="1.0" encoding="utf-8"?> 
<package> 
  <metadata> 
    <id>MVCDemo.Attributes.Validation</id> 
    <version>1.0.0</version> 
    <authors>Andrey Veselov</authors>
    <description>Custom validation attributes for ASP.NET and ASP.NET MVC.</description> 
    <language>en-US</language>
    <licenseUrl>http://andrey.moveax.ru/terms-of-use.aspx</licenseUrl>
    <projectUrl>http://andrey.moveax.ru/</projectUrl>
    <tags>ASP.NET MVC</tags>
  </metadata> 
</package>

Отдельно можно отметить только тег id. Это уникальный идентификатор библиотеки, который должен быть равен имени используемого ей пространства имен. Кроме того, id и номер версии будут использованы для создания имени установочного пакета.

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

Создаем установочный пакет

Запустим "Visual Studio Command Prompt" и перейдем в папку nuget-package. В ней выполним следующую команду (nuget.exe должен быть доступен из командной строки):

nuget pack AdditionalValidationAttributes.nuspec

В результате будет создан установочный пакет "MVCDemo.Attributes.Validation.1.0.0.nupkg". По формату это zip-файл который можно открыть в любом архиваторе. Кроме того, для их просмотра можно воспользоваться утилитой "NuGet Package Explorer".

Скопируем полученный файл в репозиторий, созданный в предыдущей части. Теперь посмотрим на созданный пакет в работе, а затем немного автоматизируем процесс его создания.

Проверка

Для проверки создадим простой ASP.NET MVC 3 проект NuGetMvсDemo. Модель TestModel будет содержать два свойства, для проверки атрибутов из AdditionalValidationAttributes:

namespace NuGetMvсDemo.Models
{
    using System.ComponentModel.DataAnnotations;

    public class TestModel
    {
        [Required]
        [DataType(DataType.MultilineText)]
        public string TextBlock { get; set; }

        public bool BooleanValue { get; set; }        
    }
}

Добавим Контроллер HomeController с единственным Действием Create:

namespace NuGetMvсDemo.Controllers
{
    using System.Web.Mvc;

    public class HomeController : Controller
    {

        // GET: /Home/Create
        public ActionResult Create()
        {
            return View();
        }

        //
        // POST: /Home/Create
        [HttpPost]
        public ActionResult Create(FormCollection collection)
        {
            return View();
        }
    }
}

Теперь необходимо создать строго-типизированное Представление для Действия, используя для этого Модель TestModel и шаблон Create.

Остается только в методе RegisterRoutes() изменить Действие по умолчанию:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new {
            controller = "Home",
            action = "Create",
            id = UrlParameter.Optional
        } // Parameter defaults
    );

}

Можно запустить проект и убедиться что форма выводится без ошибок.

Теперь откроем консоль "Package Manager Console" и установим в качестве текущего источника локальный репозиторий "Local NuGet repository". Ведем команду "Get-Package -ListAvailable" и получим следующий список:

PM> Get-Package -ListAvailable

Id                             Version              Description                            
--                             -------              -----------                            
Castle.Core                    1.2.0                Core of the castle project             
Castle.DynamicProxy            2.2.0                Castle DynamicProxy is a library for...
log4net                        1.2.10               log4net is a tool to help the progra...
MVCDemo.Attributes.Validation  1.0.0                Custom validation attributes for ASP...
NLog                           1.0.0.505            NLog is a logging platform for .NET ...
NLog                           2.0.0.0              NLog is a logging platform for .NET ...
RazorEngine                    2.1                  A templating engine built upon Micro...

Установим пакет "MVCDemo.Attributes.Validation":

PM> Install-Package MVCDemo.Attributes.Validation
Successfully installed 'MVCDemo.Attributes.Validation 1.0.0'.
Successfully added 'MVCDemo.Attributes.Validation 1.0.0' to NuGetMvDemo.

Обратите внимание, что в папку Scripts добавилась папка Validation c JavaScript-файлами для проверки данных на стороне клиента. Кроме того, подключена сборка "MVCDemo.Attributes.Validation.dll". В случае удаления библиотеки все эти изменения будут отменены, а соответствующие файлы стерты.

Изменим Модель и задействуем в ней новые атрибуты проверки данных:

namespace NuGetMvDemo.Models
{
    using System.ComponentModel.DataAnnotations;
    using MVCDemo.Attributes.Validation;

    public class TestModel
    {
        [Required]
        [DataType(DataType.MultilineText)]
        [BlockHtml (ErrorMessage="Html is not allowed.")]
        [StringLengthRange(2,20)]
        public string TextBlock { get; set; }

        [Equal(true, ErrorMessage="Please check this checkbox.")]
        public bool BooleanValue { get; set; }        
    }
}

Так же в Представление необходимо добавить ссылки на JavaScript-файлы:

@model NuGetMvDemo.Models.TestModel
@{
    ViewBag.Title = "Create";
}
<h2>
    Create</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/Validation/BlockHtmlAttribute.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/Validation/EqualAttribute.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {

    .........

Запустим проект и убедимся, что новые атрибуты работоспособны.

Автоматизируем создание установочного пакета

Копировать файлы каждый раз вручную не очень удобно. Конечно можно написать cmd-файл, но есть решение удобнее: спецификация NuGet позволяет указать файлы для включения в пакет. Таким образом, нет необходимости копировать их в папку.

Удалим все, за исключением "CustomValidationAttributesLib.nuspec", из папки nuget-package. Теперь откроем файл спецификаций и добавим в него список файлов:

<?xml version="1.0" encoding="utf-8"?> 
<package> 
  <metadata> 
    <id>MVCDemo.Attributes.Validation</id> 
    <version>1.0.0</version> 
    <authors>Andrey Veselov</authors>
    <description>Custom validation attributes for ASP.NET and ASP.NET MVC.</description> 
    <language>en-US</language>
    <licenseUrl>http://andrey.moveax.ru/terms-of-use.aspx</licenseUrl>
    <projectUrl>http://andrey.moveax.ru/</projectUrl>
    <tags>ASP.NET MVC</tags>
  </metadata>
  <files>
    <file src="..\MVCDemo.Attributes.Validation\bin\Release\*.dll" target="lib" />
    <file src="..\MVCDemo.Attributes.Validation\Scripts\Validation\*.js" target="content\Scripts\Validation" />    
  </files>
</package>

Файл или их группа (по маске) задается тегом <file>. Атрибут src определяет откуда их необходимо взять. При этом относительные пути считаются указанными относительно папки, где расположен файл со спецификацией. Второй атрибут target показывает место размещения в установочном пакете.

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

В действия после сборки проекта (post-build step) добавим вызов "NuGet Command Line". При помощи условия поставим ограничение, что установочный пакет будет собираться только вместе с Release версией:

if $(ConfigurationName) == Release "$(DevEnvDir)..\Tools\nuget" pack "$(SolutionDir)nuget-package\CustomValidationAttributesLib.nuspec" /OutputDirectory "$(SolutionDir)nuget-package"

В данной команде используется опциональный параметр OutputDirectory. Он указывает куда сохранить файл созданного установочного пакета. Кроме того, подразумевается что nupack.exe скопирован в папку "Microsoft Visual Studio 10.0\Common7\Tools\".

Соберем проект и убедимся, что при сборке Release-версии в папку nuget-package добавляется "MVCDemo.Attributes.Validation.1.0.0.nupkg". При необходимости можно настроить публикацию пакета сервер или копирование его в локальный репозиторий.

И в завершении серии, предлагаю ознакомиться с справкой по использованию NuGet. В ней, кроме краткого изложения описанных в серии возможностей, рассмотрен вопрос модификации конфигурационных и исходных файлов проекта. Кроме того, есть инструкция по подключению поддержки nuspec-файлов в Visual Studio IntelliSense.


Исходный код различных вариантов проекта проекта (C#, Visual Studio 2010):
Проект исходной демонстрационной библиотеки (10 Kb)
Проект с созданием установочного пакета вручную (17 Kb)
Проект с автоматическим созданием установочного пакета (11 Kb)
Проект тестового ASP.NET MVC проекта (464 Kb)

Комментарии (3) -

Александр 17.01.2013 18:18:05

Добрый день.
Тут столкнулся с интересной проблемой. Мб Вы на свежую голову сможете посоветовать решение.
Суть: есть пакет, данный пакет содержит 2 сборки одного и того же проекта, но собранного под разные платформы (3.5 и 4.0). Сборка, собранная под 4.0, имеет чуть больший функционал.
Соответственно сборки помещаются в пакет так:
  <files>
    <file src="MyLib40.dll" target="lib\net40\MyLib.dll" />
    <file src="MyLib35.dll" target="lib\net35\MyLib.dll" />
  </files>

Можно ли как-то указать для проекта на платформе 4.0 использовать сборку из пакета, предназначенную для 3.5?

Александр 17.01.2013 18:19:46

@ Александр:

Забыл сказать, что хочется это сделать через командную строку. Понятно, что можно подцепить для 4.0, потом поменять целевую платформу в файле package.config и поменят reference в проекте на требуемый.

@ Александр: Прямых или интуитивно понятных путей нет, кроме как разделать на 2 пакета. Можно даже оставить одно имя, но тянуть разные версии (скажем линейка MyLib3.xx.xx.dll для .NET3.5 и MyLib4.xx.xx.dll для .NET4) и устанавливать через
Install-Package MyLib -Version 3.xx.xx
Install-Package MyLib -Version 4.xx.xx

В пакете 4.xx.xx могут лежать обе версии, в 3.x только одна. Их сборку можно автоматизировать через post-build event и будет все просто, но это все же костыль.

Pingbacks and trackbacks (1)+

Добавить комментарий