My First NuGet Package

I’ve been working on a project over the last year that was my first serious use of MVC, Git and Nuget. While I was working on part of the system that allowed users to upload documents I wrote a custom validator that would check the file extension was valid, the file didn’t exceed a maximum size and other little useful checks. Someone pointed out that it would be useful to have this as a NuGet package that we could use against other projects so I thought “why not?”.

I started by reading these articles by Scott Hanselman “Creating a NuGet Package in 7 easy steps” & “Updating and Publishing a NuGet Package” to get an idea of how to I needed to proceed.

I followed Scott’s instructions for creating the appropriate directory structure, adding the sub structure I needed for the package and ran nuget.exe to get the generated nuspec file.

Which I edited as above. I then added my validation C# and javascript files. For the C# file, I used the .pp extension to specify I wanted some pre-processing done on the file, editing the code to include the $rootnamespace$ for a cleaner integration into other projects.

using FluentValidation.Validators;

namespace $rootnamespace$.Models.Validation
    public class DocumentExtensionValidator : PropertyValidator

I was fairly sure my first attempt would fail and, since I didn’t want to publish the package without being able to test it, I found another very useful post about how to test your NuGet packages locally.

I packed it up and moved it to the newly created local repository. I quickly created a basic MVC project with a simple web page with a file uploader.

@model TestNugetBuild.Models.Home.IndexViewModel
    Layout = null;

<!DOCTYPE html>

    <meta name="viewport" content="width=device-width" />
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
        <label for="DocumentToUpload">Select a document to upload</label>
        @Html.TextBoxFor(x => x.Document, new { type = "file", @id = "DocumentToUpload", @class = "input-upload" })

        <button type="submit" class="btn btn--xs btn--secondary is-hidden" title="Upload document" id="addDocument">Upload document</button>
        @Html.ValidationMessageFor(m => m.Document, string.Empty, new { @class = "post-label error-label" })

As I expected, there was a problem. As I tried to add the validation code against the file object I realised I had neglected to register the validators. The methods were not being picked up and I really wanted this to be as easy for the user as possible, with no need for manually hooking the code in to the project. Back to Scott’s posts…

Sure enough, he had written in his 2nd post about including WebActivator to allow registration of various things at application startup. I added the files I needed to the package and edited the nuspec.

A minor change from Scott’s “Updating a Nuget Package” post: when I checked the WebActivator I found that (as expected) it is no longer at version 1.1. It is now also going by the ID “WebActivatorEx”. This is important, the ID needs to match or when you install your NuGet package and it looks for dependencies it won’t find it. My version of the AppStart file is as follows:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Web.Infrastructure;
using $rootnamespace$.Models.Validation;
using FluentValidation.Mvc;
using FluentValidation.Attributes;

[assembly: WebActivatorEx.PostApplicationStartMethod(typeof($rootnamespace$.AppStart_RegisterValidators), "Start")]
namespace $rootnamespace$ {
    public static class AppStart_RegisterValidators {
        public static void Start() {
            var fluentValidationProvider = new FluentValidationModelValidatorProvider(new AttributedValidatorFactory());
            fluentValidationProvider.Add(typeof(DocumentExtensionValidator), (metadata, context, rule, validator) => new DocumentExtensionValidatorAdaptor(metadata, context, rule, validator));
            fluentValidationProvider.Add(typeof(DocumentSizeValidator), (metadata, context, rule, validator) => new DocumentSizeValidatorAdaptor(metadata, context, rule, validator));
            fluentValidationProvider.Add(typeof(DocumentEmptyValidator), (metadata, context, rule, validator) => new DocumentEmptyValidatorAdaptor(metadata, context, rule, validator));
            fluentValidationProvider.Add(typeof(ImageDimensionValidator), (metadata, context, rule, validator) => new ImageDimensionValidatorAdaptor(metadata, context, rule, validator));
            fluentValidationProvider.AddImplicitRequiredValidator = false;

After packing and moving to my local repository, and installing the latest version, Intellisence now picked up the validator options correctly.

I have a few more general tweaks to do before it’s completely done, but the basic structure for the package is now there!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s