@Shazwazza

Shannon Deminick's blog all about web development

Installing .NET Core 1.01 on Ubuntu 16.10

October 23, 2016 23:03

TL;DR  You’ll need to manually install libicu55

image

Warning: Linux noob content below

I’ve been testing out some .NET Core cross platform stuff and originally had been using Ubuntu 14.04 with .NET Core 1.0.0 and that all worked fine along with the installation instructions from https://www.microsoft.com/net/core#ubuntu , however some of the latest tests I’ve been doing needed a MySQL version later than 5.5. It would seem that when I installed MySQL on Ubuntu 14.04 by executing apt-get mysql-server that I got 5.5 which was not compatible with what I needed. So attempting to upgrade gave me other issues for which I would require a later version of Ubuntu. Long story short, I’m a linux noob and I couldn’t get anything to upgrade, ended up executing all sorts of commands I didn’t understand and probably shouldn’t have and ultimately killed my Linux install.

So a clean install of Ubuntu 16.04 it was … there’s a catch though, you can choose between LTS (Long Term Support) or not. I chose not to since It’s a VM and I don’t mind newer updates, etc… Turns out that was a bad idea with .NET Core installs! It would seem that once the non LTS is installed you end up with 16.10 which has installed some newer versions of required libraries, namely something called libicu which is now on 57 instead of a required 55.

Trying to run the normal installation procedure from the web instructions mentioned above for 16.04 ended up telling me this:

sudo apt-get install dotnet-dev-1.0.0-preview2-003131

Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
dotnet-dev-1.0.0-preview2-003131 : Depends: dotnet-sharedframework-microsoft.netcore.app-1.0.1 but it is not going to be installed
E: Unable to correct problems, you have held broken packages.

So what the heck does that mean?! So after some Googling, I tried to just install the dependency:

sudo apt-get install dotnet-sharedframework-microsoft.netcore.app-1.0.1

Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
dotnet-sharedframework-microsoft.netcore.app-1.0.1 : Depends: libicu55 (>=55.1.1~) but it is not installable
E: Unable to correct problems, you have held broken packages.

Ok, not much further but I gather that I need libicu55 installed, so let’s try:

sudo apt-get install libicu55

Package libicu55 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package libicu55 has no installation candidate

Manual libicu55 installation

I suppose normal linux users would probably just know that you need to download and install libicu55 manually. Well it took a little bit of research for me to figure that out, but here’s what to do:

  • head over to http://packages.ubuntu.com/en/xenial/amd64/libicu55/download
  • click one of the mirror links to download the file
  • in Terminal, head to the folder you downloaded it (i.e. probably ~/Downloads)
  • install it using this command: sudo dpkg –i libicu55_55.1-7_amd64.deb  (or whatever file name you saved it as)

That should install just fine, then you can run sudo apt-get install dotnet-dev-1.0.0-preview2-003131 and everything will be fine again :)

ASMX SOAP Webservices with abstract models without using XmlInclude

July 22, 2016 10:12

I’m hoping this post might be useful to some folks out there that might be stuck using old ASMX/SOAP webservices in ASP.Net. If you’ve tried to return an abstract or superclass from an ASMX webservice without using XmlInclude or SoapInclude, you’ll get an error like:

System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type MyAwesomeClass was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write6_Item(String n, String ns, Item o, Boolean isNullable, Boolean needType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write10_Item(Object o)
   at Microsoft.Xml.Serialization.GeneratedAssembly.ItemSerializer.Serialize(Object objectToSerialize, XmlSerializationWriter writer)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
   at System.Web.Services.Protocols.XmlReturnWriter.Write(HttpResponse response, Stream outputStream, Object returnValue)
   at System.Web.Services.Protocols.HttpServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)
   at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)
   at System.Web.Services.Protocols.WebServiceHandler.Invoke()

The normal way to work around this is to attribute your ASMX class with [XmlInclude(typeof(MyAwesomeClass)] and repeat this for every subclass that you might be returning. This essentially tells the SOAP handler what types it should expect to serialize so it can ‘warm’ up a list of XmlSerializers.

The problem with this is that you need to know about all of these types up-front, but what if you have a plugin system where other developers can define their own types? There would be no way of knowing up-front what types to register so this approach will not work.

IXmlSerializer to the rescue

To work around this problem you can define a wrapper class for your abstract/superclass.  Working with IXmlSerializer is pretty annoying and I highly recommend this great article if you are going to use it since one mistake can cause all sorts of problems

The following class should work for any object. Also note the usage of the static dictionary to store references to created XmlSerializer instances since these are expensive to create per type.

public class SerializedObjectWrapper : IXmlSerializable
{
    /// <summary>
    /// The underlying Object reference that is being returned
    /// </summary>
    public object Object { get; set; }

    /// <summary>
    /// This is used because creating XmlSerializers are expensive
    /// </summary>
    private static readonly ConcurrentDictionary<Type, XmlSerializer> TypeSerializers 
        = new ConcurrentDictionary<Type, XmlSerializer>();

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        reader.MoveToContent();

        //Get the Item type attribute
        var itemType = reader.GetAttribute("ItemType");
        if (itemType == null) throw new InvalidOperationException("ItemType attribute cannot be null");
            
        //Ensure the type is found in the app domain
        var itemTypeType = Type.GetType(itemType);
        if (itemTypeType == null) throw new InvalidOperationException("Could not find the type " + itemType);

        var isEmptyElement = reader.IsEmptyElement;
                    
        reader.ReadStartElement();

        if (isEmptyElement == false)
        {
            var serializer = TypeSerializers.GetOrAdd(itemTypeType, t => new XmlSerializer(t));
            Object = serializer.Deserialize(reader);
            reader.ReadEndElement();
        }
    }

    public void WriteXml(XmlWriter writer)
    {
        var itemType = Object.GetType();
        var serializer = TypeSerializers.GetOrAdd(itemType, t => new XmlSerializer(t));
            
        //writes the object type so we can use that to deserialize later
        writer.WriteAttributeString("ItemType", 
            itemType.AssemblyQualifiedName ?? Object.GetType().ToString());

        serializer.Serialize(writer, Object);
    }
}

Usage

Here’s an example of the usage of the SerializedObjectWrapper class along with the example that would cause the above mentioned exception so you can see the difference:

public abstract class MyAbstractClass
{
}

public class MyAwesomeClass : MyAbstractClass
{
}

//WONT WORK
[WebMethod]
public MyAbstractClass GetStuff()
{
    return new MyAwesomeClass();
}

//WILL WORK
[WebMethod]
public SerializedObjectWrapper GetStuff()
{
    return new SerializedObjectWrapper
    {
        Object = new MyAwesomeClass()
    };
}

 

