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.
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.
You can install the package using “Install-Package RazorToMVCViaNuGet” which would add the RazorToMVCViaNuGet.dll to your project
Once the package is installed a reference to RazorToMVCViaNuGet is added in your project
You can now use the helpers in RazorToMVCViaNuGet .dll in your views.Notice there is no namespace needed for the helpers.
When you run the application then Wola!!!! you would see that you were able to distribute and use your helpers :)
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.