Getting the IHostEnvironment in .NET Core 3.0

Standard

Where as .NET Core 2.1 introduced the GenericHost concept to aid in constructing non-HTTP applications while leveraging primitives for DI, logging, and config, .Net Core 3.0 focused on restructuring the web hosting to be compatible with the generic host instead of having to duplicate code in multiple abstractions.
I may go into the reasons for this change in another post but as I was recently asked the question, I thought I would provide a simple example of how to leverage the IHostedEnvironment in .NET Core 3.0

First add the following 2 packages to your application:
dotnet add package Microsoft.Extensions.Hosting
dotnet add package Microsoft.Extensions.DependencyInjection

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace TestIHostEnvironment
{
    class Program
    {
        static void Main(string[] args)
        {
            var host = Host.CreateDefaultBuilder()
                .ConfigureServices((context, services) =>
                {
                    services.AddTransient<ITestService, TestService>();
                })
                .Build();

            using (var serviceScope = host.Services.CreateScope())
            {
                var serviceProvider = serviceScope.ServiceProvider;
                var testService = serviceProvider.GetRequiredService<ITestService>();

                var result = testService.DoStuff();

                Console.WriteLine(result);
            }
        }
    }
}

public interface ITestService
{
    string DoStuff();
}

public class TestService : ITestService
{
    private readonly IHostEnvironment _iHostedEnvironment;

    public TestService(IHostEnvironment iHostedEnvironment)
    {
        _iHostedEnvironment = iHostedEnvironment;
    }

    public string DoStuff()
    {
        return $"Stuff Done in {_iHostedEnvironment.EnvironmentName} environment";
    }
}

Creating an In Memory Zip Archive for multiple files in C#

Standard

I was asked an interesting technical question the other day that felt relevant enough to share. Having tackled a similar issue in the distant past using SharpLib this felt like a good opportunity to recreate the functionality using native .Net functionality in the form of ZipArchive!

For this use case the ask was to store various string data that can be appended to an in memory zip archive in form of a new file containing the data. After the data is processed the desire was to write the zip file to a specific location for another process. The following is short proof of concept to outline the implementation.

using System.IO.Compression;
using System.Text;

namespace ZipTest
{
    internal class Program
    {
        /// <summary>
        /// Create a new file to contain the data passed in and then add that to the Zip Archive
        /// </summary>
        /// <param name="archive">The Archive to append to</param>
        /// <param name="fileName">The name of the file as you wish it to appear in the archive</param>
        /// <param name="textContent"></param>
        static void AddFileToZip(ZipArchive archive, string fileName, string textContent)
        {
            // Create a new entry in the archive using the specified file name
            ZipArchiveEntry entry = archive.CreateEntry(fileName);

            // Write the text content to the entry
            using (Stream entryStream = entry.Open())
            using (StreamWriter writer = new StreamWriter(entryStream, Encoding.UTF8))
            {
                writer.Write(textContent);
            }
        }
        // Append the data in the form of a file to the archive
        static void AppendFileToZipArchive(MemoryStream zipStream, string fileName, string textContent)
        {
            // Create a new ZipArchive instance using the existing MemoryStream
            using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Update, leaveOpen: true))
            {
                AddFileToZip(archive, fileName, textContent);
            }
        }

        static void SaveZipArchiveToDisk(MemoryStream zipArchiveStream, string outputPath)
        {
            // Save the MemoryStream to a file
            File.WriteAllBytes(outputPath, zipArchiveStream.ToArray());
        }
        static void Main(string[] args)
        {
            using (MemoryStream zipArchiveStream = new MemoryStream())
            {
                // Append files to the zip archive
                AppendFileToZipArchive(zipArchiveStream, "file1.txt", "This is the content of file 1.");
                AppendFileToZipArchive(zipArchiveStream, "file2.txt", "This is the content of file 2.");

                // Save the zip archive to a file
                SaveZipArchiveToDisk(zipArchiveStream, "result.zip");
            }
        }
    }
}

Hopefully you find this useful!

Javascript: Var vs Let vs Const?

Standard

