Goal Achieved – and this week’s summary of .NET Live Coding

What an ending to this week…  we wrote a LOT of code, and I’m proud to say that a fair amount of the code added to the projects this week were submitted from viewers.  THANK YOU!  … and that’s just the beginning of the story from the week ending January 20, 2018

I started the week by looking at a pull request submitted by SQL-MisterMagoo to add color gradients to the follower goal widget in StreamTools.  Yes, I can’t make this name up, and that’s a fantastic handle.  The feature allows you to define multiple colors for the Followers Goal bar and also define how those colors will blend into each other.

Follower Goal with new gradient features

In addition to adding this new configuration option, he added some documentation for the new parameters in the Docs_Goal.cshtml page.  I always appreciate when I receive a pull-request with new features, tests, AND docs.

I updated my follower-goal bar on the video to use a red-yellow-green set of stripes by adding this configuration to my environment variables:

FollowerGoal__FillBackgroundColor=red,yellow,green
FollowerGoal__FillBackgroundColorBlend=1,1,1

I then showed off my build.cmd script that automatically builds my application in a container and pushes a copy to my private docker registry hosted on Azure.  The contents of build.cmd are listed below:

docker build -t fritz.streamtools:%1 -t fritz.streamtools:latest -f Fritz.StreamTools\Dockerfile .

docker tag fritz.streamtools:%1 fritzregistry.azurecr.io/fritz.streamtools:%1
docker tag fritz.streamtools:%1 fritzregistry.azurecr.io/fritz.streamtools:latest

docker push fritzregistry.azurecr.io/fritz.streamtools

This makes it real easy for me to push a new copy from my development machine and then pull it back down to my production machine. Eventually, I’ll push a “production ready” image to the public Docker Hub.

I received a questions about the cost of hosting a private docker registry on Azure, and its a relatively cheap consideration for a small registry.  At the time of this video recording, it costs about $5 a month, and its effectively free with a new Azure account that currently comes with $200 in credit for the first month.

Our friend djvortechs has seen some downloads for his Visual Studio 2017 extension, the Visual Studio Media Player.  This extension was inspired from our work on the EpicBuildMusic extension, and he’s done a great job embedding a media player in Visual Studio.

The next task we tackled was in the ConfigurationBuilders project.  We received an issue asking for a set of features in the YAML Configuration Builder.  This tool will allow you to use YAML files to add configuration to your .NET 4.7.1 projects and continue to use the standard ConfigurationManager API.

I wrote a few unit tests to help exercise the current features of the YAML Configuration Builder, and then added a sample project that showed the full-integration of the feature in a console application.  I used the sample project to show that a standard feature of the ConfigurationBuilders in .NET 4.7.1, that you can add multiple configuration builders to a section by listing their names in a comma-separated list and they will be processed from left-to-right.

<appSettings configBuilders="Yaml1,Yaml2, YamlSectionAppSettings">
</appSettings>

I concluded by editing the markup in the original issue to convert the bullet-list of features to a checkbox list.  This was done by adding square brackets after the hyphen to start the markup:

 - [ ] checkbox item

Then we used the tilda (~) to wrap the text that I wanted to strike-through.  Easy to do, and one of those markup features that I want to document so I can find it again later.

Thursday’s Stream

On Thursday, I started things off by introducing the new hat my daughter insisted I wear for this stream. We’re big Marvel comics fans at the Fritz house, and she wanted me to go with Iron Fist today.  Normally, I have a green-screen behind me to handle the chroma-key filter on my webcam.  Fortunately, my screen has a blue color on the back that’s perfect for this… so today I turned the screen around and was able to wear green without going transparent like my hat did on Tuesday.

Next, I introduced the community Discord server.  This is a place for you to socialize, hang out, and chat with other viewers of the stream while the show is not running.  I configured two initial channels:  general and projectsOnStream.  The general channel will be updated from a GitHub bot whenever there is an issue or change in the Fritz.LiveStream repository, and the projectsOnStream channel will receive updates whenever code is changed, issues are submitted, or pull-requests are submitted to any of the projects we’re working on.  I encourage you to check out the server, and chat with some of the folks you’ve met during the stream.

Next, we returned to the YAML Configuration Builder task and added an “optional” property to allow a developer to determine if the YAML file’s presence is required and an error should be thrown if it is not located.

Finally, we added a feature to called “section” to the YAML Configuration Builder that would allow you to specify a section of the YAML code to apply to your configuration. For example, I could have this YAML file:

---
appSettings:
  sectionSetting1: value1
  sectionSetting2: value2
connectionStrings:
  db1: connectionString1

I can apply the appSettings section to my appSettings section in App.Config with this markup in the app.config file:

<configBuilders>
  <builders>
    <add name="YamlSectionAppSettings" mode="greedy" location="section.yml"
      section="appSettings" optional="true"
      type="Fritz.ConfigurationBuilders.YamlConfigurationBuilder, Fritz.ConfigurationBuilders"/>
   </builders>
</configBuilders>
<appSettings configBuilders="YamlSectionAppSettings">
</appSettings>

The key here is the new “section” attribute on the builders/add element that specifies the section of the YAML file to read settings from.

