Force Update .Net Core SDK Docker Image Using Drone

Since working with .NET Core from the release candidate days, the framework continues to get updated.  That’s a great thing, but living on the edge of a framework sometimes also comes with a few caveats.

The .NET Core work I’m doing gets deployed to Linux-based Docker containers.  The CI/CD process is driven by Drone.  Using this process, there are a few configuration files to maintain.  Being on the edge of .NET Core at this moment in time where there is a lot of churn in the framework and the tooling is all at a preview version, things get can get interesting.

When using Docker, you maintain a Dockerfile that serves as a configuration for the Docker image that your solution needs.  At the moment of this post, .NET core recently rev’d from version 1.0.0 to 1.0.1.  Living on the edge, I naturally updated my solution to use 1.0.1 and also updated the Dockerfile to use a 1.0.1 container:

FROM microsoft/dotnet:1.0.1-core

Everything’s good so far.  Now let’s ship it!  In order to do that, Drone also has its own configuration that has to be modified.  The first step in the drone configuration is pulling a Docker image to build the application and run the unit tests.  However, unlike my Dockerfile, we can’t use the runtime .NET Core Docker image for that.  Instead, the SDK image is needed:

build:
  compile:
    image: microsoft/dotnet:1.0.0-preview2-sdk
    commands:
      - dotnet restore
      - dotnet test ./tests/myproject.Tests
      - dotnet publish ./src/myproject/project.json --configuration Release

There’s one problem here, and it has to do with one of the great benefits of Docker – caching.  Docker images are ingeniously made up of pieces, or layers.  For instance, the official dotnet Docker image from Microsoft is made up of several dependencies (framework pieces, OS pieces, etc) each of which are tagged with a version in Docker Hub (the public Docker image repository).  Docker only downloads the pieces it needs to make up containers and uses pieces from cached Docker images when it can.  For some reason the maintainers of the dotnet SDK Docker image updated the image to use .NET Core 1.0.1 but didn’t update the Docker Hub image name from dotnet:1.0.0-preview2-sdk.  The result was when Drone ran the CI process, it saw the dotnet sdk image tag was the same and didn’t attempt to re-download the dotnet sdk image that contained the 1.0.1 update.  When Drone ran the CI process, it attempted to execute the project’s unit tests but couldn’t due to a .NET Core version mismatch because it was using a cached dotnet sdk Docker image that used .NET version 1.0.0.

The specified framework 'Microsoft.NETCore.App', version '1.0.1' was not found.
  - Check application dependencies and target a framework version installed at:
      /usr/share/dotnet/shared/Microsoft.NETCore.App
  - The following versions are installed:
      1.0.0

The fix to this is to force Drone to update the dotnet sdk Docker image.  Luckily I found a GitHub issue asking how to do that.  The answer was to add a command to force pull (note line 5 below) the image in the Drone config:

build:
  compile:
    image: microsoft/dotnet:1.0.0-preview2-sdk
    pull: true
    commands:
      - dotnet restore
      - dotnet test ./tests/myproject.Tests
      - dotnet publish ./src/myproject/project.json --configuration Release

Voila!  Drone force pulled the latest dotnet sdk Docker image that included .NET Core 1.0.1 and the deployment succeeded!

Tags: , Filled Under: Programming Posted on: September 27, 2016

Built-in Dependency Injection Support with .NET Core

With .NET Core, gone are the days of needing a 3rd party solution to implement Dependency Injection (DI).  DI support is built-in to the .NET Core framework, but getting this wired-up is a bit different depending on if you’re using ASP.NET Core or some other .NET Core project type.

Here’s an overview of the pieces we want to wire up:

class library for DI

The above shows a .NET Core (1.0 RTM) class library named SomeClassLibrary which is referenced by both a console app and a web app.  The class library contains an interface for a WidgetService that gets Widget object data from a WidgetRepository.

The Widget is an object with two properties, Id and Name:

namespace SomeClassLibrary.Domain
{
    public class Widget
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

The SomeConsoleApp and SomeWebApp projects will be loosely coupled to the WidgetService and WidgetRepository, therefore they’ll programs against their respective interfaces.

Here’s a look at the IWidgetService interface:

using System.Collections.Generic;
using SomeClassLibrary.Domain;

namespace SomeClassLibrary.Application
{
    public interface IWidgetService
    {
        List<Widget> GetAllWidgets();
    }
}

All this interface is doing is defining a method named GetAllWidgets that returns a list of Widget objects.  The concrete WidgetService class then gets the Widgets via the injected IWidgetRepository:

using System.Collections.Generic;
using System.Linq;
using SomeClassLibrary.Domain;

namespace SomeClassLibrary.Application
{
    public class WidgetService : IWidgetService
    {
        private readonly IWidgetRepository widgetRepository;