In JavaScript, var, let, and const are used to declare variables, but they have different scoping rules and behaviors. Here’s a breakdown of the differences between them:

  1. var:
    • Variables declared with var are function-scoped or globally scoped, depending on where they are declared. They are not block-scoped.
    • This means that a variable declared with var is accessible throughout the entire function in which it is declared or throughout the global scope if declared outside of any function.
    • var declarations are hoisted to the top of their scope during the compilation phase, so you can access them before they are declared in your code (this can lead to unexpected behavior).
    • var variables can be re-declared and updated within their scope.
  2. let:
    • Variables declared with let are block-scoped, which means they are confined to the nearest enclosing block, such as a loop or an if statement.
    • let variables are not hoisted to the top of their block. They are only accessible after they are declared in the code.
    • Unlike var, you cannot re-declare a variable using let in the same scope.
    • let variables can be updated after declaration, meaning you can change their value.
  3. const:
    • Variables declared with const are also block-scoped like let.
    • However, const variables are constants, which means their value cannot be reassigned after it’s assigned once. This makes them suitable for values that should remain constant throughout their scope.
    • Like let, const variables are not hoisted and are only accessible after they are declared in the code.
    • Similar to let, you cannot re-declare a variable using const in the same scope.

Here’s a quick example to illustrate the differences:

function example() {
    var varVariable = "I am var";
    let letVariable = "I am let";
    const constVariable = "I am const";

    if (true) {
        var varVariable = "I am still var";
        let letVariable = "I am still let"; // This creates a new block-scoped variable
        // const constVariable = "This will cause an error"; // Cannot redeclare in the same scope
    }

    console.log(varVariable); // Outputs: "I am still var"
    console.log(letVariable); // Outputs: "I am let"
    console.log(constVariable); // Outputs: "I am const"
}

example();

In modern JavaScript, it’s generally recommended to use let and const over var due to their more predictable scoping and behavior. Use let when you need to reassign a variable, and use const when you want to ensure a variable’s value remains constant.

Inserting an Element into Web.Config or XML file using Powershell

Standard

The following is an overview on how to inject a new XML tag into an XML file at a specific location using a Powershell script. The functionality is often used during automated deployment but has several uses. There are several methods for accomplishing this, however I found the following to be most compatible with several versions.

Function AddClientToXml 
{
    [CmdletBinding()]
    param(
       [Parameter(Mandatory=$true)]
       $configFilePath 
    )
    # Load the web.config file into an XML document.
    $xmlDoc = New-Object System.Xml.XmlDocument
    $xmlDoc.Load($configFilePath)

    # Create our XML to be inserted
    $clientXml = @"
        <client>
            <endpoint address="RegistrationAddressValue"
                behaviorConfiguration="SampleClientCertificateBehavior" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_RegistrationService"
                contract="Registration.RegistrationService" name="WSHttpBinding_RegistrationService">
                <identity>
                    <dns value="RegistrationDNS" />
                </identity>
            </endpoint> 
        </client>
"@
    
    $clientNodes = $xmlDoc.SelectSingleNode("//system.serviceModel/client")
    # Check to see if the <client> node already exists.
    if ($clientNodes.Count -gt 0) {
        # The <client> node exists, so we'll replace it with the new one.
        # Set $clientNode to it's first child node.
        $clientNode = $clientNodes[0]
        
        # Replace the <client> node with $clientXML element
        $clientNode.ParentNode.ReplaceChild($xmlDoc.ImportNode($clientXml.DocumentElement, $true), $clientNode)
     } 
     else 
     {
        # The <client> node doesn't exist, so we'll create it.
        $serviceModelNode = $xmlDoc.SelectSingleNode('//system.serviceModel')
        
        # Load the $clientXml string into a new XmlDocument object.
        $newXmlDoc = New-Object System.Xml.XmlDocument
        $newXmlDoc.LoadXml($clientXml)

        # Get the $clientXml as a node
        $importedNode = $xmlDoc.ImportNode($newXmlDoc.DocumentElement, $true)
        
        # Append the $importedNode to the $serviceModelNode
        $serviceModelNode.AppendChild($importedNode)
        $xmlDoc.Save($configFilePath) 
     }

    return $xmlDoc
}
  
$webConfigPath = "C:\PATH TO WEB.CONFIG\Web.config"
AddClientToXml($webConfigPath)

After running the script the web.config specified to the function should resemble the following:

<system.serviceModel>
        <bindings>
            ...
        </bindings>
        <client> 
          <endpoint address="RegistrationAddressValue"
                behaviorConfiguration="SampleClientCertificateBehavior" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_RegistrationService"
                contract="Registration.RegistrationService" name="WSHttpBinding_RegistrationService">
                <identity>
                    <dns value="RegistrationDNS" />
                </identity>
            </endpoint> 
        </client>
      <behaviors>
        ...
      </behaviors>
    </system.serviceModel>

