Installing and Configuring a UPS with Windows 10

The power grid at my home office is sometimes unreliable. In the last year there have been several power outages ranging from several hours to transient outages of a few seconds.

My main PC is a silent desktop which means (unlike a laptop) has no resilience to power outages. This is where an external uninterruptable power supply (UPS ) comes in handy. A UPS is like a big battery that gets charged from main power, but when there is an outage the battery kicks in and provides power to connected devices.

When choosing a UPS, generally speaking, the more expensive they are the longer they can provide power to connected devices (or provide the same or more power for a longer time). Having researched typical power consumptions and armed with the knowledge that my PC uses SSDs, is fan-less, and does not have a high-powered GPU something in the 1000-1500 VA range was required. My main requirement was the ability to save work and safely shut down the PC before loosing all power. If I had more complex energy requirements I would have first purchased a power meter to measure how much power my devices were using before choosing the UPS.

Installing the UPS

Once I understood the approximate power requirements, I selected the Smart-UPS 1000VA LCD 230V from APC.

APC Smart-UPS 1000VA LCD 230V Front

The rear of the unit consists of a number of sockets, for the outputs there are 2 distinct groups that can be configured differently. For example the main group can have the PC and one of the monitors connected. The secondary power group can have non-essential devices attached, in my case the powered studio monitor speakers. The UPS was configured to turn off the secondary group if there is a power outage but after a 15 second delay; this will help with short transient outages. The main group will remain on for as long as the UPC battery has power. There are many different ways to configure this UPS by using the LCD display and front buttons, including the ability to enable/disable audible notifications.

APC Smart-UPS 1000VA LCD 230V rear panel

The rear panel also has a USB connector that can be connected to the PC.

Configuring Windows 10 Power Settings for a UPS

Once everything had been connected (including the UPS-PC USB cable) it can all be switched on. Once the UPS battery is fully charged, turning off the main power at the power outlet causes the UPS to switch to battery power, the PC and single monitor stay on and 15 seconds later the speakers turn off (to save power). Once on battery, the PC and monitor draw about 50W of power and the estimated run time according to the UPS LCD  is about 2 hours.

Because of the USB connection to the PC, Windows 10 also displays the battery status in the system tray:

Windows 10 UPS Battery status

If a power outage occurs when using the PC, once the battery gets low I can manually shutdown the PC to prevent damage/data loss. If however the PC is unattended at the time, I still want it to be safely shutdown.

To do this in Windows 10, type “power & sleep settings” in the start menu and configure the basic settings. From here, “Additional power settings can be opened” and power plans customized. Once in the plan settings, the “Change advanced power settings” can be selected to get down into the fine details:

Opening additional power settings

Once in the detailed Power Options dialog, in additional to other settings I opened the Battery section and changed the critical battery level to be 20% and the critical battery action to Hibernate. I also modified some o the other battery settings. 20% for critical is very conservative as I wanted to hibernate the PC with plenty of UPS battery capacity remaining.

Hibernating Windows 10 when critical UPS battery level reached

Now when on UPS battery power, Windows will warn me when the battery gets low (I configured this to be 40%) and then auto-hibernate at 20% battery.

It’s a great feeling to know that even when there is a storm blowing in that I will not loose any work and that my main PC hardware is protected from surges and unexpected power loss.

Testing ASP.NET Core Controllers in Isolation with Mock Objects and Moq

In previous posts we saw how to get started testing ASP.NET Core MVC controllers and also how to use the Moq mocking library in .NET Core tests.

If there is code in controllers that needs testing, but the controller has a dependency, for example passed into the constructor, it may not make sense to use the real version of the dependency. In these cases Moq can be used to create a mock version of the dependency and pass it to the controller that needs testing.

As an example suppose we have the following controller code:

public class HomeController : Controller
{
    private readonly ISmsGateway _smsGateway;

