Tuesday, February 22, 2011

How I NuGet - Creating a NuGet Package–Without a batch file

This is a follow-up to a previous post How I NuGet – Creating a NuGet Package where I used a batch file to create my NuGet package.

The batch file is not a necessary step in the process – it’s just a preference of mine.  However, after refactoring the process to use the NuGet native commands to include files, I’m leaning toward eliminating the batch step in my process.  Recall the following high-level outline of the steps used to create the NuGet package from the previous post:
  1. Download the NuGet Command Line tool
  2. Create a generic nuget nuspec file - the nuget manifest file
  3. Update the nuget manifest with project specific settings
  4. Create a batch file (.bat) file that will serve as the main entry point into the nuget package creation process
  5. Create the nuget package
  6. Submit and contribute the package to the NuGet Gallery
Eliminating step 4, creation of the batch file and updating step 3, Update the NuGet manifest settings to the following:

<?xml version="1.0"?>
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
        <id>MvcContrib.Shp</id>
        <version>1.0.0.0</version>
        <authors>Dan Ryan</authors>
        <owners>Dan Ryan</owners>
        <licenseUrl>http://mvcxgridmenu.codeplex.com/license</licenseUrl>
        <projectUrl>http://mvcxgridmenu.codeplex.com/</projectUrl>        
        <requireLicenseAcceptance>false</requireLicenseAcceptance>        
        <description>UI Extensions to the MvcContrib Project - Themed Grid & Menu</description>
        <tags>MVC MVC3 ASP.NET MvcContrib</tags>
        <dependencies>
            <dependency id="MicrosoftWebMvc" version="2.0" />
            <dependency id="MvcContrib.Mvc3-ci" version="3.0.57.0" />
        </dependencies>
    </metadata>
    <files>
        <file src="..\src\MvcContrib.Shp\MvcContrib.Shp\bin\Release\MvcContrib.Shp.dll" target="lib" />
        <file src="..\src\MvcContrib.Shp\Shp.Web\Scripts\jquery.mvccontrib*.*" target="content\Scripts" />
        <file src="..\src\MvcContrib.Shp\Shp.Web\Scripts\superfish.js" target="content\Scripts" />
        <file src="..\src\MvcContrib.Shp\Shp.Web\Scripts\*jquery.hoverIntent*" target="content\Scripts" />
    </files>
</package>

The XML files element in the snippet above will include the child file elements in the NuGet package and place the respective file in the associated target (destination directory) of the NuGet package – the snippet above uses targets of lib and content.  You can read all above the files element and other NuGet file specifications here: .nuspec File Format

Again, this is an alternative (and recommended) way to create a NuGet package.  All the other steps in the high-level outline of steps (above) remains the same.

Thanks for reading…

Monday, February 21, 2011

How I NuGet - Creating a NuGet Package


Update: How I NuGet - Creating a NuGet Package – Without a batch file

I started toying around with the MvcContrib project a couple of months ago.  Since then, I created a few UI extensions that use the MvcContrib project. I wanted to contribute to the project; however, Jeremy Skinner recommended that I create a NuGet package and distribute my contributions that way.  So, that's what I did and this post describes/outlines the steps I used to create the NuGet package.

The source for the MvcContrib UI extensions suggested above is available on CodePlex here: MvcContrib UI Extensions - Themed Grid & Menu

My assumption is that you are familiar with NuGet.  If not, you can read all about it at its CodePlex project site.

Here is a high level outline of the steps that I used to create my NuGet package:
  1. Download the NuGet Command Line tool
  2. Create a generic nuget nuspec file - the nuget manifest file
  3. Update the nuget manifest with project specific settings
  4. Create a batch file (.bat) file that will serve as the main entry point into the nuget package creation process
  5. Create the nuget package
  6. Submit and contribute the package to the NuGet Gallery
For reference, the following is a snippet of my directory structure used in the MvcContrib UI Extensions.  I will reference this structure in the steps below.  This image will also help with understanding the batch file used in the steps below.

 

1. Dowload the NuGet Command Line tool

Easy - download the NuGet command line tool here.  Using our structure above, put the .exe into the MvcContrib.Shp/nuspec/ directory.