This approach is particularly useful when using CI/CD to deploy your code base to environments that require different configurations.

Hope this helps!

LINQ and problem of Premature Materialization

Standard

I am a huge believer in the power and usefulness of LINQ. At the same time I often see common mistakes that can have large impacts on performance. When working with an IEnumerable it’s important to remember that you may not be working with the actual data, but a promise of data being available.

IEnumerable represents the concept of a collection of data. Similar to a cursor in SQL, an IEnumerable is forward only traversable collection that loads and iterates over the records one at a time. If you have a 1000 records read from a database using an IEnumerable, there is technically only one record in memory at a given time.

Materialization in Memory
When you force materialization in memory, all records must be loaded into memory for manipulation. I’m going to use the following method as an example.

    string GetDefaultSMSPhoneNumber(IEnumerable<PhoneNumbers> patientNumbers)
    {
        const int PHONE_TYPE_HOME = 1;
        const int PHONE_TYPE_OFFICE = 3;
        const int PHONE_TYPE_OTHER = 9;

        var phoneNumberByType = patientNumbers.Where(p => p.sms_capable == 1).GroupBy(p => p.phone_type_id);

        // Select the phone number last used in creating a prescription
        if (patientNumbers.Where(p => p.sms_capable == 1 && p.last_used_for_rx == 1).Count() > 0)
        {
            return patientNumbers.Where(p => p.sms_capable == 1 && p.last_used_for_rx == 1).FirstOrDefault().phone_number;
        }

        // If no number has been used, select a configured SMS number in the following order (Other, Home, Office) 
        if (patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_OTHER).Count() > 0)
        {
            return patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_OTHER).FirstOrDefault().phone_number;
        }

        // If no number has been used, select a configured SMS number in the following order (Other, Home, Office) 
        if (patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_HOME).Count() > 0)
        {
            return patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_HOME).FirstOrDefault().phone_number;
        }

        // If no number has been used, select a configured SMS number in the following order (Other, Home, Office) 
        if (patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_OFFICE).Count() > 0)
        {
            return patientNumbers.Where(p => p.sms_capable == 1 && p.phone_type_id == PHONE_TYPE_OFFICE).FirstOrDefault().phone_number;
        }

        return string.Empty;
    }

Aside from high cyclomatic complexity, this method materializes the collection a minimum of 3 times and a maximum of 9 times. Some of the issues above can remedied simply by removing the uneeded or redundant calls. For example:

// The following statement can be cleaned up a few different ways
if (patientNumbers.Where(p => p.sms_capable == 1 && p.last_used_for_rx == 1).Count() > 0)
{
     return patientNumbers.Where(p => p.sms_capable == 1 && p.last_used_for_rx == 1).FirstOrDefault().phone_number;
}

// The criteria in the Where can be moved to the count
// Because it's only looking for existence, count should be replaced with Any
// This approach will iterate the collection twice, once for the Any and once for FirstOrDefault
if (patientNumbers.Any(p => p.sms_capable == 1 && p.last_used_for_rx == 1))
{
     // Similarly he criteria in the Where clause can moved directly to the FirstOrDefault
     return patientNumbers.FirstOrDefault(p => p.sms_capable == 1 && p.last_used_for_rx == 1).phone_number;
}

// Alternatively you can do the following which will only materialize your collection once
var patient = patientNumbers.FirstOrDefault(p => p.sms_capable == 1 && p.last_used_for_rx == 1);
if (patient != null)
    return patient.phone_number
 