I wrote some unit tests and even simplified some code as I saw how I could refactor my navigation of the YAML file.  Overall, I was pretty happy with how this feature turned out.

Saturday’s Stream

The last stream of the week was the most exciting stream for me.  We had three pull-requests from viewers in the StreamTools project.  I redirected the stream to merge these changes and discuss the various features they provided.

The first pull request made the SignalR connection more robust by attempting to reconnect every 5 seconds when disconnected.  Additionally, it tried to resolve some of the mixed spacing issues in the project files.  I normalized those files with the Tidy C# extension for Visual Studio.  Additionally, we learned that when you are reviewing a diff on GitHub, you can add ?w=1 to the address to force GitHub to ignore whitespace differences.  Very cool pro-tip from the chatroom.

The second pull request created a concrete MockService object that could be used by folks testing and writing user-interface features.  After some discussion, we agreed that the name MockService could be replaced with the more descriptive “FakeService” name.  Mocks are objects created using reflection, and Fakes are more concrete objects previously declared in code.  We renamed the class and added it to the main project.

The third pull request showed us how to use AutoFixture to replace the arrange sections of our unit tests.  This was neat to see how the creation of an attribute coupled with the use of an xUnit Theory attribute means that AutoFixture will create mock instances of objects and pass them into test methods as an input parameter.  Check out this code for a test using AutoFixture:

[Theory]
[AutoMoqStreamServiceWithNameAndCount]

public void ShouldCountSeparately(IStreamService jeffStreams, IStreamService otherStreamService)
{

	// arrange

	// act
	var sut = new Fritz.StreamTools.Services.StreamService(new[] { jeffStreams, otherStreamService });
	var count = sut.ViewerCountByService.ToList();

	// assert
	Assert.Equal(2, count.Count());
	Assert.Equal(jeffStreams.CurrentViewerCount, count.First(c => c.service == jeffStreams.Name).count);
	Assert.Equal(otherStreamService.CurrentViewerCount, count.First(c => c.service == otherStreamService.Name).count);

}

The AutoMoqStreamServiceWithNameAndCount attribute knows how to create an IService object and pass it in to this method.  We can then test using concrete instances that were generated by that attribute.  Easy, reusable, and places that initialization code in one place.

Next, we ran into a problem where the SignalR JavaScript client library is declared and added to our output with a version number hardcoded into the file name.  Instead of replacing that version number everywhere, I added a new TagHelper that would generate the appropriate script tag with a pointer to the current SignalR library in our project.  TagHelpers look like HTML tags but behave like directives that are replaced on the server. Look how easy the code for this object is:

public class SignalrTagHelper : TagHelper
{

	public SignalrTagHelper(IHostingEnvironment env) {

		this.HostingEnvironment = env;

	}

	private readonly IHostingEnvironment HostingEnvironment;

	public override void Process(TagHelperContext context, TagHelperOutput output)
	{

		output.TagName = "script";
		output.TagMode = TagMode.StartTagAndEndTag;

		var filename = IdentifyClientLibrary(new FileSystem(), HostingEnvironment.WebRootPath);

		output.Attributes.Add("src", filename);

	}

	internal string IdentifyClientLibrary(IFileSystem fileSystem, string webRootPath)
	{

		var folderName = fileSystem.Path.Combine(webRootPath, "lib/signalr");
		var folder = fileSystem.DirectoryInfo.FromDirectoryName(folderName);

		var fileInfo = folder.GetFiles("signalr-client-*.min.js")
			.OrderByDescending(f => f.Name).First();

		return $"~/lib/signalr/{fileInfo.Name}";

	}
}

This class renders code during the Process method, and it declares that it will output a script tag with a start and end tag. Next, we locate the filename to write into the src attribute using the IdentifyClientLibrary method.  Finally, the src attribute is set.  The IdentifyClientLibrary method does a simple lookup for the signalr-client library file in the wwwroot/lib/signalr folder.

The challenge with this that was pointed out by the viewers was:  how do you unit test this class?  We landed on the idea of using the System.IO.Abstractions package to mock the filesystem, and I refactored the method to use the IFileSystem interface to access the files on disk.  I can then test by substituting a mock filesystem.  I wasn’t able to finish this test because…

WE HIT OUR FOLLOWER GOAL DURING THE WRITING OF THIS TEST!

I’m thrilled that we hit our 500 follower goal, and now I will make good on my promise:  I am scheduling a FREE ASP.NET Core Workshop on stream for any and all viewers that wish to attend.  Tentatively, it should last about 8 hours and I plan to invite several friends to help with areas of ASP.NET Core that they are experts in.  I have an event in Seattle at the end of the month, so look for a scheduling announcement that would land it in early February.

Also:  look for me on Wednesday the 24th on the PhillyDotNet Mixer stream, which I’ll re-host on my stream as well, where I’ll be presenting to the Philly.NET user group about new features in Visual Studio 2017 and .NET that were released after Ignite 2017.

A great week, I’m thrilled to make the follower goal… and I’m defining a new goal and reward for 1000 followers.  I’m flattered that so many folks are interested in the live stream, and I hope you join me next week for pair-programming with my guests.  I hope to see you then!