2. Create a generic nuget nuspec file - the nuget manifest file

Create the .nuspec file by running the following command from the dos prompt:

nuget spec
This will create a file by with the name of Package.nuspec. All this is is an xml file that describes the details of the package - formally called a package manifest or specification.  While renaming this file is not required, I think it makes sense to give it the same name as that of the resulting NuGet package  - in our scenario, MvcContrib.Shp.nuspec.

3. Update the nuget manifest with project specific settings

The NuGet .nuspec file format specification contains many configuration details; however, for our scenario I’ve updated the .nuspec file to contain the following content:

<?xml version="1.0"?>
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
        <id>MvcContrib.Shp</id>
        <version>1.0.0.0</version>
        <authors>Dan Ryan</authors>
        <owners>Dan Ryan</owners>
        <licenseUrl>http://mvcxgridmenu.codeplex.com/license</licenseUrl>
        <projectUrl>http://mvcxgridmenu.codeplex.com/</projectUrl>        
        <requireLicenseAcceptance>false</requireLicenseAcceptance>        
        <description>UI Extensions to the MvcContrib Project - Themed Grid & Menu</description>
        <tags>MVC MVC3 ASP.NET MvcContrib</tags>
        <dependencies>
            <dependency id="MicrosoftWebMvc" version="2.0" />
            <dependency id="MvcContrib.Mvc3-ci" version="3.0.57.0" />
        </dependencies>
    </metadata>
</package>
The XML elements are pretty self-explanatory; however, I recommend reading the NuGet .nuspec file format specification for details on each element.

4. Create a batch file (.bat) that will serve as the main entry point into the nuget package creation process

This step is not necessary; however, I like batch files.  Batch files give us the ability to place simple, repeatable logic into a batch file and execute that logic by double-clicking the batch file.  The following batch file creates a temp directory with subdirectories for the NuGet package content, copies the files (.dll, and .js files) from the source directories and places these files in the temp content directories, executes the NuGet.exe pack command, and then cleans up by removing the temp directories.  Again, this could have all been done via the .nuspec file, but I just prefer to use the batch.  Here’s the batch file contents:

echo OFF :: root nuspec directory set rootDirectory=%cd% ::::::::::::::::::::::::::::::::: :: 1) build the destination directory structure ::::::::::::::::::::::::::::::::: :: destination structure set baseDirectory=basenuspec set contentDirectory=content set libDirectory=lib set scriptsDirectory=Scripts :: make directory command set makeDirectoryCommand=MKDIR :: delete directory command ::set deleteDirectoryCommand=DEL /f set deleteDirectoryCommand=RMDIR /s /q :: delete the previous package build files and directories - if they were not deleted before %deleteDirectoryCommand% %baseDirectory% :: build the directory structure %makeDirectoryCommand% %baseDirectory% cd %baseDirectory% %makeDirectoryCommand% %libDirectory% %makeDirectoryCommand% %contentDirectory% cd %contentDirectory% %makeDirectoryCommand% %scriptsDirectory% :: navigate to the root directory cd %rootDirectory% ::::::::::::::::::::::::::::::::: :: 2) copy files from source to destination ::::::::::::::::::::::::::::::::: :: relative path to the MvcContrib.Shp.dll set srcLibDirectory=..\src\MvcContrib.Shp\MvcContrib.Shp\bin\Release\ :: relative path to source script files set srcScriptsDirectory=..\src\MvcContrib.Shp\Shp.Web\Scripts\ :: lib files to copy set libFiles=MvcContrib.Shp.dll :: script files to copy set scriptFiles=jquery.mvccontrib*.* superfish.js *jquery.hoverIntent* :: copy commnad set copyCommand=COPY /y :: copy the source dll to the lib destination directory %copyCommand% %srcLibDirectory%\%libFiles% %rootDirectory%\%baseDirectory%\%libDirectory%\ :: navigate to the root directory cd %rootDirectory% :: navigate to the source scripts directory cd %srcScriptsDirectory% :: copy the source scripts to the scripts destination directory for %%F in (%scriptFiles%) do %copyCommand% %%F %rootDirectory%\%baseDirectory%\%contentDirectory%\%scriptsDirectory%\ :: navigate to the root directory cd %rootDirectory% ::::::::::::::::::::::::::::::::: :: 3) create the nuget package ::::::::::::::::::::::::::::::::: :: nuget pack command set packCommand=NuGet.exe pack :: nuspec manifest file set manifest=MvcContrib.Shp.nuspec :: run the nuget package command %packCommand% %manifest% -b %baseDirectory% :: delete the temp package build files and directories %deleteDirectoryCommand% %baseDirectory% ::PAUSE
The above batch file is pretty much fully documented, so it shouldn’t take too much to understand the logic.