    public HomeController(ISmsGateway smsGateway)
    {
        _smsGateway = smsGateway;
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Send(SendSmsRequest request)
    {
        if (ModelState.IsValid)
        {
            var sendReceipt = _smsGateway.Send(request.PhoneNumber, request.Message);

            return Ok(sendReceipt);
        }

        return BadRequest();
    }
}

In the preceding code, the controller takes an ISmsGateway dependency as a constructor parameter. This dependency is later used in the the Send() method.

After installing Moq a mock SMS gateway can be created. Once created, Moq’s Setup() method can be used to determine what happens when the controller calls the mocked Send() method as the following code demonstrates:

[Fact]
public void ShouldSendOk()
{
    SendSmsRequest sendSmsRequest = new SendSmsRequest
    {
        PhoneNumber = "42",
        Message = "Hello"
    };

    Guid expectedSendReceipt = Guid.NewGuid();

    var mockSmsGateway = new Mock<ISmsGateway>();
    
    mockSmsGateway.Setup(x => x.Send(sendSmsRequest.PhoneNumber, sendSmsRequest.Message))
                  .Returns(expectedSendReceipt);

    var sut = new HomeController(mockSmsGateway.Object);
    
    IActionResult result = sut.Send(sendSmsRequest);

    var okObjectResult = Assert.IsType<OkObjectResult>(result);

    Assert.Equal(expectedSendReceipt, okObjectResult.Value);
}

We may also want to test that if there is a model binding error, then  no message is sent via the SMS gateway. The follow test code shows the use of the AddModelError() method to simulate an error, and the use of Moq’s Verify() method to check that the gateway’s Send() method was never called:

[Fact]
public void ShouldNotSendWhenModelError()
{
    SendSmsRequest sendSmsRequest = new SendSmsRequest
    {
        PhoneNumber = "42",
        Message = "Hello"
    };

    var mockSmsGateway = new Mock<ISmsGateway>();

    var sut = new HomeController(mockSmsGateway.Object);
    sut.ModelState.AddModelError("Simulated", "Model error");

    sut.Send(sendSmsRequest);

    mockSmsGateway.Verify(x => x.Send(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
}

To learn how to get started testing ASP.NET Core MVC applications check out my ASP.NET Core MVC Testing Fundamentals Pluralsight course.

Paying Your Software Development Tax

In software development we already have the technical debt metaphor that helps describe the the fact that a quick and dirty approach now, may create problems in the future. For example getting a feature into production sooner but compromising the quality/design/testability/etc. may make future changes harder or more costly: hence paying interest over time for the technical debt that was just created.

The technical debt metaphor is easily relatable to by non-developers and can help facilitate discussions with business owners/stakeholders.

In the real world, paying interest is an acceptable part of life and loans in various forms are not seen as problematic for the majority of people in modern society.

Even though they are an essential part of society however, most people dislike the thought of taxes.

Would the metaphor of a software development tax provide a more visceral reaction and encourage higher quality software where appropriate?

For example, there are “taxes” that come from everyday software development, such as bug fixing or introducing code duplication. Rather than saying “this will add some technical debt to the project…”, we could say “that’s going to increase the amount of tax we have to pay to deliver this…”.

Testing ASP.NET Core MVC Controllers: Getting Started

When writing ASP.NET Core MVC web applications, you may want to test that controller actions behave in the expected way, for example that the action returns the correct result type (e.g. a ViewResult) or that the action behaves as expected when the model state is invalid.

To get started writing controller tests, first add a new .NET Core xUnit test project to the solution. This will create the test project along with requried xUnit.net NuGet packages. It will also add a default test class "UnitTest1.cs":

using System;
using Xunit;

namespace WebApplication1.Tests
{
    public class UnitTest1
    {
        [Fact]
        public void Test1()
        {
        }
    }
}

In the preceding code, notice the xUnit.net [Fact] attribute that marks the Test1 method as a test that should be executed by the test runner. One way to run tests in Visual Studio is to use the built-in Test Explorer which can be accessed via the menus: Test->Windows->Test Explorer.

If you build the project you will see the default test shown in the Test Explorer window:

Visual Studio Test Explorer

Adding a Controller Test

First, to get access to the controllers in the ASP.NET Core MVC application, add a reference to the web project from the test project. An instance of a controller can now be created in the test method:

var sut = new WebApplication1.Controllers.HomeController();

We can now call methods (actions) on the controller and verify the results. As a simple example, we can check that the Index method result is a view:

[Fact]
public void Test1()
{
    HomeController sut = new WebApplication1.Controllers.HomeController();

    IActionResult result = sut.Index();

    Assert.IsType<ViewResult>(result);
}

There are many different ways to test the results of controllers, including the ability to simulate model errors or using Moq mock objects as controller constructor dependencies.

The following code shows an excerpt from a controller and a test that examines the view's model that was returned:

public class PersonViewModel
{
    public string Name { get; set; }
}

public IActionResult Person()
{
    PersonViewModel viewModel = new PersonViewModel
    {
        Name = "Amrit"
    };

    return View(viewModel);
}
[Fact]
public void Test2()
{
    HomeController sut = new WebApplication1.Controllers.HomeController();

    IActionResult result = sut.Person();

    ViewResult viewResult = Assert.IsType<ViewResult>(result);

    PersonViewModel model = Assert.IsType<PersonViewModel>(viewResult.Model);

    Assert.Equal("Amrit", model.Name);
}

To learn how to get started testing ASP.NET Core MVC applications check out my ASP.NET Core MVC Testing Fundamentals Pluralsight course.

Mocking in .NET Core Tests with Moq

When writing automated tests it is sometimes useful to isolate the thing(s) being tested from other parts of the system. These ‘other’ parts may still need to be provided, and sometimes the real versions are too hard or cumbersome to use. In these instances “mocked” versions can be created and used.

A mock version of something is an object that can act like the real thing but can be controlled in test code.

Moq (pronounced “mok u” or “mock”) is a library available on NuGet that allows mock objects to be created in test code and it also supports .NET Core.

Moq allows the manipulation of mock objects in many ways, including setting mock methods to return specific values, setting up properties, and matching specific arguments when the thing being tested calls the mock object.

For example, the following code shows a class that requires a constructor dependency to be able to operate:

using System;

namespace Domain
{
    public interface IThingDependency
    {
        string JoinUpper(string a, string b);
        int Meaning { get; }
    }

    // "Real" implementation
    public class ThingDependency : IThingDependency
    {
        public string JoinUpper(string a, string b)
        {
            throw new NotImplementedException();
        }

        public int Meaning => throw new NotImplementedException();
    }

    // Class we want to test in isolation of ThingDependency
    public class ThingBeingTested
    {
        private readonly IThingDependency _thingDependency;

        public string FirstName { get; set; }
        public string LastName { get; set; }

        public ThingBeingTested(IThingDependency thingDependency)
        {
            _thingDependency = thingDependency;
        }

        public string X()
        {
            var fullName = _thingDependency.JoinUpper(FirstName, LastName);

            return $"{fullName} = {_thingDependency.Meaning}";
        }
    }
}

Without a mock object, to write a test we could use the real ThingDependency:

[Fact]
public void TestUsingRealDependency()
{
    var sut = new ThingBeingTested(new ThingDependency());

    // test code
}

To isolate the ThingBeingTested from the rest of the system, Moq can create a mock version of an IThingDependency:

[Fact]
public void TestUsingMockDependency()
{
    // create mock version
    var mockDependency = new Mock<IThingDependency>();

    // set up mock version's method
    mockDependency.Setup(x => x.JoinUpper(It.IsAny<string>(), It.IsAny<string>()))
                  .Returns("A B");

    // set up mock version's property
    mockDependency.Setup(x => x.Meaning)
                  .Returns(42);

    // create thing being tested with a mock dependency
    var sut = new ThingBeingTested(mockDependency.Object);

    var result = sut.X();

    Assert.Equal("A B = 42", result);
}

In the preceding code, the Setup() method is used to tell the mock how to behave when it is called by the ThingBeingTested.

Moq can also be used to test the correct interactions are occurring between the ThingBeingTested and the IThingDependency:

[Fact]
public void TestUsingMockDependencyUsingInteractionVerification()
{
    // create mock version
    var mockDependency = new Mock<IThingDependency>();

    // create thing being tested with a mock dependency
    var sut = new ThingBeingTested(mockDependency.Object)
    {
        FirstName = "Sarah",
        LastName = "Smith"
    };

    sut.X();

    // Assert that the JoinUpper method was called with Sarah Smith
    mockDependency.Verify(x => x.JoinUpper("Sarah", "Smith"), Times.Once);

    // Assert that the Meaning property was accessed once
    mockDependency.Verify(x => x.Meaning, Times.Once);
}

In the preceding code, the Verify method is used to check that the mock JoinUpper method is being called exactly once with the values “Sarah” and “Smith”. The test code is also expecting the method to be called exactly once.

Moq can be used to test in isolation other parts of applications such as ASP.NET Core MVC controllers, where the controller requires a dependency (such as an IFooRepository):

[Fact]
public void ContollerTest()
{            
    var mockDependency = new Mock<IFooRepository>();

    var sut = new HomeController(mockDependency.Object);
    
    // test code
}

Check out the quickstart for more information on the features of Moq.

To learn how to get started testing ASP.NET Core MVC check out my ASP.NET Core MVC Testing Fundamentals Pluralsight course.

FeatureToggle v4 RC2 with .NET Core Configuration Changes

FeatureToggle logo

The pre-release RC2 version of FeatureToggle with .NET Core support is now available on NuGet.

See release notes and GitHub issues for additional background/breaking changes/limitations.

RC2 builds on RC1 and modifies the format of the json settings to make use of nesting as discussed in this issue, for example:

{
  "FeatureToggle": {
    "Printing": "true",
    "Saving": "false"
  }
}

Thanks to @steventmayer for the suggestions.

Architecting Azure Functions: Function Timeouts and Work Fan-Out with Queues

When moving to Azure Functions or other FaaS offerings it’s possible to fall into the trap of “desktop development’ thinking, whereby a function is implemented as if it were a piece of desktop code. This may negate the benefits of Azure Functions and may even cause function failures because of timeouts. An Azure Function can execute for 5 minutes before being shut down by the runtime when running under a Consumption Plan. This limit can be configured to be longer in the host.json (currently to a mx of 10 minutes). You could also investigate something like Azure Batch.

Non Fan-Out Example

Azure functions flow

In this initial attempt, a blob-triggered function is created that receives a blob containing a data file. Each line has some processing performed on it (simulated in the following code) and then writes multiple output blobs, one for each processed line.

using System.Threading;
using System.Diagnostics;

public static void Run(TextReader myBlob, string name, Binder outputBinder, TraceWriter log)
{
    var executionTimer = Stopwatch.StartNew();

    log.Info($"C# Blob trigger function Processed blob\n Name:{name}");

    string dataLine;
    while ((dataLine = myBlob.ReadLine()) != null)
    {
        log.Info($"Processing line: {dataLine}");
        string processedDataLine = ProcessDataLine(dataLine);
        
        string path = $"batch-data-out/{Guid.NewGuid()}";
        using (var writer = outputBinder.Bind<TextWriter>(new BlobAttribute(path)))
        {
            log.Info($"Writing output line: {dataLine}");
            writer.Write(processedDataLine);
        }
    }

    executionTimer.Stop();

    log.Info($"Procesing time: {executionTimer.Elapsed}");
     
}

private static string ProcessDataLine(string dataLine)
{
    // Simulate expensive processing
    Thread.Sleep(1000);

    return dataLine;
}

Uploading a normal sized input data file may not result in any errors, but if a larger file is attempted then you may get a function timeout:

Microsoft.Azure.WebJobs.Host: Timeout value of 00:05:00 was exceeded by function: Functions.ProcessBatchDataFile.

Fan-Out Example

Embracing Azure Functions more, the following pattern can be used, whereby there is no processing in the initial function. Instead the function just divides up each line of the file and puts it on a storage queue. Another function is triggered from these queue messages and does the actual processing. This means that as the number of messages in the queue grows, multiple instances of the queue-triggered function will be created to handle the load.

Azure functions fan-out flow

public async static Task Run(TextReader myBlob, string name, IAsyncCollector<string> outputQueue, TraceWriter log)
{
    log.Info($"C# Blob trigger function Processed blob\n Name:{name}");

    string dataLine;
    while ((dataLine = myBlob.ReadLine()) != null)
    {
        log.Info($"Processing line: {dataLine}");
        
        string path = $"batch-data-out/{Guid.NewGuid()}";
        
        await outputQueue.AddAsync(dataLine);
    }
}

And the queue-triggered function that does the actual work:

using System;
using System.Threading; 

public static void Run(string dataLine, out string outputBlob, TraceWriter log)
{
    log.Info($"Processing data line: {dataLine}");

    string processedDataLine = ProcessDataLine(dataLine);

    log.Info($"Writing processed line to blob: {processedDataLine}");
    outputBlob = processedDataLine;
}


private static string ProcessDataLine(string dataLine)
{
    // Simulate expensive processing
    Thread.Sleep(1000);

    return dataLine;
}

When architecting processing this way there are other limits which may also cause problems such as (but not limited to) queue scalability limits.

To learn more about Azure Functions, check out my Pluralsight courses: Azure Function Triggers Quick Start  and  Reducing C# Code Duplication in Azure Functions.

Multiple Platform Targeting in Visual Studio 2017

Suppose you are creating a library that has a central set of features and also additional features that are only available on some platforms. This means that when the project is built there are multiple assemblies created, one for each platform.

One way to achieve multi platform targeting is to create a number of separate projects, for example one for .NET Core , one for UWP, another one for .NET framework, etc. Then a shared source code project can be added and referenced by each of these individual projects; when each project is built separate binaries are produced. I’ve used this approach in the past, for example when working on FeatureToggle but is a little clunky and results in many projects in the solution.

Another approach is to have a single project that is not limited to a single platform output, but rather compiles  to multiple platform assemblies.

For example, in Visual Studio 2017, create a new .NET Core class library project called TargetingExample and add a class called WhoAmI as follows:

using System;

namespace TargetingExample
{
    public static class WhoAmI
    {
        public static string TellMe()
        {
            return ".NET Core";
        }
    }
}

After building the following will be created: "…\MultiTargeting\TargetingExample\TargetingExample\bin\Debug\netcoreapp1.1\TargetingExample.dll". Notice the platform directory “netcoreapp1.1”.

If we add a new .NET Core console app project and reference the TargetingExample project:

using System;
using TargetingExample;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(WhoAmI.TellMe());
            Console.ReadLine();
        }
    }
}