        public WidgetService(IWidgetRepository widgetRepository)
        {
            this.widgetRepository = widgetRepository;
        }

        public List<Widget> GetAllWidgets()
        {
            return this.widgetRepository.GetAll().ToList();
        }
    }
}

The IWidgetRepository interface exposes a method named GetAll() that returns an IEnumerable of Widget:

using System.Collections.Generic;

namespace SomeClassLibrary.Domain
{
    public interface IWidgetRepository
    {
        IEnumerable<Widget> GetAll();
    }
}

The concrete implementation of the WidgetRepository returns a hard-coded list of Widgets for the purposes of our demonstration:

using System.Collections.Generic;

namespace SomeClassLibrary.Domain
{
    public class WidgetRepository : IWidgetRepository
    {
        public IEnumerable<Widget> GetAll()
        {
            // send back some hard-coded data
            return new List<Widget>
            {
                new Widget { Id = 1, Name = "First Widget" },
                new Widget { Id = 2, Name = "Second Widget" }
            };
        }
    }
}

Let’s Use DI in the ASP.NET Core App

ASP.NET Core makes DI very easy.  By convention, the Startup.cs class will run at the beginning of the application lifecycle.  By default it has a ConfigureServices method that runs using a IServiceCollection parameter.  To implement DI, simply add the NuGet package Microsoft.Extensions.DependencyInjection and call the AddScoped extension to map an interface to a concrete class.

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SomeClassLibrary.Domain;
using SomeClassLibrary.Application;

namespace SomeWebApp
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // add descriptors for interfaces
            services.AddScoped<IWidgetRepository, WidgetRepository>();
            services.AddScoped<IWidgetService, WidgetService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IWidgetService widgetService)
        {
            loggerFactory.AddConsole();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.Run(async (context) =>
            {
                // use the resolved Widget service
                List<Widget> widgets = widgetService.GetAllWidgets();

                // if everything resolved, print out the Name property value of the first widget
                await context.Response.WriteAsync(widgets.FirstOrDefault().Name);
            });
        }
    }
}

The above code tells the ASP.NET Core app what concrete classes to use per interface used in the ConfigureServices method (lines 20-21).  Then when the app runs the IWidgetService (which in this case is passed in to the Configure method) resolves its concrete implementation and the service can be used (line 37).

Now Let’s Use DI in a .NET Core Console App

Using DI in a ASP.NET Core web app is fairly straight-forward because you’re provided the benefit of Startup.cs and its built-in service collection availability.  A console app starts with a static Main method that doesn’t take in an IServiceCollection, so where do you start?  I started by Googling around and ran in to this excellent Derp Turkey blog post.  Go ahead and give it a read, because it explains DI in a console app much more in depth than I do here.  The main reason that I’m re-explaining it is because that post was written for a beta of .NET Core and a few NuGet package names have slightly changed.

First install the NuGet package for Microsoft.Extensions.DependencyInjection.  In the Main method, start by defining a new ServiceCollection object and then add your interface descriptors just like you did for the web app (lines 18-19 below).

Next you’ll need an IServiceProvider instance to wire-up the service collection (line 22 below).  After that, you have access to your service and all its methods.

using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using SomeClassLibrary.Application;
using SomeClassLibrary.Domain;

namespace SomConsoleApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // create service collection
            IServiceCollection services = new ServiceCollection();

            // add descriptors for interfaces
            services.AddTransient<IWidgetRepository, WidgetRepository>();
            services.AddTransient<IWidgetService, WidgetService>();

            // create service provider
            IServiceProvider provider = services.BuildServiceProvider();

            // resolve the IWidgetService
            IWidgetService service = provider.GetService<IWidgetService>();

            // use the resolved Widget service
            List<Widget> widgets = service.GetAllWidgets();

            // if everything resolved, the list of hard-coded widgts will come back from the WidgetService
            foreach (var widget in widgets)
            {
                Console.WriteLine("Widget Details:");
                Console.WriteLine("  Id:" + widget.Id);
                Console.WriteLine("  Name: " + widget.Name);
                Console.WriteLine("\n");
            }

            Console.Read();
        }
    }
}

The above will use service’s wired-up DI implementation to resolve the concrete classes and return the fake data we have in the WidgetRepository.

All these code samples are in GitHub.

 

Tags: Filled Under: Programming Posted on: June 30, 2016

Serving Static Files Outside of wwwroot in Asp.NET Core 1.0

In ASP.NET Core 1.0 (which is out as RC2 at the time I’m writing this post), static content such as images, css files, javascript files, etc can be served up in the wwwroot folder once your web site contains the NuGet package for Microsoft.AspNetCore.StaticFiles.  But what if you wanted to serve up static files outside of wwwroot?  With a little work extending the application builder configuration, it is possible.