Could I have used PowerShell to do this? Absolutely; however, I really haven't spent much time diving into PowerShell. Until then, the batch solution works just fine.

As a side note - NuGet gives you the ability to add Content to the package (this is essentially what the previous batch file is doing); add pre-processing of files to the client project (the project importing the NuGet package); add XML elements to be merged with the client project's .config files; add PowerShell scripts to do anything else that the NuGet package requires; and a whole laundry list of other functionality. Again, if you're interested, check out the NuGet Project and Documentation on CodePlex.

5. Create the nuget package

In our scenario, creating the NuGet package is simple.  All you have to do is double-click the .bat file and the batch file handles the command to create the NuGet package.  The resulting package is compiled into a single file.  In our scenario and using the .nuspec file from above, the resulting package is compiled into: MvcContrib.Shp.1.0.0.0.nupkg. How is the package name composed? The following image identifies the package name components:

nupkgname

 

6. Submit and contribute the package to the NuGet Gallery

Log into the NuGet Gallery and contribute your package.  What?  If you don’t already have an account, request one from the NuGet Gallery.  The process of submitting/contributing you package for distribution is as simple as uploading and following the NuGet package wizard.

Useful Links:
Anyway, thanks for reading…

Monday, February 7, 2011

MvcContrib Menu

Demo | Source

This page is a placeholder for now; however, I intent to create a post that describes the use of my own version of the MvcContrib Menu Helper.

For now, you can see a working demo by using the demo link.  Once I have the source code cleaned up a bit, I'll post the source code.

Below is a quick snippet of the code used to generate the main menu in the demo. Notice the fluent style and the use of Razor Templates. BTW, sorry for the poor color-code - Razor doesn't format well using SyntaxHighligher.

@Html.MvcContrib().Menu().Items(menu => {
    menu.Action<HomeController>(c => c.Index(), "no text displayed", Url.Content("~/Content/ico/house.png"))
        .ItemAttributes(@class => "solo").DisplayText(false); 
           
    menu.Link("About", null, Url.Content("~/Content/ico/application_side_boxes.png")).Items(sub => {
        sub.Content(
            @:@Html.Partial("_MvcContribLogo")    
        );
    }).ListAttributes(style => "width: 450px;", @class => "sf-shadow-off");
    
    menu.Link("Secure", null, Url.Content("~/Content/ico/lock_open.png")).Items(sub => {
        sub.Secure<HomeController>(c => c.Index(), null, Url.Content("~/Content/ico/application_view_tile.png"));
        sub.Secure<HomeController>(c => c.About(), null, Url.Content("~/Content/ico/info2.png"));
        sub.Secure<HomeController>(c => c.SecurePageOne(), null, Url.Content("~/Content/ico/shield.png"));
        sub.Secure<HomeController>(c => c.SecurePageTwo(), null, Url.Content("~/Content/ico/shield_go.png"));
    });
    
    menu.Link("Insecure", null, Url.Content("~/Content/ico/lock.png")).Items(sub => {
        sub.Action<HomeController>(c => c.Index(), null, Url.Content("~/Content/ico/application_view_tile.png"));
        sub.Action<HomeController>(c => c.About(), null, Url.Content("~/Content/ico/info2.png"));
        sub.Action<HomeController>(c => c.SecurePageOne(), null, Url.Content("~/Content/ico/shield.png"));
        sub.Action<HomeController>(c => c.SecurePageTwo(), null, Url.Content("~/Content/ico/shield_go.png"));
    });
    
    menu.Action<MenuController>(c => c.Index(), "Menu Examples", Url.Content("~/Content/ico/house_go.png"));
})

Demo | Source