I know most people aren’t using AMSX web services anymore but in case your stuck on an old project or have inherited one, this might be of use :)

ASP.NET Core application shutdown events

June 3, 2016 09:39

While porting an existing library to ASP.NET Core I had to find the equivalent functionality of IRegisteredObject which I use for graceful shutdowns of running tasks in background threads. The newer & nicer approach to this in ASP.NET Core is Microsoft.AspNetCore.Hosting.IApplicationLifetime:

  /// <summary>
  /// Allows consumers to perform cleanup during a graceful shutdown.
  /// </summary>
  public interface IApplicationLifetime
  {
    /// <summary>
    /// Triggered when the application host has fully started and is about to wait
    /// for a graceful shutdown.
    /// </summary>
    CancellationToken ApplicationStarted { get; }

    /// <summary>
    /// Triggered when the application host is performing a graceful shutdown.
    /// Requests may still be in flight. Shutdown will block until this event completes.
    /// </summary>
    CancellationToken ApplicationStopping { get; }

    /// <summary>
    /// Triggered when the application host is performing a graceful shutdown.
    /// All requests should be complete at this point. Shutdown will block
    /// until this event completes.
    /// </summary>
    CancellationToken ApplicationStopped { get; }

    /// <summary>Requests termination the current application.</summary>
    void StopApplication();
  }

Unlike the old IRegisteredObject this interface is pretty clear on it’s functionality.

Registering a method to be called for any of the three operations is simple:

//register the application shutdown handler
 applicationLifetime.ApplicationStopping.Register(DisposeResources);

protected void DisposeResources()
{
    //Cleanup stuff when the app is shutting down
}

Obtaining an instance of IApplicationLifetime can be done during Startup.cs in the Configure method

public void Configure(IApplicationBuilder app, IApplicationLifetime applicationLifetime)
{
    // start your app
}

Happy coding!

Custom Assembly loading with Asp.Net Core

March 15, 2016 14:58

Building a plugin system in Asp.Net Core is a dream compared to previous Asp.Net versions!

In previous versions it was not really feasible to load Assemblies located outside of the /bin folder for a web application. I battled with this concept quite a long time ago and although it’s sort of possible, the notion of having a plugin system that supported loading DLLs from outside of the /bin folder was riddled with hacks/problems and not really supported OOTB.

A large part of the issues has to do with something called an ‘Assembly Load Context’. In traditional .Net there are 3 of these context types: “Load”, “LoadFrom” and “Neither”, here’s a very old but very relevant post about these contexts from Suzanne Cook. In traditional Asp.Net, the “Load” context is used as the default context and it is managed by something called Fusion (.Net’s normal Assembly Loader/Binder). The problem with this context is that it is difficult to load an assembly into it that isn’t located in Fusion’s probing paths (i.e. /bin folder). If you load in an Assembly with a different Assembly Load Context and then try to mix it’s Types with the Types from the default context  … you’ll quickly see that it’s not going to work.

The “Neither” context

Here is the Neither context definition as defined by Suzanne Cook:

If the user generated or found the assembly instead of Fusion, it's in neither context. This applies to assemblies loaded by Assembly.Load(byte[]) and Reflection Emit assemblies (that haven't been loaded from disk). Assembly.LoadFile() assemblies are also generally loaded into this context, even though a path is given (because it doesn't go through Fusion).

In Asp.Net Core (targeting CoreCLR), the default Assembly Load Context is the “Neither” context. This is a flexible context because it doesn’t use Fusion and  it allows for loading assemblies any way that you want - including loading an assembly from a byte array, from a path or by a name. Since all of Asp.Net Core uses this context it means that all of the types loaded in with this context can talk to each other without having the previous Asp.Net problems.

I would assume that Asp.Net Core targeting Desktop CLR would still operate the same as before and still have the 3 types of Assembly Load Context’s … Maybe someone over at Microsoft can elaborate on that one? (David Fowler… surely you know? :)

Finding referenced plugin assemblies

In many cases if you create a product that supports plugin types, developers will create plugins for your product and ship them via Nuget. This is a pretty standard approach since it allows developers that are using your product to install plugins from the Nuget command line or from within Visual Studio. In this case plugin types will be found in referenced assemblies to your application and will be automatically loaded. Asp.Net Core has an interface called Microsoft.Extensions.PlatformAbstractions.ILibraryManager that can be used to resolve your application’s currently referenced ‘Libraries’ (i.e Nuget packages) and then each ‘Library’ returned exposes the Assemblies that it includes. Asp.Net MVC 6 has an even more helpful interface called Microsoft.AspNet.Mvc.Infrastructure.IAssemblyProvider which returns a list of referenced assemblies that are filtered based on if they are assemblies that reference a subset of MVC assemblies. The default implementation of IAssemblyProvider (DefaultAssemblyProvider) is extensible and we can use it to override it’s property ReferenceAssemblies in order to supply our own product assembly names instead of the MVC ones. This is perfect since this allows us to get a list of candidate assemblies that might contain plugins for your product:

public class ReferencePluginAssemblyProvider : DefaultAssemblyProvider
{
    //NOTE: The DefaultAssemblyProvider uses ILibraryManager to do the library/assembly querying
    public ReferencePluginAssemblyProvider(ILibraryManager libraryManager) : base(libraryManager)
    {
    }

    protected override HashSet<string> ReferenceAssemblies 
        => new HashSet<string>(new[] {"MyProduct.Web", "MyProduct.Core"});
}

now if you want to get a list of candidate assemblies that your application is referencing you could do:

//returns all assemblies that reference your product Assemblies
var candidateReferenceAssemblies = referencedPluginAssemblyProvider.CandidateAssemblies;

Finding and loading non-referenced plugin assemblies

This is where things get fun since this is the type of thing that wasn’t really very feasible with traditional Asp.Net web apps. Lets say you have a plugin framework where a plugin is installed via your web app, not in Visual Studio and therefore not directly referenced in your project. For this example, the plugin is a self contained collection of files and folders which could consist of: Css, JavaScript, Razor Views, and Assemblies. This plugin model is pretty nice since to install the plugin would mean just dropping the plugin folder into the right directory in your app and similarly  to uninstall it you can just remove the folder.  The first step is to be able to load in these plugin Assemblies from custom locations. For an example, let’s assume the web app has the following folder structure:

  • App Root
    • App_Plugins <—This will be the directory that contains plugin folders
      • MyPlugin1
        • bin <—by convention we’ll search for Assemblies in the /bin folder inside of a plugin
        • Views
      • MyPlugin2
        • bin <—by convention we’ll search for Assemblies in the /bin folder inside of a plugin
        • css
    • Views
    • wwwroot

IAssemblyLoader

The first thing we need is an ‘Microsoft.Extensions.PlatformAbstractions.IAssemblyLoader’, this is the thing that will do the assembly loading into the Assembly Load Context based on an AssemblyName and a location of a DLL:

public class DirectoryLoader : IAssemblyLoader
{
    private readonly IAssemblyLoadContext _context;
    private readonly DirectoryInfo _path;

    public DirectoryLoader(DirectoryInfo path, IAssemblyLoadContext context)
    {
        _path = path;
        _context = context;
    }

    public Assembly Load(AssemblyName assemblyName)
    {
        return _context.LoadFile(Path.Combine(_path.FullName, assemblyName.Name + ".dll"));
    }

    public IntPtr LoadUnmanagedLibrary(string name)
    {
        //this isn't going to load any unmanaged libraries, just throw
        throw new NotImplementedException();
    }
}

IAssemblyProvider

Next up we’ll need a custom IAssemblyProvider but instead of using the one MVC ships with, this one will be totally custom in order to load and resolve the assemblies based on the plugin’s /bin folders. The following code should be pretty straight forward, the CandidateAssemblies property iterates over each found /bin folder inside of a plugin’s folder inside of App_Plugins. For each /bin folder found it creates a DirectoryLoader mentioned above and loads in each DLL found by it’s AssemblyName into the current Assembly Load Context.

/// <summary>
/// This will return assemblies found in App_Plugins plugin's /bin folders
/// </summary>
public class CustomDirectoryAssemblyProvider : IAssemblyProvider
{
    private readonly IFileProvider _fileProvider;
    private readonly IAssemblyLoadContextAccessor _loadContextAccessor;
    private readonly IAssemblyLoaderContainer _assemblyLoaderContainer;

    public CustomDirectoryAssemblyProvider(
            IFileProvider fileProvider, 
            IAssemblyLoadContextAccessor loadContextAccessor, 
            IAssemblyLoaderContainer assemblyLoaderContainer)
    {
        _fileProvider = fileProvider;
        _loadContextAccessor = loadContextAccessor;
        _assemblyLoaderContainer = assemblyLoaderContainer;
    }

    public IEnumerable<Assembly> CandidateAssemblies
    {
        get
        {
            var content = _fileProvider.GetDirectoryContents("/App_Plugins");
            if (!content.Exists) yield break;
            foreach (var pluginDir in content.Where(x => x.IsDirectory))
            {
                var binDir = new DirectoryInfo(Path.Combine(pluginDir.PhysicalPath, "bin"));
                if (!binDir.Exists) continue;
                foreach (var assembly in GetAssembliesInFolder(binDir))
                {
                    yield return assembly;
                }
            }
        }
    }

    /// <summary>
    /// Returns assemblies loaded from /bin folders inside of App_Plugins
    /// </summary>
    /// <param name="binPath"></param>
    /// <returns></returns>
    private IEnumerable<Assembly> GetAssembliesInFolder(DirectoryInfo binPath)
    {
        // Use the default load context
        var loadContext = _loadContextAccessor.Default;

        // Add the loader to the container so that any call to Assembly.Load 
        // will call the load context back (if it's not already loaded)
        using (_assemblyLoaderContainer.AddLoader(
            new DirectoryLoader(binPath, loadContext)))
        {
            foreach (var fileSystemInfo in binPath.GetFileSystemInfos("*.dll"))
            {
                //// In theory you should be able to use Assembly.Load() here instead
                //var assembly1 = Assembly.Load(AssemblyName.GetAssemblyName(fileSystemInfo.FullName));
                var assembly2 = loadContext.Load(AssemblyName.GetAssemblyName(fileSystemInfo.FullName));
                yield return assembly2;
            }
        }
    }
}

That’s pretty much it! If you have an instance of CustomDirectoryAssemblyProvider then you can get Assembly references to all of the assemblies found in App_Plugins:

//returns all plugin assemblies found in App_Plugins
var candidatePluginAssemblies = customDirectoryAssemblyProvider.CandidateAssemblies;

Integrating non-referenced plugins/Assemblies with MVC

What if you had custom plugin types as MVC Controllers or other MVC types? By default MVC only knows about assemblies that your project has references to based on the DefaultAssemblyLoader.  If we wanted MVC to know about Controllers that exist in a plugin not referenced by your project (i.e. in App_Plugins) then it’s a case of registering a custom IAssemblyProvider in IoC which will get resolved by MVC. To make this super flexible we can create a custom IAssemblyProvider that wraps multiple other ones and allows you to pass in a custom referenceAssemblies filter if you wanted to use this to resolve your own plugin types:

public class CompositeAssemblyProvider : DefaultAssemblyProvider
{
    private readonly IAssemblyProvider[] _additionalProviders;
    private readonly string[] _referenceAssemblies;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="libraryManager"></param>
    /// <param name="additionalProviders">
    /// If passed in will concat the assemblies returned from these 
    /// providers with the default assemblies referenced
    /// </param>
    /// <param name="referenceAssemblies">
    /// If passed in it will filter the candidate libraries to ones
    /// that reference the assembly names passed in. 
    /// (i.e. "MyProduct.Web", "MyProduct.Core" )
    /// </param>
    public CompositeAssemblyProvider(
        ILibraryManager libraryManager,
        IAssemblyProvider[] additionalProviders = null,
        string[] referenceAssemblies = null) : base(libraryManager)
    {
        _additionalProviders = additionalProviders;
        _referenceAssemblies = referenceAssemblies;
    }

    /// <summary>
    /// Uses the default filter if a custom list of reference
    /// assemblies has not been provided
    /// </summary>
    protected override HashSet<string> ReferenceAssemblies
        => _referenceAssemblies == null
            ? base.ReferenceAssemblies
            : new HashSet<string>(_referenceAssemblies);
    
    /// <summary>
    /// Returns the base Libraries referenced along with any DLLs/Libraries
    /// returned from the custom IAssemblyProvider passed in
    /// </summary>
    /// <returns></returns>
    protected override IEnumerable<Library> GetCandidateLibraries()
    {
        var baseCandidates = base.GetCandidateLibraries();
        if (_additionalProviders == null) return baseCandidates;
        return baseCandidates               
            .Concat(
            _additionalProviders.SelectMany(provider => provider.CandidateAssemblies.Select(
                x => new Library(x.FullName, null, Path.GetDirectoryName(x.Location), null, Enumerable.Empty<string>(),
                    new[] { new AssemblyName(x.FullName) }))));
    }
}

To register this in IoC you just need to make sure it’s registered after you register MVC so that it overrides the last registered IAssemblyProvider:

//Add MVC services
services.AddMvc();
//Replace the default IAssemblyProvider with the composite one
services.AddSingleton<IAssemblyProvider, CompositeAssemblyProvider>(provider =>
{
    //create the custom plugin directory provider
    var hosting = provider.GetRequiredService<IApplicationEnvironment>();
    var fileProvider = new PhysicalFileProvider(hosting.ApplicationBasePath);
    var pluginAssemblyProvider = new CustomDirectoryAssemblyProvider(
        fileProvider,         
        PlatformServices.Default.AssemblyLoadContextAccessor,
        PlatformServices.Default.AssemblyLoaderContainer);
    //return the composite one - this wraps the default MVC one
    return new CompositeAssemblyProvider(
        provider.GetRequiredService<ILibraryManager>(),
        new IAssemblyProvider[] {pluginAssemblyProvider});
});

 

Your all set! Now you have the ability to load in Assemblies from any location you want, you could even load them in as byte array’s from an external data source.  What’s great about all of this is that it just works and you can integrate these external Assemblies into MVC.

Some things worth noting:

  • Parts of the assembly loading APIs are changing a bit in Asp.Net Core RC2: https://github.com/aspnet/Announcements/issues/149
  • The above code doesn’t take into account what happens if you load in the same Assembly from multiple locations. In this case, the last one in wins/is active AFAIK – I haven’t tested this yet but I’m pretty sure that’s how it works.
  • You may have some issues if load in the same Assembly more than once from multiple locations if those Assemblies have different strong names, or major versions applied to them – I also haven’t tested this yet

AppVeyor and ASP.Net Core (Previously ASP.Net 5)

February 12, 2016 16:23

Last year I created a runtime Js/Css pre-processor for ASP.Net Core (Previously ASP.Net 5) called “Smidge” and have been meaning to blog about how I integrated this with AppVeyor – to run my tests, build the project and output the Nuget files I need, so here it goes…

The build script

I use Powershell for my build scripts for my projects since it’s reasonably easy to read and the same script format has worked quite well for ASP.Net Core projects too. You can see the whole build file here. Here’s the important things to note:

With AppVeyor (and probably other build servers), you need to ensure that it actually has the dnx version you need:

# ensure the correct version
& $DNVM install 1.0.0-rc1-update1

Next you need to make sure that the current process is using the version you need to build:

# use the correct version
& $DNVM use 1.0.0-rc1-update1

Then we need to use DNU to make sure that your project has everything it needs to build:

& $DNU restore "$ProjectJsonPath"

Lastly it’s just building and packaging the project:

& $DNU build "$ProjectJsonPath"
& $DNU pack "$ProjectJsonPath" --configuration Release --out "$ReleaseFolder"

The rest of the build file is normal Powershell bits.

The test script

I’m using xunit for unit tests in this project and similarly to the build script I’m using a simple Powershell script to execute the tests on the build server, the test runner file is here. The important parts are just like the above: Ensure the correct version is installed and being used by the current process and making sure that the project has everything it needs to build and finally to build it. The last missing piece is to actually run the tests:

& $DNX -p "$TestsFolder" test

Where ‘test’ is a command defined in my project.json as part of my unit test project.

AppVeyor configuration

The good news is that there’s really not a lot to setup, it’s super easy. In your AppVeyor settings just go to the ‘Build’ section and tell it to execute the Powershell script with its build version information:

image

Then for the unit tests is basically the same, click on the ‘Tests’ section and tell it to execute the Powershell test script:

image

And that’s pretty much it! The only other part I’ve had to setup is the paths to my Artifacts (Nuget files) based on the current build number.

Now whenever I commit, AppVeyor will execute the build script and test script and we can see the output:

image

And it’s smart enough to know that the test runner executed is for unit tests, so all the unit test output shows up in the ‘Tests’ tab of the build

image

Now that that’s all setup, AppVeyor even gives you a handy Nuget feed that you can use to test your packages based on each build, this can be configured on the ‘NuGet’ settings section, for example here’s the Smidge feed: https://ci.appveyor.com/nuget/smidge

Smidge 1.0.0-RC3

It’s worth noting that I’ve also released a new version of Smidge since I finally had some time to work on it. Couple of bugs fixed in this release and also a handy new feature too! You can see the release notes here: https://github.com/Shazwazza/Smidge/releases/tag/1.0.0-rc3.  I’ve also updated a lot of the documentation, the main readme file was getting quite long so I’ve moved all of the docs over to the project’s Wiki on GitHub and condensed the readme for the most important bits. Have a look here: https://github.com/Shazwazza/Smidge

Making a DynamicObject implementation be case insensitive

February 5, 2016 13:25

To me this seems to be a very straight forward request but I cannot find the ‘easy’ way to do this in .Net even though there seems to be a clear indication that this is supported Out of The Box. Here’s an example of what I want to do:

//Simple class
public class Foo
{
    public string Hello {get;set;}
    public string World {get;set;}
    public int AddNumbers(int num1, int num2)
    {
        return num1 + num2;
    }
}

//Use the simple class but allow case insensitive
// access to it's properties and members
var foo = new Foo{ Hello = "hi", World = "earth" };

//make it dynamic
dynamic dFoo = foo;

//access the dynamic object's props and methods 
// in a case insensitive way:
Assert.AreEqual(foo.Hello, dFoo.hello);
Assert.AreEqual(foo.World, dFoo.world);
Assert.AreEqual(foo.AddNumbers(1,2), dFoo.addNumbers(1,2));

DynamicObject

In order to do the above, you can implement ‘DynamicObject’ and override a couple of methods:

public class Foo : DynamicObject
{
    public string Hello {get;set;}
    public string World {get;set;}
    public int AddNumbers(int num1, int num2)
    {
        return num1 + num2;
    }
    
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        //Here we would need to match lower cased binder.Name
        // to a real method that our object has
        var name = binder.Name.ToLowerInvariant();
        //TODO: Do the matching
        
        return base.TryInvokeMember(binder, args, out result);
    }
    
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        //Here we would need to match lower cased binder.Name
        // to a real property that our object has
        var name = binder.Name.ToLowerInvariant();
        //TODO: Do the matching
        
        return base.TryGetMember(binder, out result);
    }
}