This produces the output: .NET Core

If we edit the FeatureToggle.csproj file it looks like the following (notice the TargetFramework element has a single value netcoreapp1.1):

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>
</Project>

The file can be modified as follows (notice the plural <TargetFrameworks>):

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netcoreapp1.1;net461;</TargetFrameworks>
  </PropertyGroup>
</Project>

Building now produces: "…\MultiTargeting\TargetingExample\TargetingExample\bin\Debug\netcoreapp1.1\TargetingExample.dll" and  "…\MultiTargeting\TargetingExample\TargetingExample\bin\Debug\net461\TargetingExample.dll"”.

A new Windows Classic Desktop Console App project can now be added (and the .NET framework version changed to 4.6.1) and a reference to TargetingExample  added.

using System;
using TargetingExample;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(WhoAmI.TellMe());
            Console.ReadLine();
        }
    }
}

The new console app contains the preceding code and when run produces the output: .NET Core.

Now we have a single project compiling for multiple target platforms. We can take things one step further by having different functionality depending on the target platform. One simple way to do this is to use conditional compiler directives as the following code shows:

using System;

namespace TargetingExample
{
    public static class WhoAmI
    {
        public static string TellMe()
        {
#if NETCOREAPP1_1
            return ".NET Core";
#elif NETFULL
            return ".NET Framework";
#else
            throw new NotImplementedException();  // Safety net in case of typos in symbols
#endif
        }
    }
}

