Stream Wrap Up – SignalR and Refactoring for Unit Testing Madness

The weekly scramble is over, and I think we accomplished a lot in building overlays and answering questions this week.  Let’s review the progress from this week’s streams:

We started with a question from djvortechs about referencing packages from Visual Studio extension projects, or VSIX’s.  After a little exploration, I couldn’t come up with the immediate answer.  In a follow-up discussion with Mads Kristensen on Twitter, he indicated that the package we were trying to reference, Newtonsoft.Json is distributed with Visual Studio and was not needed to be included in the redistributable VSIX package.

I started work on the Fritz.StreamTools project with a simple refactoring to centralize all references to sending a command to all attached SignalR clients.  This new FollowerClient class allowed me to write the “magic string” containing the SignalR client-side function name.

public class FollowerClient
{

  public FollowerClient(IHubContext<FollowerHub> followerContext)
  {

    this.FollowerContext = followerContext;

  }

  private IHubContext<FollowerHub> FollowerContext { get; }

  public void UpdateFollowers (int newFollowers) {

    FollowerContext.Clients.All
      .InvokeAsync("OnFollowersCountUpdated", newFollowers);

  }

}

The FollowerContext is a reference to the server-side Hub that our clients are listening on.  Whenever we need to update the follower count on attached clients, the UpdateFollowers method can send that new follower count to all clients that have a “OnFollowersCountUpdated” client-side method.

I then started writing a simple RazorPage to present the current viewers from both Twitch and Mixer services, with a goal to emulate the widget that currently resides in the top-right corner of the video.  This new page, CurrentViewers.cshtml, contains very similar markup to the Followers goal widget that I constructed previously.  I copied and pasted some of the Followers code to drive updating this new Current Viewers widget.


On Thursday’s stream, I ran into a brief GitHub outage… and that lead to some fun with chromakey and the GitHub pink unicorn error message.

Jeff is angry at the GitHub Unicorn

I now have a new error page template

Big thanks to Carey Payette for capturing that second pic of me during the stream as I was playing with the GitHub error page.

I started by adding a .EditorConfig file to the Fritz.StreamTools project to help enforce some standards in code formatting and syntax.  Additionally, I set the TreatWarningsAsErrors property in the project’s csproj file to true.  When the EditorConfig extension is in place in Visual Studio, it will throw errors during the build process if my rules are violated.  This should also help with ensuring that my files are formatted with my preferences, like preferring tabs over spaces.

Next, we looked at how I added a logger to the interactions with the Twitch and Mixer services.  This allows those services to report to the container’s logs when changes in the service state occur.

Next, I started using PowerShell to maintain the files committed to Git source control.  The module that I prefer to use with PowerShell for Git highlighting, tab-completion, and prompt enhancements is called posh-git.  It was really easy to install from the PowerShell command-line in Windows 10:

  1. PowerShellGet\Install-Module posh-git -Scope CurrentUser
  2. Import-Module posh-git
  3. Add-PoshGitToProfile

More details including permission configuration is available on the posh-git project page.

Next, I performed a refactoring where I moved the contents of the Startup.ConfigureServices method to another class in order to simplify the contents of the Startup class.  This is a very important class, and with the volume of content in it, the chances of inadvertently breaking something was starting to grow.  I simplified by creating a class in a folder called “StartupServices” called “ConfigureServices” that has a single method, Execute and would do the same things as the former Startup.ConfigureServices method.

I re-arranged the code in that Execute method, and even added some groupings by moving some of the similar configuration into private methods.  I think this now makes the configuration of services for this project a bit easier to manage, and defends the Startup class against invalid updates.  In the future, we can write some unit-tests against the ConfigureServices class to ensure that our configuration is being applied properly.

Then, we merged a pull-request from Bruno that rolled up the various streaming services into an aggregate StreamService object.  This was really great because all of the user-interface work in the project could be refactored to remove their direct references to Twitch or Mixer.  Really great stuff, and a good step towards making our code more testable.

I made my application a little bit easier to tweak and re-run by using the dotnet watch feature.  This was added to my project by adding the Microsoft.DotNet.Watcher.Tools reference to my project file and then executing on the command line “dotnet watch run”.  This would re-start the application whenever a server-side file changed on disk.

We updated the CurrentViewers razor page to take advantage of this new aggregate StreamService, and output the collection of services and viewer counts by using a simple Linq query.  Then, I received a comment in the chat room that suggested I use the JavaScript array reduce feature to update the total viewer count, instead of using a for..loop to sum the values.  This JavaScript code to sum the values for the Total Viewers element looks like:

const reducer = (accumulator, currentValue) => 
   accumulator + parseInt(currentValue.textContent, 10);
var currentCounts = document.getElementsByClassName("serviceCount");
var elArray = Array.from(currentCounts);
document.getElementById("totalCount").textContent = elArray.reduce(reducer, 0);

The reducer function receives an accumulator value and the currentValue that it should be operating on.  The currentCounts object is a collection of HTML elements with the CSS class “serviceCount”, and is converted to an array using the Array.from statement.  Finally, the totalCount textContent is set to the result value of the reducer function operating on each element of the elArray, with an initial accumulator value of 0.

Finally, I added a check to only add the Twitch and Mixer services when a ClientID is configured for those services.  With this indirect reference to these services in use now, we should be able to conditionally add services as they are configured.

On Saturday’s stream, we started by answering some questions about the new Span feature and also a question about how and where to get a comprehensive teaching experience online for .NET Core development. Of course, you can check out Microsoft Virtual Academy and the .NET Core courses that I have written as well as my book about Learning ASP.NET in 24 hours.

In this stream, I focused on adding unit tests to the solution.  My primary way of executing unit tests is in Visual Studio 2017, and I showed how to run tests manually and also the Live Unit Testing feature of the Enterprise edition of Visual Studio.  Also, I showed that the dotnet watch tool could be used for testing as well just by running “dotnet watch test” against my test project.

I started with some simple tests to verify that the count of followers and viewers was summed properly, and then moved on to testing the more complex interaction of verifying that the output from Twitch was handled properly by the application.

There were some questions about PHP and unit testing during the stream.  I suggested folks check out the Peachpie project, which enables PHP applications to be compiled with the .NET roslyn compiler.  Jakub Misek from the Peachpie project spoke about the features during dotNetConf 2017, and that video is below:

We then wrote some more complex tests to inspect the events raised when the Twitch service raises the Updated event. To do this, we used the xUnit event testing feature that looks like this:

var evt = Assert.Raises<ServiceUpdatedEventArgs>(
  h => sut.Updated += h,
  h => sut.Updated -= h,
  () => sut.Service_OnNewFollowersDetected(null, myArgs)
);

Assert.Equal(initialFollowers + newFollowerCount, evt.Arguments.NewFollowers);
Assert.Null(evt.Arguments.NewViewers);

The Raises method takes a type parameter that matches the arguments type of the Event we are looking for, attaches and detaches from the Updated event in the first two arguments, and the third parameter is the method call that should trigger the Updated event.  The return value from the Raises method is a wrapper around this Updated event that we can inspect on the last two lines of the sample.

Overall some good progress this week.  Next week, we’re going to start the week with completing the YamlConfigurationBuilder from the ConfigurationBuilders project.  Later, we should have a guest on Thursday or Saturday morning.  Keep an eye on the stream and my Twitter account for updates about the content planned this week.  I hope to see you then!