Wednesday, December 11, 2013

Nuget package which supports different ASP.NET MVC versions


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.


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.


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 = ""

#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 { 
elseif ($MvcVersion.StartsWith("3.0")) {
    $project.Object.References | Where-Object { ($_.Name.StartsWith("Korzh.EasyQuery.Mvc")) -and !($_.Name.StartsWith("Korzh.EasyQuery.Mvc3")) } | ForEach-Object {
elseif ($MvcVersion.StartsWith("4.0")) {
    $project.Object.References | Where-Object { ($_.Name.StartsWith("Korzh.EasyQuery.Mvc")) -and !($_.Name.StartsWith("Korzh.EasyQuery.Mvc4")) } | ForEach-Object { 
elseif ($MvcVersion.StartsWith("5.0")) {
    $project.Object.References | Where-Object { ($_.Name.StartsWith("Korzh.EasyQuery.Mvc")) -and !($_.Name.StartsWith("Korzh.EasyQuery.Mvc5")) } | ForEach-Object { 

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 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 
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.

Saturday, October 26, 2013

New features and enhancements in Visual Studio 2013 and .NET 4.5.1

Here I would like to list several links to the articles or blog posts which describe the enhancements and new features of recently released Visual Studio 2013 together with .NET 4.5.1 update.

Friday, October 11, 2013

SSL is dead...for about 15 years already!

It was a big surprise for me to get known that SSL is a deprecated term and actually we all have been using TLS for about 15 years already (since 1999).
More about here:
The only question is: why in this case we still buy "SSL certificates"? :)

Friday, September 27, 2013

Possible scalability problem in ASP.NET projects which use Entity Framework or other ORM solutions.

Recently I've come across a very useful article by Michael K. Campbell which describes a very common mistake in the architecture of ASP.NET application that uses EntityFramework or any other ORM solution.
Since I met (and even did :)) the similar mistake before I decided to share a link to that article here.

Wednesday, August 21, 2013

Custom assemblies with ISerializable classes running in ASP.NET medium trust applications

The problem.

  • Suppose you have some common code that want to share between your projects. So you placed that code in a Class Library project, create an assembly and reference it in your projects.
  • Let’s also suppose that one or more classes in that assembly implements ISerializable interface;
  • Finally, imagine that we have a web-application, which uses this assembly and this application is run in medium-trust environment (by the way, most shared hosting services will run your application in medium-trust security level).
If you meet all of the above terms you are likely to encounter with the same problem, which we faced not so long ago with our EasyQuery ASP.NET assemblies.
Namely, when accessing a Web page that uses code from such assembly you will see something like the following:

Parser Error
Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.
Parser Error Message: Inheritance security rules violated while overriding member: 'Korzh.EasyQuery.DataModel.System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)'. Security accessibility of the overriding method must match the security accessibility of the method being overriden.

The reason of the problem

Medium trust level of ASP.NET web-application requires from application’s code to be security transparent. We should note that since version 4.0. NET framework uses a new (Level 2) model code access security (CAS). For more information on these changes please read this article.
Among other changes Level 2 CAS introduces new requirements to security-transparent code (you can read more about them here).

The problem is that GetObjectData() method required to implement ISearializable interface is marked with a SecurityCritical attribute and so this piece of your code "breaks" the transparency for the whole assembly.

The solution

We tried different approaches to solve this problem. Nothing helped.
The only working solution we found for now is to set the following two assembly-wide attributes in AssemblyInfo.cs file for your project:

[assembly: SecurityRules(SecurityRuleSet.Level1)]
[assembly: AllowPartiallyTrustedCallers]

So the solution is simply to lock your assembly into the .NET Framework 2.0 rules (level 1 transparency) and just ignore new security rules introduced in .NET 4.0

Unfortunately currently we can say nothing about any disadvantages of this solution. I'm going to publish an update to this post if we encounter some problem with it.

Any comments, notes, suggestions or links to other solutions of the described problem are welcome!

See also

Here are the links to articles where you can find more information about code access security and trust levels in ASP.NET applications:

Friday, July 19, 2013

A brief history of ASP.NET MVC framework.

ASP.NET MVC Framework appeared 10th of  December 2007 as a Community Technology Preview. Since that time millions of web-applications have being made with the help of this framework, millions of problems have been solved
Here are several articles which can tell us a little about the history of ASP.NET MVC:

Friday, July 12, 2013

Load Testing in the Cloud

Nice new functionality in Visual Studio 2013 (Ultimate).
Now you can check in advance whether your web site to cope with the expected heavy load.
No need to setup your own additional servers or virtual machines to organize and manage such a load. Just create a new project of "Web Performance and Load Test" type and Visual Studio will do the result.

Here is the original post in TFS blog with detailed instructions.