First, create a folder under the root (but outside of wwwroot) of the ASP.NET Core application.  In this example, I’ll name that folder ‘static’.  In this example, we’ll store static files within this folder.

Next, let’s create a static class (no pun intended) within the ASP.NET Core web application project to extend the ApplicationBuilder with a method that will allow for serving static content from this folder named ‘static’:

using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Internal;
using Microsoft.Extensions.FileProviders;

public static class ApplicationBuilderExtensions
{
	public static IApplicationBuilder UseStaticResources(this IApplicationBuilder app, HostingEnvironment env)
	{
		var path = Path.Combine(env.ContentRootPath, "static"); // this allows for serving up contents in a folder named 'static'
		var provider = new PhysicalFileProvider(path);

		var options = new StaticFileOptions();
		options.RequestPath = ""; // an empty string will give the *appearance* of it being served up from the root
		//options.RequestPath = "/content"; // this will use the URL path named content, but could be any made-up name you want
		options.FileProvider = provider;

		app.UseStaticFiles(options);
		return app;
	}
}

Let’s walk through what this is doing.  On line 9 it is getting the physical path of the newly created ‘static’ folder.  Now that the app knows where these files physically reside, let’s take advantage of some optional URL routing.  Shown above on line 15, I’m setting the RequestPath to an empty string.  What that will do is re-route requests for static files in the root path of the app to the physical ‘static’ folder.  That means an HTTP request like this:

<img src='foo.img' />

will be routed to look for the foo.img file in the physical folder named ‘static’.

Alternately, if I wanted to use the ‘content’ folder name (or any other name) in HTML calls for these static resources, I could do so as shown in the commented-out line #16.  In that line, the URL would use the ‘content’ route, which doesn’t physically exist but in fact gets re-routed to the ‘content’ physical path.  In this case, the resources physically sitting in the ‘static’ folder would be accessed using that re-written path like this:

<img src='/content/foo.img' />

Finally, line 19 is needed to give your app the ability to actually serve up static files within your application (you’ll still need to have the NuGet package Microsoft.AspNetCore.StaticFiles in order to make this work).

But in order to make this all work, we need to actually use this ApplicationBuilder extension.  To do that, open up the Start.cs file of the ASP.NET Core web application.  In Start.cs there is a method named Configure that gets called at runtime and configures the HTTP request pipeline.  It is within here that the call to the UseStaticResources method is needed:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
	app.UseStaticResources((HostingEnvironment)env);
	
	//... the rest of your Configure method calls go here
}

The above line #4 calls the method you created which allows for the serving up of static files from whatever folder you designated outside of wwwroot.

Update 7/1/2016 – Microsoft released their official documentation for working with static files in ASP.NET Core; definitely worth a read.

Tags: , Filled Under: Programming Posted on: June 3, 2016

Using PowerShell to Automate TortoiseSVN Updates

If you find yourself working with a code base using SVN for source control (bla..), then you may as well spend a few minutes automating the periodic updates you’ll need to get from trunk.

Let’s do this with TortoiseSVN and PowerShell.  If you haven’t set up a PowerShell profile, that’s will be the first step.  Details on how to do that can be found on this TechNet article, or follow these steps:

Open a Windows Powershell prompt by pressing the Windows key, type Powershell in the search box, then right-click the Windows Powershell icon and choose ‘Run as administrator’.  At the Windows PowerShell prompt, check if your PowerShell profile exists:

Test-path $profile

If it doesn’t exist, the result from the above command will be False.  To create a profile, execute this command:

New-item –type file –force $profile

Now that the PowerShell profile is created, you’ll see the following directory was created: C:\Users\{your user name}\Documents\WindowsPowerShell.  To edit the profile, you can either open it up in your text editor of choice or have PowerShell do that for you:

Notepad $profile

Next is to create a function in the PowerShell profile that will be used to update the your SVN repo from trunk:

function fn_update_trunk {tortoiseproc /command:update /path:"C:\Work\ProjectX\trunk"}

What the above line is doing is creating a function that uses the TortiseSVN Automation Commands to update your local repository.  In this example, the SVN update command is being performed on the pre-existing repository I have at C:\Work\ProjectX\trunk.

Save the PowerShell profile file and you’re almost ready.  The next step is to create an shortcut that can be clicked to run the automated process.  I have this shortcut on my desktop.  In order to create that, from the Windows desktop right-click and choose New -> Shortcut.  A window will appear prompting you for the location of the shortcut.  Place the following text in the location box:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -command fn_update_trunk

This needs to be the location of the PowerShell executable on your computer.  For ease of use, this is adding a parameter to bypass the PowerShell execution policy.  Finally, a command is added to run the function that was created in the profile to update the SVN repository.