I don’t know about you, but I’d rather not have to write all the code to do the matching and executing. This seems like a pretty straight forward thing to want to do and after looking at the innards of some of this stuff, it turns out that the ‘GetMemberBinder’ object has a property conveniently called `IgnoreCase`… surely this functionality already exists!?

Well I unfortunately cannot find anything worthwhile on Google about ‘GetMemberBinder.IgnoreCase’, I also can’t really see where or how it gets used when looking at decompiled sources.

So I’ve reverted to handling this on my own but I would really really really like to know if there’s a built in and simple way to do this in .Net since it sure seems like it should exist.

CaseInsensitiveDynamicObject

This is a base class implementation to achieve what I want. It’s not error proof and I’m sure with some objects it won’t work 100% as expected but for simple objects this will work. Using this implementation is super easy:

public class Foo : CaseInsensitiveDynamicObject
{
    public string Hello {get;set;}
    public string World {get;set;}
    public int AddNumbers(int num1, int num2)
    {
        return num1 + num2;
    }
}

By doing that, my original requirement works! Here’s the code that does this … because I was lazy and didn’t want to create more classes than I needed I’m using Tuples so the code is fully of super generic fun ;)

/// <summary>
/// This will check enable dynamic access to properties and methods in a case insensitive manner
/// </summary>
/// <typeparam name="T"></typeparam>
/// <remarks>
/// This works by using reflection on the type - the reflection lookup is lazy so it will not execute unless a dynamic method needs to be accessed
/// </remarks>
public abstract class CaseInsensitiveDynamicObject<T> : DynamicObject
    where T: class
{
    /// <summary>
    /// Used for dynamic access for case insensitive property access
    /// </summary>`
    private static readonly Lazy<IDictionary<string, Func<T, object>>> CaseInsensitivePropertyAccess = new Lazy<IDictionary<string, Func<T, object>>>(() =>
    {
        var props = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .DistinctBy(x => x.Name);
        return props.Select(propInfo =>
        {
            var name = propInfo.Name.ToLowerInvariant();
            Func<T, object> getVal = propInfo.GetValue;
            return new KeyValuePair<string, Func<T, object>>(name, getVal);

        }).ToDictionary(x => x.Key, x => x.Value);
    });

    /// <summary>
    /// Used for dynamic access for case insensitive property access
    /// </summary>
    private static readonly Lazy<IDictionary<string, Tuple<ParameterInfo[], Func<T, object[], object>>>> CaseInsensitiveMethodAccess
        = new Lazy<IDictionary<string, Tuple<ParameterInfo[], Func<T, object[], object>>>>(() =>
        {
            var props = typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public)
                .Where(x => x.IsSpecialName == false && x.IsVirtual == false)
                .DistinctBy(x => x.Name);
            return props.Select(methodInfo =>
            {
                var name = methodInfo.Name.ToLowerInvariant();
                Func<T, object[], object> getVal = methodInfo.Invoke;
                var val = new Tuple<ParameterInfo[], Func<T, object[], object>>(methodInfo.GetParameters(), getVal);
                return new KeyValuePair<string, Tuple<ParameterInfo[], Func<T, object[], object>>>(name, val);

            }).ToDictionary(x => x.Key, x => x.Value);
        });

    /// <summary>
    /// Used for dynamic access for case insensitive method access
    /// </summary>
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        var name = binder.Name.ToLowerInvariant();
        if (CaseInsensitiveMethodAccess.Value.ContainsKey(name) == false)
            return base.TryInvokeMember(binder, args, out result);

        var val = CaseInsensitiveMethodAccess.Value[name];
        var parameters = val.Item1;
        var callback = val.Item2;
        var fullArgs = new List<object>(args);
        if (args.Length <= parameters.Length)
        {
            //need to fill them up if they're optional
            for (var i = args.Length; i < parameters.Length; i++)
            {
                if (parameters[i].IsOptional)
                {
                    fullArgs.Add(parameters[i].DefaultValue);
                }
            }
            if (fullArgs.Count == parameters.Length)
            {
                result = callback((T)(object)this, fullArgs.ToArray());
                return true;
            }
        }
        return base.TryInvokeMember(binder, args, out result);
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        var name = binder.Name.ToLowerInvariant();
        if (CaseInsensitivePropertyAccess.Value.ContainsKey(name) == false)
            return base.TryGetMember(binder, out result);

        result = CaseInsensitivePropertyAccess.Value[name]((T)(object)this);
        return true;
    }
}

 