The preceding code relies on the conditional compilation symbols being defined, this can be done by editing the project file once again as follows:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netcoreapp1.1;net461;</TargetFrameworks>
  </PropertyGroup>

  <PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp1.1' ">
    <DefineConstants>NETCOREAPP1_1</DefineConstants>
  </PropertyGroup>
  
  <PropertyGroup Condition=" '$(TargetFramework)' == 'net461' ">
    <DefineConstants>NETFULL</DefineConstants>
  </PropertyGroup>
</Project>

Now when the project is built, the netcoreapp1.1\TargetingExample.dll will return “.NET Core” and net461\TargetingExample.dll will return “.NET Framework”. Each dll has been compiled with different functionality depending on the platform.

Update: The explicit <DefineConstants> for the different platforms are not required if you want to use the defaults, e.g. "NETCOREAPP1_1", "NET461", etc as per this Twitter thread and GitHub.

FeatureToggle v4 RC1 with .NET Core Support

The pre-release RC1 version of FeatureToggle with .NET Core support is now available on NuGet.

See release notes and GitHub issues for additional background/breaking changes/limitations.

The main drive for v4 is to add initial .NET Core support.

Using Feature Toggle in a .NET Core Console App

In Visual Studio 2017, create a new .NET Core Console App and install the NuGet package. This will also install the dependent FeatureToggle.NetStandard package (.NET Standard 1.4).