While refactoring our “if” statements cleans up our code, each one is still materializing our collection which is undesirable. If we look at the objective of our method we can refactor the logic to use Linq itself instead of using logic on top of data retrieved from Linq. We a list of phone numbers, broken into prioritized group and we want to return the first eligible number.

        string GetDefaultSMSPhoneNumber(IEnumerable<PhoneNumbers> patientNumbers)
        {
            // Because the numeric values for the phone types don't match the order of importance
            // a dictionary is used to order number by the desired priority.
            var phoneTypeSortOrder = new Dictionary<int, int> { { (int)PhoneType.Other, 1 }, { (int)PhoneType.Home, 2 }, { (int)PhoneType.Office, 3 } };
            
            // Filter to only SMS capable number and check to see if a number has been previously used
            var smsNumbers = patientNumbers.Where(p => p.sms_capable == 1);              
            var lastUsedNumber = smsNumbers.FirstOrDefault(p => p.last_used_for_rx == 1);
            if (lastUsedNumber != null) 
                return lastUsedNumber.phone_number; 
            
            // If no number has been used, select a configured SMS number in the following order (Other, Home, Office)             
            var configuredNumbers = smsNumbers.Where(x => phoneTypeSortOrder.ContainsKey(x.phone_type_id))
                .GroupBy(p => phoneTypeSortOrder[p.phone_type_id])  // Put the number into groups based on type
                .OrderBy(g => g.Key)                                // Order the numbers by their group
                .SelectMany(g => g)                                 // Apply the order to all the numbers in group
                .FirstOrDefault();                                  // Return the first phone number
            return configuredNumbers?.phone_number ?? string.Empty; 
        }

As you can see the refactored code is much smaller, is still easy to read, and is more performant in all scenarios. In the best case scenario the collection is materialized only once when the Phone Number last used for Rx is retrieved. In the worse case scenario our collection is materialized twice. Once as referenced above and once during the GroupBy operation.

Hopefully this provides some help and insight as you continue to work with Linq.
Happy to hear your thoughts!

Interview Tips – The First Question

Standard

As an interviewer, one of the very first questions you should ask should be:

On a scale of 1 to 10, 1 being you’ve heard of it, 10 being you could write a book, how do you rate yourself in [Topic]?

This is probably one of the most important questions to start the interview with for a couple of reasons we will explore.

Set the tone for interview / conversation

The answer to this question should help set the tone and filter the questions that you pose to the candidate. If a candidate rates themselves a 2 or 3, there is no sense asking them advanced questions on the subject. So many interviewers make the mistake of having a standard listen of questions that they “have to get through” without actually tailoring the content to the candidate. It’s demoralizing to both the interviewer and the candidate. The answer to this question should directly impact which questions you ask and possibly how to phrase them. It should also give you an idea of their potential as a mentor.

Gauge the candidates potential for self assessment

As an interviewer, how many times has a candidate told you that they are “a fast learner”, “quick to ramp up”, “love tackling difficult challenges”? The boilerplate statements are based on the candidates opinion of themselves. When they make these statements without proof they are essentially asking to give them the benefit of the doubt.

If a candidate rates themselves an 8 and yet fails to answer questions around that level, it doesn’t necessarily mean that they lying. It does however point to an issue with honest self assessment. If they overestimate their ability it is a safe assumption other proclamations may as well. Possibly due to the Dunning-Kruger effect On the flip side some candidates will underrate themselves which can indicate a humbleness and muted ego.

Basic Interview Tips from an Interviewer

Standard

This will be the start of a weekly segment where I will cover 1 interview question. How to ask it, why it matters, and the kind of answers you should be looking for.

In 20+ years of consulting and development I have interviewed and been interviewed over 100 times. Development interviews are often more challenging than your standard interviews in that they often encompass quizzes, code exercises, logic problem or riddles. As an interviewee I have encountered all manner of riddles and other asinine questions stolen from the net without a grasp of their purpose.

As an interviewer I’ve encountered countless woefully underqualified candidates from head hunter. In some cases they were sent to report back the questions they were asked to build the correct answers for the next candidate. (This happens way more often than you might think). I’ve also had several candidates with great potential that just failed to properly prepare.

Over the years I have helped countless colleagues navigate the gauntlet that is the tech interview. As an interviewee, the quality of the conversation heavily determines both the likelihood and quality of an offer. As an interviewer, they types of questions you ask can make a serious impact on how or if the candidate will integrate well with your team and environment.

The purpose of this ongoing segment will be to give interviewers the questions that will tell them what they actually want to know and given interviewees the tools they need to not only succeed, but stand out. So stop asking:

  • Why are manhole covers round?
  • How many golfballs fit on a school bus?
  • How many piano tuners are there in Chicago?

And start asking questions that actually give you the information you need.

Using Roslyn to get a list of Implemented Interfaces for CSharpSyntaxRewriter

Standard

While working on a project to update method signature’s and add a parameter down the entire stack I ran into an issue when the method being altered is implemented as part of an interface, as the implementing class no longer matches the interfaces signature. Because of this I needed to get a collection of the implemented interfaces for the class beforehand which was not straightforward.