If anyone know how to make this work OOTB with .Net, perhaps using the `GetMemberBinder.IgnoreCase` I’d love to hear it!

Isolated WebApi attribute routing

January 17, 2016 12:39

Attribute routing in ASP.Net WebApi is great and makes routing your controllers quite a bit more elegant than writing routes manually. However one problem I have with it is that it is either “on” or “off” at an application level.  There is no way for a library developer to tell ASP.Net to create routes based on attributes for specific controllers or assemblies without forcing the consumer of that library to enable Attribute Routing for the whole application. In many cases this might not matter, but if you are creating a package or library of that contains it’s own API routes, you probably don’t want to interfere with a developers’ normal application setup. There should be no reason why they need to be forced to turn on attribute routing in order for your product to work, and similarly they might not want your routes automatically enabled.

The good news is that this is possible. With a bit of code, you can route your own controllers with attribute routing and be able to turn them on or off without affecting the default application attribute routes. A full implementation of this has been created for the Umbraco RestApi project so I’ll reference that source in this post for the following code examples.

Show me the code

They key to getting this to work is: IDirectRouteProvider, IDirectRouteFactory

The first thing we need is a custom IDirectRouteFactory which is actually a custom attribute. I’ve called this CustomRouteAttribute  but you could call it whatever you want.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class CustomRouteAttribute : Attribute, IDirectRouteFactory

This custom attribute just wraps the default WebApi RouteAttribute’s IDirectRouteFactory implementation so we don’t have to re-write any code for that.

(see full implementation here)

Next we’ll create a custom IDirectRouteProvider:

/// <summary>
/// This is used to lookup our CustomRouteAttribute instead of the normal RouteAttribute so that 
/// we can use the CustomRouteAttribute instead of the RouteAttribute on our controlles so the normal
/// MapHttpAttributeRoutes method doesn't try to route our controllers - since the point of this is
/// to be able to map our controller routes with attribute routing explicitly without interfering
/// with default application routes.
/// </summary>
public class CustomRouteAttributeDirectRouteProvider : DefaultDirectRouteProvider
{
    private readonly bool _inherit;

    public CustomRouteAttributeDirectRouteProvider(bool inherit = false)
    {
        _inherit = inherit;
    }

    protected override IReadOnlyList<IDirectRouteFactory> GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
    {
        return actionDescriptor.GetCustomAttributes<CustomRouteAttribute>(inherit: _inherit);
    }
}

So far this is all pretty straight forward so far but here’s where things start to get interesting. Because we only want to create routes for specific controllers, we need to use a custom IHttpControllerTypeResolver. However, since the HttpConfiguration instance only contains a single reference to the IHttpControllerTypeResolver we need to do some hacking. The route creation process for attribute routing happens during the HttpConfiguration initialization so we need to create an isolated instance of HttpConfiguration, set it up with the services we want to use, initialize it to create our custom routes and assign those custom routes back to the main application’s HttpConfiguration.