Click the Next button and you’ll be prompted to name the shortcut.  Once the shortcut is created, click on it and it’ll open a PowerShell prompt which will then open TortiseSVN and automatically update your SVN trunk.

Tags: , Filled Under: Programming Posted on: June 18, 2015

Plugging Twilio SMS in to the ASP.NET Identity Message Service

If you want to enable 2-factor authentication in ASP.NET, ASP.NET Identity and Twilio make it silly easy to do so.

Step 1: Setting Up Your Project for ASP.NET Identity
From Visual Studio, start with an ASP.NET Web Application and select the MVC Template.  In this example I’ll use the Authentication option ‘Individual User Accounts’, which under the covers is really just adding the ASP.NET Identity NuGet packages for you.  For an existing application you could manually include the ASP.NET Identity NuGet packages, but I would take a look at the ASP.NET Identity Samples App first to get familiar with what it offers.

Create an MVC project with Individual Accounts.

Create an MVC project with Individual Accounts.

Congratulations, you now have an MVC application with ASP.NET Identity management!  In the App_Start folder a class file named IdentityConfig.cs was added by the NuGet package.

The IdentityConfig.cs file has multiple classes in it (StyleCop may have something to say about that), and the one that controls SMS is named SmsService.  Scroll down to it and you’ll see a single placeholder method to send an SMS message asynchronously.

SMS Service Class

The SmsService class in IdentityConfig.cs

Step 2: Set-up Twilio for SMS
Now it’s time for Twilio!  Sign up for a free Twilio account.  To do this simply press the ‘Sign Up’ button on the Twilio site and you’ll be prompted to create an account.  The account is free and you don’t need to enter in any payment information.  During the sign-up process it will ask to verify your mobile phone number prior to assigning you a phone number in your Twilio account.

The reason for verifying your own phone number first has to do with the free trial account that gets set up.  While in trial/sandbox mode, a phone number is created and made available to you for free, however one of the limitations is it can only communicate with a number you register and verify with Twilio.  More details of how a Twilio free trial account works can be found here.

Now that you have a Twilio account and phone number, you’ll need three pieces of information to get ASP.NET Identity 2-factor authentication via SMS working: your Twilio phone number, account SID, and Auth Token.  These can be found on the Twilio Account page.  Make a note of this information.

Twilio account page

You’ll need the Account SID, Auth Token, and your Twilio assigned phone number.

Now back to the ASP.NET application that you created.  Simply install the Twilio NuGet package to add support for their API.

PM> Install-Package Twilio

In the SmsService class in IdentityConfig.cs, the TwilioRestClient will be used to send the SMS messages supporting 2-factor authentication.

public class SmsService : IIdentityMessageService
{
	public Task SendAsync(IdentityMessage message)
	{
		// Plug in your sms service here to send a text message.
		// set our AccountSid and AuthToken
		string AccountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
		string AuthToken = "fXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

		// instantiate a new Twilio Rest Client
		var client = new TwilioRestClient(AccountSid, AuthToken);
		client.SendMessage("14085551111", message.Destination, message.Body);

		return Task.FromResult(0);
	}
}

In the above code, your Twilio Account SID and Auth Token are set to variables.  The TwilioRestClient takes them as parameters (more info about the TwilioRestClient can be found in this section of the Twilio docs).  The SendMessage method takes the following parameters: your Twilio assigned phone number, the recipient phone number, and the message.  The IdentityMessage object contains both the recipient (message.Destination) and the message text (message.Body).

Step 3: Using 2-factor Authentication For Your Account
Run your application and log in.  You can manage your account by clicking on your user name in the top right.  An account management screen is shown.

First add your phone number; it should be the same phone number that you verified when you created the Twilio account.

Add your phone number to your account

Click on the Add link to enter the phone number you previously verified when creating your Twilio account.

You’ll be asked to verify this phone number.  If you hooked up Twilio correctly within your app’s SmsService class, you will get a text with the verification code.  Enter that code to verify your phone number for the ASP.NET Identity service.

Enter verification code

Enter the code sent via SMS to verify your phone number.

Now enable 2-factor authentication on your account.

Enable two factor authentication for your account

Enable 2-factor authentication for your account.

To test it out, sign out of your app.  Log back in and you’ll first enter your username and password.  Next, you’ll be prompted to send a verification code for 2-factor authentication.

Enter verification code

Enter the received 2-factor verification code to complete login.

That code will be sent via SMS; enter it when prompted.  Once you press the Submit button, you’ll finally be logged in.

When you’re ready to go to production, upgrade your Twilio account and update that information in the SmsService class.

Tags: Filled Under: Programming Posted on: January 25, 2015