From Razor Helpers to MVC via NuGet

Over the last few days,  I have been working on a sample which shows how you can build your custom library of helpers using the Razor syntax and use NuGet to distribute this library as a package so that MVC or WebMatrix application developers can use this package of helpers. This is a great way of writing resuable helpers for most of the common tasks that developers would be doing and using NuGet distribution channel to reach out to all the developers.

To start off, you can write the Razor helpers in the Editor of your choice(VS / WebMatrix). You can then write a console application that parses all these helper files and generates a binary out of it. The following code snippet shows you how you can compile a number of helper files into a binary. This program takes in

a folder path where all helper files are located and generates a dll(RazorToMVCViaNuGet) in the same location.

 

 

    1: static void Main(string[] args)
    2: {
    3:     //Input: path to the folder where the helper files are
    4:     if (args.Count<string>() <= 0)
    5:     {
    6:         Console.WriteLine("please input the helper folder location");
    7:         return;
    8:     }
    9:     //folder where all helpers are stored
   10:     string helperLocation = args[0].ToString();
   11:     string helperdllName = "RazorToMVCViaNuGet.dll";
   12:     string RazorInstallLocation = System.Environment.Is64BitOperatingSystem ? System.Environment.GetEnvironmentVariable("ProgramFiles(x86)") : System.Environment.GetEnvironmentVariable("ProgramFiles");
   13:     string RazorBinaryLocation =RazorInstallLocation + @"\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies";
   14:     string[] compiledcode = new string[100];
   15:     int counter = 0;
   16:     //get the directory information for the helper filers
   17:     DirectoryInfo dir = new DirectoryInfo(helperLocation);
   18:     foreach (FileInfo file in dir.GetFiles())
   19:     {
   20:         if (file.Extension.Equals(".cshtml"))
   21:         {
   22:             //instantiate razor engine
   23:             StreamReader input = new StreamReader(file.FullName);
   24:             WebCodeRazorHost host = new WebCodeRazorHost(file.FullName);
   25:             RazorTemplateEngine engine = new RazorTemplateEngine(host);
   26:  
   27:             //parse the helper file and generate the CCU
   28:             GeneratorResults results = engine.GenerateCode(input);
   29:             CodeCompileUnit ccu = results.GeneratedCode;
   30:             CodeDomProvider codeProvider = (CodeDomProvider)Activator.CreateInstance(host.CodeLanguage.CodeDomProviderType);
   31:             StringBuilder output = new StringBuilder();
   32:             using (StringWriter writer = new StringWriter(output))
   33:             {
   34:                 codeProvider.GenerateCodeFromCompileUnit(ccu, writer, new CodeGeneratorOptions());
   35:             }
   36:             compiledcode[counter] = output.ToString();
   37:             counter++;
   38:         }
   39:         else
   40:             continue;
   41:     }
   42:  
   43:     //Generate a helper dll
   44:     CSharpCodeProvider provider = new CSharpCodeProvider();
   45:     // Build the parameters for source compilation.
   46:     CompilerParameters cp = new CompilerParameters();
   47:     // Add assembly reference to comile the dll
   48:     cp.ReferencedAssemblies.Add("System.dll");
   49:     cp.ReferencedAssemblies.Add("System.Web.dll");
   50:     cp.ReferencedAssemblies.Add("System.Security.dll");
   51:     cp.ReferencedAssemblies.Add("System.Core.dll");
   52:     cp.ReferencedAssemblies.Add(RazorBinaryLocation + "\\System.Web.WebPages.dll");
   53:     cp.ReferencedAssemblies.Add(RazorBinaryLocation + "\\WebMatrix.Data.dll");
   54:     //Generate Class Library
   55:     cp.OutputAssembly = helperLocation + "\\" + helperdllName;
   56:     cp.GenerateExecutable = false;
   57:     // Save the assembly as a physical file.
   58:     cp.GenerateInMemory = false;
   59:     // Invoke compilation.             
   60:     CompilerResults cr = provider.CompileAssemblyFromSource(cp, compiledcode);
   61:     if (cr.Errors.Count > 0)
   62:     {
   63:         // Display compilation errors.
   64:         Console.WriteLine("Errors building");
   65:         foreach (CompilerError ce in cr.Errors)
   66:         {
   67:             Console.WriteLine("  {0}", ce.ToString());
   68:             Console.WriteLine();
   69:         }
   70:     }
   71:     else
   72:     {
   73:         Console.WriteLine("Source success");
   74:     }
   75: }

For eg. the following picture shows the folder with the helper files, their content and the generated library. As you see in the picture the RazorToMVCViaNuGet.dll contains the compiled code the Razor Helpers.

Helperdll

At this point we have a binary which has all the helpers. In the next steps I will show you how to create a Nuget package for this RazorToMVCViaNuGet.dll and add it to the package feeds. Before I go any further you can get more information about installing Nuget and creating packages from Nuget Codeplex site. Make sure you download Nupack.exe along with downloading NuGet. This exe does not come with the Nuget download and has to be downloaded separately from the same place as Nuget

Now that you have NuGet and Nupack.exe, let’s create our package now.

1. Create a folder called Demohelperpackage

2. Create a .nuspec file based on the Nuspec format for a package. I created the following file DemoHelper.nuspec

    1: <?xml version="1.0"?>
    2: <package xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="https://www.w3.org/2001/XMLSchema">
    3:  <metadata xmlns="https://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
    4:    <id>RazorToMVCViaNuGet</id>
    5:    <version>1.1</version>
    6:    <authors>pranavra</authors>
    7:    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    8:    <description>Demo of how you can distribute razor helper using nuget</description>
    9:    <summary>Razor helper to MVC via NuGet</summary>
   10:  </metadata>
   11: </package> 
 3. Create a folder called lib under Demohelperpackage and copy RazorToMVCViaNuGet.dll to this location

4. copy nupack.exe to Demohelperpackage and run “NuPack.exe pack DemoHelper.nuspec” to generate the package

5. You would see the a RazorToMVCViaNuGet.1.1.nupkgnupkg file created in the same folder

Now that we have our package, we can test it out by having NuGet talk to a local feed rather than having NuGet talk to the official feed. You can refer how to do this from this page "Hosting Your Own Local and Remote NuPack Feeds"

Once you have this setup you can use the Package Manager Console to list and install the package that you had just created.

Create an ASP.NET MVC3 WebApplication to use this package in your project. Open the package manager console window.

To see the list of packages you can do list-package which would list out your package.

image

You can install the package using “Install-Package RazorToMVCViaNuGet” which would add the RazorToMVCViaNuGet.dll to your project

image

Once the package is installed a  reference to RazorToMVCViaNuGet is added in your project

image

You can now use the helpers in RazorToMVCViaNuGet .dll in your views.Notice there is no namespace needed for the helpers.

image

When you run the application then Wola!!!! you would see that you were able to distribute and use your helpers :)

image

This shows how easy it is to compile your own library of Razor helpers which you can distribute using NuGet to MVC/WebMatrix developers

Future Improvements

1. The sample only works for .cshtml file and can be extended for .vbhtml files as well

2. Nuspec for this helper can be extended to have a dependency on Microsoft.AspNet.WebPages to be installed.