Up first, we create a custom IHttpControllerTypeResolver to only resolve the controller we’re looking for:

public class SpecificControllerTypeResolver : IHttpControllerTypeResolver
{
    private readonly IEnumerable<Type> _controllerTypes;

    public SpecificControllerTypeResolver(IEnumerable<Type> controllerTypes)
    {
        if (controllerTypes == null) throw new ArgumentNullException("controllerTypes");
        _controllerTypes = controllerTypes;
    }

    public ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)
    {
        return _controllerTypes.ToList();
    }
}

Before we look at initializing a separate instance of HttpConfiguration, lets look at the code you’d use to enable all of this in your startup code:

//config = the main application HttpConfiguration instance
config.MapControllerAttributeRoutes(
    routeNamePrefix: "MyRoutes-",
    //Map these explicit controllers in the order they appear
    controllerTypes: new[]
    {                    
        typeof (MyProductController),
        typeof (MyStoreController)
    });

The above code will enable custom attribute routing for the 2 specific controllers. These controllers will be routed with attribute routing but instead of using the standard [Route] attribute, you’d use our custom [CustomRoute] attribute. The MapControllerAttributeRoutes extension method is where all of the magic happens, here’s what it does:

  • Iterates over each controller type
  • Creates an instance of HttpConfiguration
  • Sets it’s IHttpControllerTypeResolver instance to SpecificControllerTypeResolver for the current controller iteration (The reason an instance of HttpConfiguration is created for each controller is to ensure that the routes are created in the order of which they are specified in the above code snippet)
  • Initialize the HttpConfiguration instance to create the custom attribute routes
  • Copy these routes back to the main application’s HttpConfguration route table

You can see the full implementation of this extension method here which includes code comments and more details on what it’s doing.  The actual implementation of this method also allows for some additional parameters and callbacks so that each of these routes could be customized if required when they are created.

 

There is obviously a bit of code involved to achieve this and there could very well be a simpler way, however this implementation does work rather well and offers quite a lot of flexibility. I’d certainly be interested to hear if other developers have figured this out and what their solutions were.

All about ASP.Net File Change Notification (FCN)

October 15, 2015 10:45

There’s a chance you might not have heard of FCN (File Change Notification) in ASP.Net and there’s an even bigger chance you didn’t realize how much it might affect you.

What is FCN in ASP.Net?

As you know ASP.Net monitors a few files/folders such as the ~/web.config and ~/App_Code and will restart your app domain when it detects changes. This is part of FCN in ASP.Net but it goes much deeper than that. There are a few other files & folders that ASP.Net monitors which will also cause an app domain restart: bin, App_WebReferences, App_GlobalResources, App_Code, Global.asax, and others. However what you might not realize is that ASP.Net actually monitors every single folder (+ files) in your web app!

Update 29/07/2016! I found a nice MS article about FCN here. I’ve been looking for more resources about this since a few new issues have been cropping up and I’m wondering if another MS update has caused another problem. Recently we’ve seen an increase in the error: “Overwhelming Change Notification in …” which has everything to do with FCN. I’ve also added a few links to the bottom of this post.

Why do I care?

If you have a web app that contains a lot of folders there is a good chance that the performance of your file system is affected in one way or another. To give you an example of how many file system watchers ASP.Net generates I created a Razor view (.cshtml)  (which you should definitely test on your own site!) to display what is actually happening behind the scenes. Here’s the output for the first run page from the Visual Studio 2015 MVC template site:

image

The table above lists all of the “DirectoryMonitor” instances and the folder they are attached to along with all of the “FileMonitor” instances attached to that DirectoryMonitor. It’s worth nothing that these are not simply just .Net’s FileSystemWatcher, but some sort of native windows IO using a delegate called NativeFileChangeNotification. The above table doesn’t seem too scary but these monitors are not static either, they grow with every directory and file that is accessed in your web app.  For example, if I navigate to these pages: /Home/About, /Home/Contact, /Account/Register, /Account/Login and go back to view this table it looks like:

image

Things start to get interesting when you have a web application that has a lot of folders. Some examples of this might be:

  • You are using a dynamic image processor such as Image Resizer or Image Processor since these will create a lot of folders based on hashes to store these dynamic images
  • Maybe you have a lot of members/users on your site and you have one or more folders for each one
  • Maybe you use nodejs or bower and you store these generated folders in your web root and references the assets directly in those folders … there can be tons of folders in bower_components and node_modules
  • You could be using a web framework or CMS like Umbraco or Orchard (I’m sure there are plenty of others) that contain quite a lot of folders by default

Here’s the truncated result of an Orchard site after visiting the admin area, creating a page and displaying it:

image

Whoa!

ASP.Net’s FCNMode