Add the following code to Program.cs:

using System;
using FeatureToggle;

namespace ConsoleApp1
{

    public class Printing : SimpleFeatureToggle { }
    public class Saving : EnabledOnOrAfterDateFeatureToggle { }
    public class Tweeting : EnabledOnOrAfterAssemblyVersionWhereToggleIsDefinedToggle { }

    class Program
    {
        static void Main(string[] args)
        {
            var p = new Printing();
            var s = new Saving();
            var t = new Tweeting();

            Console.WriteLine($"Printing is {(p.FeatureEnabled ? "on" : "off")}");
            Console.WriteLine($"Saving is {(s.FeatureEnabled ? "on" : "off")}");
            Console.WriteLine($"Tweeting is {(t.FeatureEnabled ? "on" : "off")}");


            Console.ReadLine();
        }
    }
}

Running the application will result in an exception due to missing appSettings.config file: “System.IO.FileNotFoundException: 'The configuration file 'appSettings.json' was not found and is not optional.“ By default, FeatureToggle will expect toggles to be configured in this file, add an appSettings.json and set its Copy To Output Directory to “Copy if newer” and add the following content:

{
  "FeatureToggle.Printing": "true",
  "FeatureToggle.Saving": "01-Jan-2014 18:00:00",
  "FeatureToggle.Tweeting": "2.5.0.1" // Assembly version is set to 2.5.0.0
}