The information needed is available from INamedTypedSymbol for the class. This is obtained through the SemanticModel using the GetDeclaredSymbol method. Once you have this Symbol the interfaces are available through the AllInterfaces property.

    public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
    {
        var tree = node.SyntaxTree;
        var root = tree.GetRoot();   
        // Get the Semantic Model         
        var sModel = comp.GetSemanticModel(node.SyntaxTree);
        // Get symbol for the class
        var classSymbol = sModel.GetDeclaredSymbol(root.DescendantNodes().OfType<ClassDeclarationSyntax>().First());
        // Get classes implemented interfaces.
        var implementedInterfaces = classSymbol.AllInterfaces;

        return base.VisitClassDeclaration(node);
    }

RAISED BED GARDEN 2015 SECOND UPDATE

Standard

It’s the beginning of August now and the garden is still thriving.  As an experiment this has been a huge success but also a learning experience.  Here are some of my own take aways from this experience.

Garden Size and Planting Style

4′ x 8′ was a good size for a raised bed garden.  Any wider and we would have had difficultly tending to things in the middle.  The Grid layout that we used was successful overall but this experience has taught me to change my approach in planting.  We planting in rows the plants in that row are all of a similar size.  When you plant within a grid however you have to very aware of everything around your plant.  I will cover this more in plant choices.  I think for next year we are going to add a second raised bed beside the first.

Plant Selections

This was a big learning experience for me.  Here is a break down and I what I learned about each of the plants we grew.

CauliflowerI would not grow this again.  It takes a long time to harvest and produces a single head.  In addition the leaves are large and take up lots of space. Each cauliflower could have easily filled its own square in the grid.  Space consumed compared to output this plant wasn’t worth it.
CabbageSimilar to cauliflower this plant takes up quite a bit of space, has a long harvest time, and produces one viable head.  If I planted this again it would be limited in number and on the outskirts of the bed.
BroccoliThese were awesome!  The plant is larger but produced lots of florets over good span of time.  Everything from the stalk, leaves, florets, and even flowers are edible.  The only downside were the caterpillars that were particularly prolific.  I will most likely double the amount planted next year, but I think they are best planted toward a side.
CucumbersI am amazed by many cucumbers we have harvested and continue to harvest.  The vines became so big that they grew out of the garden and into the yard until we gave them a trellis.  I will probably plant the same amount next year.
TomatoesWe grew both Roma and Grape tomatoes, planted mostly in the middle of the garden.  Both produced and continue to produce quite a bit of fruit.  The plants do seem to branch out and at least one of them reaches from one end of the garden to the other.  We harvested the Roma’s for sauce given most of the grape tomatoes away.  Next year I will most likely stick with just Roma tomatoes.
CeleryOur celery grew tall but it remained thin and mostly leafy.  We never ended up harvesting it.  If we grow it again it will be in limited quantity.
CarrotsOur carrots didn’t have much of a chance.  Planted towards the middle it seemed like something was always towering over them blocking out their sun.  If we plant them next year it need to be away from anything tall.
PotatoesSuccessful.  We will probably stick with 2 next year as well.
Bell PeppersWe were really looking forward to these but they got a late start due to trying to compete with the cauliflower and cabbages for sun.  Once those were removed we have harvested a few peppers that had the most excellent flavor.  Next year we will most likely plant twice as many..
garden3
garden2
garden1

RAISED BED GARDEN 2015 FIRST UPDATE

Standard

Its been about a month now since we planted our garden and its coming along, though not as fast as I’d like.

2015-05-13
2015-05-11

We ran a soaker hose strategically through the garden to make sure everything would get the water it needs. Afterwards we added some mulch to help keep the weeds down. The lettuce and broccoli are doing very well and have outpaced everything else growth wise. Everything feels so empty and I have this urge to plant more but wife is adamant that we already probably have too much. Shes probably right.

I’ve also picked up some berry bushes.  I bought a Blackberry, Blueberry, Red Raspberry, and ordered 3 Black Raspberry bushes online.  Our girls really like fresh berries so I’m very excited for them to be able to pick them when the time comes.  An interesting note, apparently Red and Black Raspberry’s don’t play well together so you have to keep them at least 75ft apart.

Berry Bushes

Berry Bushes