At some stage in ASP.Net’s lifetime somebody must have complained about this to Microsoft and they released a hotfix (seen here: https://support.microsoft.com/en-us/kb/911272). Then I can only assume that other people complained about this and with .Net 4.5 a new configuration setting appeared: FCNMode. This documentation explains a little about what each option does:

  • Default - For each subdirectory, the application creates an object that monitors the subdirectory. This is the default behavior
  • Disabled - File change notification is disabled.
  • NotSet - File change notification is not set, so the application creates an object that monitors each subdirectory. This is the default behavior.
  • Single - The application creates one object to monitor the main directory and uses this object to monitor each subdirectory.

Unfortunately these docs don’t tell us the whole story. It’s obvious that Default/NotSet are the same thing and are the default. Disabled is fairly clear but what it doesn’t mention is that if you set it to Disabled, this will disable all FCN for your web app, so if you change the contents of /bin or /App_Code, the site will not restart. However, Disabled still means that the web.config file is monitored so if you use this setting you can still bump your web.config to restart your site.

What exactly is “Single” though?

The folks over at DNN seem to have quite a bit of experience with FCN and this article seems to be the only place that actually explains “Single” mode correctly:

“FCNMode creates a monitor object with a buffer size of 4KB for each folder. When FCNMode is set to Single, a single monitor object is created with a buffer size of 64KB. When there are file changes, the buffer is filled with file change information. If the buffer gets overwhelmed with too many file change notifications an “Overwhelming File Change Notifications” error will occur and the app domain will recycle. The likelihood of the buffer getting overwhelmed is higher in an environment where you are using separate file server because the folder paths are much larger.”

If I change fcnMode=”Single” in my web.config for the same Orchard site above, the results are:

image

That’s quite a bit less!

I’m sure there are pros to using “Default” instead of “Single” but I’m not actually sure what they are.

Real world problem

The circumstance where “Default” FCN mode becomes a real problem is when you have a website that is running off of a remote file share.  As noted in Shawn Walker’s DNN article mentioned above:

“The likelihood of the buffer getting overwhelmed is higher in an environment where you are using separate file server because the folder paths are much larger.”

I can’t actually see a performance difference between Default or Single when running locally with an SSD HD, but I have seen some big issues running with Default when hosting on a remote file server:

  • Constant app domain restarts – I’ve seen constant app domain restarts even when a site is just serving requests without any IO activity apart from just reading. And by ‘Constant’ … I mean every few seconds all day long.
  • File server performance suffers severely – When multiple sites are active and are being hosted on a remote file server with Default FCNMode, the writing performance of the file server is drastically degraded even though when monitoring IOPS there doesn’t appear to be any issues

To solve this issue we changed fcnMode=”Single” in the machine.config so that all sites would effectively use “Single”… and the result was instant: No more constant app restarts, file server performance was instantly back to normal. And as far as I can tell, there has been no downside to running FCNMode in Single.

So I really wonder what the up-side of Default is when it seems that running in Single mode is perfectly stable running on any hosting environment… ?

FCN doesn’t appear to be a thing with aspnetcore!

More info?

Updated 13/08/2018 – I wrote an FCN Viewer tool and wrote some more in-depth info about FCN and more of it’s quirks here: https://shazwazza.com/post/fcn-file-change-notification-viewer-for-aspnet/

Here’s a list of helpful links about FCN in ASP.Net:

Updated 29/07/2016! – More links I’ve discovered. Turns out this has been an issue for IIS + ASP.Net for quite some time with various older hotfixes, some of these new links might shed some light on the particular problem you might be having.

Configuring ASP.Net Identity OAuth login providers for multi-tenancy

March 26, 2015 01:48

Say for example you have a CMS :) You want to give full control to the developer to manage how their front-end members with authenticate, which could of course include ASP.Net Identity OAuth login providers. At the same time you want to easily allow your CMS to be configured so that ASP.Net Identity OAuth providers can be used for logging into the back office.  In this scenario, the same OAuth provider might be used for both front-end and back-office authentication but authenticated under 2 different OAuth accounts. Another example might be if you have multi-tenancy set up for your front-end site and perhaps you want to use the same OAuth login provider but have members authenticate with different OAuth accounts for different domain names.

The defaults

As an example, lets assume that front-end members are configured to authenticate with the ASP.Net Identity Google OAuth2 provider. This is easily done by just following one of the many tutorials out there. Your startup code might look like:

app.UseCookieAuthentication(new CookieAuthenticationOptions ....

app.UseExternalSignInCookie();

app.UseGoogleAuthentication(
              clientId: "123456789...",
              clientSecret: "987654321....");

Great, but I need 2 (or more) Google OAuth2 providers, so what now? I can’t just add 2 declarations of:

app.UseGoogleAuthentication(
              clientId: "123456789...",
              clientSecret: "987654321....");

app.UseGoogleAuthentication(
              clientId: "abcdef...",
              clientSecret: "zyxwv....");

you’ll quickly realize that doesn’t work and only one provider instance will actually be used. This is because of the default underlying settings that get used to instantiate the Google provider. Let’s have a look at what the default options are in this case. The above code is equivalent to this:

app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = "Google",
    ClientId = "123456789...",
    ClientSecret = "987654321....",
    Caption = "Google",
    CallbackPath = new PathString("/signin-google"),
    AuthenticationMode = AuthenticationMode.Passive,
    SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(),
    BackchannelTimeout = TimeSpan.FromSeconds(60),
    BackchannelHttpHandler = new System.Net.Http.WebRequestHandler(),
    BackchannelCertificateValidator = null,
    Provider = new GoogleOAuth2AuthenticationProvider()
});

The AuthenticationType

One very important aspect of the default settings is the AuthenticationType. This is a unique identifier for the provider instance and this is one of the reasons why if you have 2 x UseGoogleAuthentication declarations with the defaults only one will ever be used.

Knowing this, it’s clear that each declaration of UseGoogleAuthentication needs to specify custom options and have the AuthenticationType unique amongst them. So we might end up with something like:

//keep defaults for front-end
app.UseGoogleAuthentication(
    clientId: "123456789...",
    clientSecret: "987654321....");

//custom options for back-office
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = "GoogleBackOffice",
    ClientId = "abcdef...",
    ClientSecret = "zyxwv...."    
});

If you test this now, you’ll find out that only the first declaration is actually working even when you explicitly tell IOwinContext.Authentication.Challenge to use the “GoogleBackOffice” provider.

The CallbackPath

The reason that the default (first) declaration is the one that activates is because the response from Google is sending the request to the path: “/signin-google”, which is the default. The GoogleAuthenticationMiddleware will delegate to the GoogleAuthenticationHandler for each request and inspect the request to see if it should execute. For this logic it checks:

if (Options.CallbackPath.HasValue && Options.CallbackPath == Request.Path)
{
     //If the path matches, auth the request...
}

Since the CallbackPath will be the same by default on both above declarations, the first one that is registered will match and the other registered authenticators will be ignored. To fix this we’ll need to update the path that Google sends back and then update the second declaration to match that path.

To tell Google to send the request back on a different path, in your Google Developers Console change the REDIRECT URIS value for the second provider:

image_thumb

Then we need to update the 2nd declaration with the custom CallbackPath so that it matches and activates properly:

app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = "GoogleBackOffice",
    ClientId = "abcdef...",
    ClientSecret = "zyxwv....",
    CallbackPath = new PathString("/custom-signin-google")
});

Hooray, now it should work!

This concept is the same for most external login providers. For example for the Facebook one the default value is “/signin-facebook”, you’d need to configure Facebook’s “Valid OAuth redirect URIs” property with the correct callback path in Facebook’s developer portal:

image_thumb1

What is SignInAsAuthenticationType?

The last thing to point out is that by default the SignInAsAuthenticationType for each provider will resolve to: app.GetDefaultSignInAsAuthenticationType(), which by default is: DefaultAuthenticationTypes.ExternalCookie  = “ExternalCookie”. Each OAuth provider is linked to another middleware that is responsible for actually issuing a user’s ClaimsIdentity, so by default this will be “ExternalCookie”. In some cases you won’t want the default external cookie authentication middleware to assign the ClaimsIdentity for your OAuth provider, you might need to issue a different ClaimsIdentity or just have more granular control over what happens with the callback for each OAuth provider. In this case you’ll need to specify another custom cookie authentication declaration, for example:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = "CustomExternal",
    AuthenticationMode = AuthenticationMode.Passive,
    CookieName = "MyAwesomeCookie",
    ExpireTimeSpan = TimeSpan.FromMinutes(5),
    //Additional custom cookie options....
});

