Wednesday, December 11, 2013

Nuget package which supports different ASP.NET MVC versions

Problem

Let's suppose you are going to create a Nuget package which depends on ASP.NET MVC. You package will work with any MVC version but it should install only that assembly which is compatible with MVC version used in the target project.
Possible solution can be to create several Nuget packages - for each supported version of MVC.
However there are two essential drawbacks in this approach:
  1. When use decide to upgrade his/her project and use new version MVC - he/she will need to remove your package and install another its version.
  2. Imagine your package depends not only on MVC but on some other assembly as well (e.g. EntityFramework) and that assembly also has few different version. In this case the number different Nuget packages you need to create multiplies to the number of versions of second assembly.
    For example our package should support 3 different versions of MVC (3, 4 and 5) and two versions of EntityFramework. In this case the total number of packages we need to create will 3x2 = 6!
    You can only imagine how you will name all those packages. It will be something like "MyPackage for MVC 3 and EF 5" - quite messy as for my.

Solution

Fortunately we have found a solution when created a Nuget package for our EasyQuery library. This solution allows you to avoid creating several different Nuget packages for each supported MVC (or any other library) version and automatically install necessary assembly depending on MVC version used in the target project.
The solution is rather simple:
  1. You include into your Nuget package the assemblies for all supported versions of MVC (or any other library which you depend on). For example, in case of EasyQuery our package includes such assemblies as Korzh.EasyQuery.Mvc2, Korzh.EasyQuery.Mvc3 and so on.
  2. You include install.ps1 PowerShell script which runs after package installation. This script performs two tasks:
  • First it finds our which version of MVC use the target project based on list of project references.
  • Using that information it removes all unnecessary assemblies installed with your package and remain only that one which corresponds to MVC version used in the target project.
If you don't know how to add install.ps1 script into your Nuget package you can read this article for instructions.

Example

So here is an example of install.ps1 script:
param($rootPath, $toolsPath, $package, $project)

# Bail out if scaffolding is disabled (probably because you're running an incompatible version of NuGet)
if (-not (Get-Command Invoke-Scaffolder)) { return }

# Could use "Set-DefaultScaffolder" here if desired

#set default version of MVC to 5.0
$MvcVersion = "5.0.0.0"

#find out the version of MVC assembly in the target project
$project.Object.References | Where-Object { $_.Name -eq 'System.Web.Mvc' } | ForEach-Object { $MvcVersion = $_.Version}
Write-Host "MVC version: " $MvcVersion

#remove unnecessary Korzh.EasyQuery.MvcX assemblies from project references
if ($MvcVersion.StartsWith("2.0")) {
    $project.Object.References | Where-Object { ($_.Name.StartsWith("Korzh.EasyQuery.Mvc")) -and !($_.Name.StartsWith("Korzh.EasyQuery.Mvc2")) } | ForEach-Object { 
        $_.Remove()
    }
}
elseif ($MvcVersion.StartsWith("3.0")) {
    $project.Object.References | Where-Object { ($_.Name.StartsWith("Korzh.EasyQuery.Mvc")) -and !($_.Name.StartsWith("Korzh.EasyQuery.Mvc3")) } | ForEach-Object {
        $_.Remove()
    }
}
elseif ($MvcVersion.StartsWith("4.0")) {
    $project.Object.References | Where-Object { ($_.Name.StartsWith("Korzh.EasyQuery.Mvc")) -and !($_.Name.StartsWith("Korzh.EasyQuery.Mvc4")) } | ForEach-Object { 
        $_.Remove()
    }
}
elseif ($MvcVersion.StartsWith("5.0")) {
    $project.Object.References | Where-Object { ($_.Name.StartsWith("Korzh.EasyQuery.Mvc")) -and !($_.Name.StartsWith("Korzh.EasyQuery.Mvc5")) } | ForEach-Object { 
        $_.Remove()
    }
}

Friday, November 22, 2013

Testing Nuget package

In our previous article we described how to create Nuget package using Nuget Package Manager tool.
Now we are going to discuss how to test this new package locally (without uploading it on Nuget.org service).
To test new package locally you should tell Visual Studio where to search for your package.

1. Run Visual Studio and open some project (it can be an empty one).

2. Open Package Manager Console and click on Options button



3. In the Options dialog:

  • Click on "Plus" button
  • Specify source name (e.g. "Local Package source") and the path to the folder where with new package.
  • Click OK to close the dialog.




4. Select "All" or "Local Package source" in the "Package source" combo-box


5. Now you can install your package:
Install-Package MyPackage 
NB:
When you modify your NuGet package - change its version number before saving. In this case you will be able to apply the latest changes using the same 
Install-Package command without uninstalling the package first.

Tuesday, November 12, 2013

Creating NuGet package using NuGet Package Explorer

There are several different ways to create Nuget package for your component or library.

  • Using Visual Studio (version 2010 and above) project.
  • Through command-line, using Nuget.exe tool

This tutorial will give you a detailed step-by-step description for the last option: NuGet Package Exporer.
So, let's start.

1. First of all you need to download and install NuGet Package Exporer.

2. When installation is completed - run Nuget Explorer and select Create a new package option.

Nuget Explorer start screen

3. Click on the Edit metadata button at the top of Package metadata panel to enter package name, version, description and other parameters.




4. Then add Lib folder to your package (Content > Add > Lib Folder menu item) - this is the place where your assemblies will be stored.



5. Right click on "Lib" folder and select Add .NET folder and then select the version of .NET framework. Repeat this operation for all versions of .NET you have assemblies for.


 6. Then right click on each .NET folder, select Add Existing Files menu item and select the assemblies (DLLs) for corresponding version of .NET.
The main rule: all files placed into some lib\netXX folder will be added as references to the targeting project with corresponding target platform (lib\net35 - for .NET 3.5 projects, lib\net40  - for .NET 4.0, etc).

7. PowerShell scripts
You can also add power shell scripts which will be executed on package install (install.ps1 script) or each time when solution is opened (init.ps1).
To do it use Content > Add > Tools  menu item and then right click on tools folder in right panel and select Add install.ps1 or Add init.ps1 menu item.


Finally  - save the package and close NuGet Package Explorer. You package will be saved as PackageName.1.0.0.nupkg file.

In our next article we are going to describe how to test you NuGet package locally using Visual Studio.