Running the app now result in:

Printing is on
Saving is on
Tweeting is off

Using Feature Toggle in an ASP.NET Core App

Usage in an ASP.NET core app currently requires the configuration to be provided when instantiating a toggle, this may be cleaned up in future versions. For RC1 the following code shows the Startup class creating a FeatureToggle AppSettingsProviderand and passing it the IConfigurationRoot from the startup class.

public void ConfigureServices(IServiceCollection services)
{
    // Set provider config so file is read from content root path
    var provider = new AppSettingsProvider { Configuration = Configuration };

    services.AddSingleton(new Printing { ToggleValueProvider = provider });
    services.AddSingleton(new Saving { ToggleValueProvider = provider });

    // Add framework services.
    services.AddMvc();
}

The appSettings would look something like the following:

{
  "FeatureToggle.Printing": "true",
  "FeatureToggle.Saving": "false",
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  }
}

As an example of using this configuration check out the example project on GitHub, in particular the following:

https://github.com/jason-roberts/FeatureToggle/blob/master/src/Examples/AspDotNetCoreExample/Models/Printing.cs

https://github.com/jason-roberts/FeatureToggle/blob/master/src/Examples/AspDotNetCoreExample/Models/Saving.cs

https://github.com/jason-roberts/FeatureToggle/blob/master/src/Examples/AspDotNetCoreExample/ViewModels/HomeIndexViewModel.cs

https://github.com/jason-roberts/FeatureToggle/blob/master/src/Examples/AspDotNetCoreExample/Controllers/HomeController.cs

https://github.com/jason-roberts/FeatureToggle/blob/master/src/Examples/AspDotNetCoreExample/Views/Home/Index.cshtml

https://github.com/jason-roberts/FeatureToggle/blob/master/src/Examples/AspDotNetCoreExample/Startup.cs

https://github.com/jason-roberts/FeatureToggle/blob/master/src/Examples/AspDotNetCoreExample/appsettings.json

New Pluralsight Course: Reducing C# Code Duplication in Azure Functions

Azure Functions allow small discrete pieces of code to execute in response to an external stimulus such as a HTTP request, message queue message, new blob data, etc.

Just because functions are easy to create (even writing and testing code right in the Azure Portal) doesn’t mean good practices such as avoiding code duplication can be abandoned.

My new Pluralsight course Reducing C# Code Duplication in Azure Functions shows some ways to reduce or remove code duplication both in a single Function App and across apps.