And then you can link that up to your OAuth declaration like:

//custom options for back-office
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = "GoogleBackOffice",
    ClientId = "abcdef...",
    ClientSecret = "zyxwv....",
    SignInAsAuthenticationType = "CustomExternal"
});

Using AspNet5 OptionsModel

January 12, 2015 04:21

If you’ve used AspNet5 then you’ve probably been using some MVC, in which case you’ve probably seen something like this in your Startup class:

// Add MVC services to the services container
services.AddMvc(configuration)
    .Configure<MvcOptions>(options =>
    {
        //Configure some MVC options like customizing the 
        // view engines, etc...
        options.ViewEngines.Insert(0, typeof(TestViewEngine));
    });

It turns out this syntax for specifying ‘options’ for a given service is a generic pattern that you can use in your own code. In fact the OptionsModel framework is it’s own code repository: https://github.com/aspnet/Options

I’ve implemented custom options in my AspNet5 project called Smidge (a runtime JavaScript/CSS pre-processing engine) and wanted to share the details since as far as I’ve seen there isn’t any documentation about this.

What are options?

Probably the simplest way to describe the options framework is that: Options allow you to configure your application via code during startup.

Options are just a POCO class that can contain configuration options to customize the behavior of your library. These option classes can be injected into any of your services with IoC using an interface called Microsoft.Framework.OptionsModel.IOptions. There’s a caveat to this POCO class however: It must contain an parameter-less/empty constructor which means you cannot have services injected into the your options class via it’s constructor.  This options framework also allows for ‘named’ options. So for example, perhaps you have a single options class that you would like to have configured in 2 different ways, one for ‘staging’ and one for your ‘live’ website.

Creating options

Here’s a really simple example of a POCO options class:

public class CustomMessageOptions
{
    public CustomMessage()
    {
        Message = "";
    }

    public string Message { get; set; }
}

In order to use this options class you need to create an options configuration class. For example:

public class CustomMessageOptionsSetup : ConfigureOptions<CustomMessageOptions>
{
    public CustomMessageOptionsSetup() 
    : base(ConfigureMessageOptions)
    {
    }

    /// <summary>
    /// Set the default options
    /// </summary>
    public static void ConfigureMessageOptions(CustomMessageOptions options)
    {
        options.Message = "Hello world";
    }
}

Then you need to add this class to your IoC container of type Microsoft.Framework.OptionsModel.IConfigureOptions:

services.AddTransient<IConfigureOptions<CustomMessageOptions>, CustomMessageOptionsSetup>();

Using options

To configure your options during startup, you do so in the ConfigureServices method like:

services.Configure<CustomMessageOptions>(options =>
{
    options.Message = "Hello there!";
});

Now you can have these options injected into any of your services using the IOptions interface noted previously:

public class MyCoolService 
{
    public MyCoolService(IOptions<CustomMessageOptions> messageOptions)
    {
        //IOptions exposes an 'Options' property which resolves an instance
        //of CustomMessageOptions
        ConfiguredMessage = messageOptions.Options.Message;
    }

    public string ConfiguredMessage {get; private set;}
}

Named options

As an example, lets say that you want a different message configured for your ‘staging’ and ‘live’ websites. This can be done with named options, here’s an example:

services
    .Configure<CustomMessageOptions>(options =>
    {
        options.Message = "Hi! This is the staging site";
    }, "staging")
    .Configure<CustomMessageOptions>(options =>
    {
        options.Message = "Hi! This is the live site";
    }, "live");

Then in your service you can resolve the option instance by name:

public class MyCoolService 
{
    public MyCoolService(IOptions<CustomMessageOptions> messageOptions)
    {
        //IRL This value would probably be set via some environment variable
        var configEnvironment = "staging";

        //IOptions exposes an 'GetNamedOptions' method which resolves an instance
        //of CustomMessageOptions based on a defined named configuration
        ConfiguredMessage = messageOptions.GetNamedOptions(configEnvironment);
    }

    public string ConfiguredMessage {get; private set;}
}

Configuring options with other services

Since your options class is just a POCO object and must have a parameter-less/empty constructor, you cannot inject services into the options class. However, there is a way to use IoC services in your options classes by customizing the ConfigureOptions class created above.  In many cases this won’t be necessary but this really depends on how you are using options.  As a (bad) example, lets say we wanted to expose a custom helper service called SiteHelper on the CustomMessageOptions class that can be used by a developer to create the message. The end result syntax might look like:

services.Configure<CustomMessageOptions>(options =>
    {
        var siteId = options.SiteHelper.GetSiteId();
        options.Message = "Hi! This is the staging site with id: " + siteId;
    });

In order for that to work the options.SiteHelper property needs to be initialized. This is done with the CustomMessageOptionsSetup class (created above) which has been added to the IoC container, this means it can have other services injected into it. The resulting class would look like:

public class CustomMessageOptionsSetup : ConfigureOptions<CustomMessageOptions>
{
    //SiteHelper gets injected via IoC
    public CustomMessageOptionsSetup(SiteHelper siteHelper) 
    : base(ConfigureMessageOptions)
    {
        SiteHelper = siteHelper;
    }

    public SiteHelper SiteHelper { get; private set; }

    /// <summary>
    /// Set the default options
    /// </summary>
    public static void ConfigureMessageOptions(CustomMessageOptions options)
    {
        options.Message = "Hello world";
    }

    /// <summary>
    /// Allows for configuring the options instance before options are set
    /// </summary>
    public override void Configure(Bundles options, string name = "")
    {
        //Assign the site helper instance
        options.SiteHelper = SiteHelper;

        base.Configure(options, name);
    }
}

IRL to give you an example of why this might be useful, in my Smidge project I allow developers to create named JavaScript/CSS bundles during startup using options. In some cases a developer might want to manipulate the file processing pipeline for a given bundle and in that case they need access to a service called PreProcessPipelineFactory which needs to come from IoC. The usage might look like:

services.AddSmidge()
    .Configure<Bundles>(bundles =>
    {                   
        bundles.Create("test-bundle-3", 
            bundles.PipelineFactory.GetPipeline(
                //add as many processor types as you want
                typeof(DotLess), typeof(JsMin)), 
            WebFileType.Js, 
            "~/Js/Bundle2");
    });

In the above, the bundles.PipelineFactory is a property on the bundles (options) class which gets initialized in my own ConfigureOptions class.

 

Hopefully this helps anyone looking to use custom options in their AspNet5 libraries!