Monthly Archives: December 2019

An ADR Visual Studio Tool – Part 2 – Refactoring

A short while ago, I wrote an article about how to create a new extension for Visual Studio. The end target of this is to have a tool that will allow easy management of ADR Records.

In this post, I’m going to clean up some of the code in that initial sample. There’s nothing new here, just some basic WPF good practices. If you’re interested in downloading, or just seeing the code, it’s here.

What’s wrong with what was there?

The extension worked (at least as far as it went), but it used code behind to execute the functionality. This means that the logic and the UI are tightly coupled. My guess is that soon (maybe as part of .Net 5) the extensions will move over to another front end tech (i.e. not WPF), which means that people that have written extensions may need to re-write them. This is a guess – I don’t know any more than you do.

Onto the refactoring… Starting with MVVM basics

Let’s start with a simple View Model; previously, the code was in the code behind, so we’ll move that all over to a view model:

    public class AdrControlViewModel : INotifyPropertyChanged
    {
        public AdrControlViewModel()
        {
            Scan = new RelayCommandAsync<object>(ScanCommand);
        }

        private string _summary;
        public string Summary 
        { 
            get => _summary; 
            set => UpdateField(ref _summary, value); 
        }

        public RelayCommandAsync<object> Scan { get; set; }

        private async Task ScanCommand(object arg)
        {
            var solutionAnalyser = new SolutionAnalyser();
            Summary = await solutionAnalyser.ScanSolution();            
        }
    }

You’ll also need the following INotifyPropertyChanged boilerplate code:

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName]string fieldName = null) =>        
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(fieldName));

        private void UpdateField<T>(ref T field, T value, [CallerMemberName]string fieldName = null)
        {
            field = value;
            OnPropertyChanged(fieldName);
        }
        #endregion

One day, this can go into a base class, if we ever create a second View Model. We’ll come back to SolutionAnalyser in a while. I shamelessly pilfered the RelayCommand code from here. Finally, I did a bit of shuffling around:

Finally, the code behind needs to be changed as follows:

    public partial class AdrControl : UserControl
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="AdrControl"/> class.
        /// </summary>
        public AdrControl()
        {
            this.InitializeComponent();
            DataContext = new AdrControlViewModel();
        }   
    }

SolutionAnalyser

This is, essentially, the only real code that actually does anything. It’s likely to be severely refactored in a later incarnation, but for now, it’s just in its own class:

    public class SolutionAnalyser
    {
        internal async Task<string> ScanSolution()
        {
            try
            {
                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                var dte = (DTE)Package.GetGlobalService(typeof(DTE));

                var sln = Microsoft.Build.Construction.SolutionFile.Parse(dte.Solution.FullName);
                string summaryText = $"{sln.ProjectsInOrder.Count.ToString()} projects";

                foreach (Project p in dte.Solution.Projects)
                {
                    summaryText += $"{Environment.NewLine} {p.Name} {p.ProjectItems.Count}";
                }
                return summaryText;
            }
            catch
            {
                return "Solution is not ready yet.";
            }            
        }
    }

What’s next?

The next stage is to introduce a search and create facility. I’m going to start creating some issues in the GitHub repo when I get some time.

Fault Resilience in Web Calls Using Polly

Some time ago, I was working on a project using WCF RPC calls. We discovered that of the calls that we made, around 10 – 20% were failing. Once we discovered this, I implemented a retry policy to try and cope with the flaky network. I didn’t realise at the time (or maybe it didn’t exist at the time) that there’s a library out there that does that for you: Polly.

To test this out, let’s create a bog standard API Web Project; from Powershell create a directory; e.g.:

mkdir PollyDemo

Then create a Web API project:

dotnet new webapi -n UnreliableApi

Let’s add a client project console app:

    static async Task Main(string[] args)
    {

        HttpClient httpClient = new HttpClient()
        {
            BaseAddress = new Uri("https://localhost:44368")
        };

        var result = await httpClient.GetAsync("weatherforecast");
        if (result.IsSuccessStatusCode)
        {
            var output = await result.Content.ReadAsStringAsync();
            Console.WriteLine(output);
        }
    }

This should call the API fine (using the default API project you get a weather forecaster). Let’s now introduce a level of entropy into the system. In the server, let’s add the following code:

        static Random _rnd = new Random();

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            // 1 in 3 chance of an error
            if (_rnd.Next(3) == 1)
            {
                throw new Exception("Bad stuff happened here");
            }

            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }

Now, if you run the client a few times, you’ll see that it’s occasionally failing (actually, from this screenshot, all you can really see if that it didn’t succeed):

We know that this error is transient – just needs an F5, so we can put some code into the client to handle this:

for (int i = 1; i <= 3; i++)
{
    var result = await httpClient.GetAsync("weatherforecast");
    if (result.IsSuccessStatusCode)
    {
        var output = await result.Content.ReadAsStringAsync();
        Console.WriteLine(output);
        break;
    }
    else
    {
        Console.WriteLine("Bad things happened... ");
    }
}

Console.WriteLine("If we get here, we either succeeded or gave up ");

And we’re back in business:

The only problem here is that our code is suddenly a little cumbersome; we have a foreach loop around the code, and we’re risking each person implementing this doesn’t introduce a bug by not breaking when successful or whatever.

Before we introduce Polly as the solution, it’s probably worth mentioning that, whilst some errors can legitimately be fixed by simply trying again, in other cases this can be incredibly harmful. You should ensure that your code is idempotent. Imagine you’re creating a sales order on this call, and it fails after writing something to the database – you risk creating multiple sales orders!

Polly

Polly is basically a library built around this concept. It’s a NuGet package, so import it from here into your client. Let’s start by refactoring our code to call the service:

        private static async Task<bool> GetTheWeather(HttpClient httpClient)
        {
            var result = await httpClient.GetAsync("weatherforecast");
            if (result.IsSuccessStatusCode)
            {
                var output = await result.Content.ReadAsStringAsync();
                Console.WriteLine(output);
                return true;
            }
            else
            {
                Console.WriteLine("Bad things happened... ");
                return false;
            }
        }

Now let’s call that using Polly:

        static async Task Main(string[] args)
        {

            //https://localhost:44368/weatherforecast

            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri("https://localhost:44368")
            };

            var retryPolicy = Policy
                .HandleResult<bool>(false)               
                .RetryAsync(3, (response, retryCount) =>
                  {
                      Console.WriteLine($"Received a response of {response.Result}, retrying {retryCount}.");
                  });

            var result = await retryPolicy.ExecuteAsync(() => GetTheWeather(httpClient));            

            Console.WriteLine("If we get here, we either succeeded or gave up ");
        }

All we’re doing here is telling Polly that we want a policy that acts on a return value of False (in theory, I imagine you could set this to something like .HandleResult(“Aardvark”) and have it retry while the method returned a value of Aardvark). RetryAsync sounds pretty obvious, but the Async part is very important, otherwise, you won’t be able to use ExecuteAsync… and you’ll spend a while wondering why (so I hear)!

ExecuteAsync is awaitable, so it will wrap the retry logic in this single line.

The advantage here is that you can define a retry policy for your application, or several retry policies for your application.

References

https://github.com/App-vNext/Polly

https://github.com/bryanjhogan/trydotnet-polly

Manually Adding DbContext for an Integration Test

In EF Core, there is an extension method that allows you to add a DBContext, called AddDBContext. This is a really useful method, however, in some cases, you may find that it doesn’t work for you. Specifically, if you’re trying to inject a DBContext to use for unit testing, it doesn’t allow you to access the DBContext that you register.

Take the following code:

services.AddDbContext<MyDbContext>(options =>
                options.UseSqlServer());
         

I’ve previously written about using UseInMemoryDatabase. However, this article covered unit tests only – that is, you are able to instantiate a version of the DBContext in the unit test, and use that.

As a reminder of the linked article, if you were to try to write a test that included that DBContext, you might want to use an in memory database; you might, therefore, build up a DBContextOptions like this:

var options = new DbContextOptionsBuilder<MyDbContext>()
                .UseInMemoryDatabase(Guid.NewGuid().ToString())
                .EnableSensitiveDataLogging()
                .Options;
var context = new MyDbContext(options);

But in a scenario where you’re writing an integration test, you may need to register this with the IoC. Unfortunately, in this case, AddDbContext can stand in your way. The alternative is that you can simply register the DbContext yourself:

var options = new DbContextOptionsBuilder<MyDbContext>()
                .UseInMemoryDatabase(Guid.NewGuid().ToString())
                .EnableSensitiveDataLogging()
                .Options;
var context = new MyDbContext(options);
AddMyData(context);
services.AddScoped<MyDbContext>(_ => context);

AddMyData just adds some data into your database; for example:

private void AddTestUsers(MyDbContext context)
{            
    MyData data = new MyData()
    {
        value1 = "test",
        value2 = "1"                
    };
    context.MyData.Add(subject);
    context.SaveChanges();
}

This allows you to register your own, in memory, DbContext in your IoC.

Building a list with Asp.Net Core

I’ve recently been working with Asp.Net Core to build some functionality, involving building a list of values. Typically, with Asp.Net Core using Razor, you have a form that may look something like this:

@using (Html.BeginForm("MyAction", "ControllerName", FormMethod.Post)
{
    @Html.AntiForgeryToken()
    <div class="form-group">
        @Html.LabelFor(model => model.MyValue)
        @Html.TextBoxFor(model => model.MyValue)
    </div>

    <div class="form-group">
        <button type="submit">Submit</button>
    </div>

This works really well in 90% of cases, where you want the user to enter a value and submit. This is your average CRUD application; however, what happens if, for some reason, you need to manipulate one of these values? Let’s say, for example, that you want to submit a list of values.

For the sake of simplicity, we’ll say that the controller accepts a csv, but we want to build this up before submission. You can’t simply call a controller method for two reasons: the first is that the controller will reload the page; and the second that you don’t have anywhere to put the value on the server. If this was, say, a method to create an entry in the DB, the DB entry, by definition, couldn’t exist until after the submission.

This all means that you would need to build this list on the client.

A solution

Let’s start with a very simple little feature of Html Helpers – the hidden field:

@Html.HiddenFor(model => model.MyList)

This means that we can store the value being submitted to the user, without showing it to the user.

We’ll now need to display the data being added. An easy way to do this is a very simple table (you can load existing values into the table for edit scenarios):

    <div>
        <table id="listTable">
            <tbody>
                @if ((Model?.ValueList ?? null) != null)
                {
                    @foreach (var v in Model.ValueList)
                    {
                        <tr>
                            <td>@v</td>
                        </tr>
                    }
                }
            </tbody>
        </table>
    </div>    

Pay particular attention to the Table Id and the fact that the conditional check is inside the tbody tag. Now let’s allow the user to add a new piece of data:

    <div class="form-group">
        @Html.LabelFor(model => model.NewValue)
        @Html.TextBoxFor(model => model.NewValue)
    </div>
    <div>
        <button type="button" id="add-value">Add Value</button>
    </div>

Okay, so now we have a button and a field to add the value; we also have a method of displaying those values. We’ll need a little bit of Javascript (JQuery in this case) to append to our list:

@section Scripts {
        $('#add-value').click(() => {

            const hiddenList = $('#MyList');
            const newValue = $('#NewValue');

            if (!hiddenList.val()) {
                hiddenList.val(newValue.val());
            } else {
                hiddenList.val(hiddenList.val() + ',' + newValue.val());
            }
            
            $('#listTable > tbody:last-child').append('<tr><td>' + newValue.val() + '</td></tr>');            
        });

On the button click, we get the hidden list and the new value, we then simply add the new value to the list. Finally, we manipulate the table in order to display the new value. If you F12 the page, you’ll notice that the Razor engine replaces the Html Helpers with controls that have Ids the same as the fields that they are displaying (note that if the field name contains a “.”, for example: MyClass.MyField, the Id would be MyClass_MyField).

When you now submit this, you’ll see that the hidden field contains the correct list of values.

References

https://stackoverflow.com/questions/16174465/how-do-i-update-a-model-value-in-javascript-in-a-razor-view/16174926

https://stackoverflow.com/questions/171027/add-table-row-in-jquery

https://stackoverflow.com/questions/36317362/how-to-add-an-item-to-a-list-in-a-viewmodel-using-razor-and-net-core

Create and Test an MSix Installation

I’ve previously written about the new Msix packaging project here. One thing that I didn’t cover in that post is that, whilst the process described there will allow you to create an Msix package, you will not be able to deploy it on your own machine. In fact, you’ll likely get an error such as this if you try:

App installation failed with error message: The current user has already installed an unpackaged version of this app. A packaged version cannot replace this. The conflicting package is 027b8cb5-10c6-42b7-bd06-828fad8e3dfb and it was published by CN=pcmic.

Because this has run on your machine, there’s a conflict with the installation. Fortunately, removing the installed version is quite easy; first, copy the package name (indicated below):

Launch a copy of powershell (as admin) and enter the following command:

Get-AppxPackage -name [packagename] -AllUsers

In my case, that would be:

Get-AppxPackage -name 027b8cb5-10c6-42b7-bd06-828fad8e3dfb -AllUsers

You’ll then see something similar to the following (copy the PackageFullName):

Now you can remove the package:

Remove-AppxPackage -package [PackageFullName] -AllUsers

In my case:

Remove-AppxPackage -package 027b8cb5-10c6-42b7-bd06-828fad8e3dfb_0.2.5.0_x64__sqbt0zj9e43cj -AllUsers

Unfortunately, you don’t get any indication this has worked, so type the get command again:

Get-AppxPackage -name 027b8cb5-10c6-42b7-bd06-828fad8e3dfb -AllUsers

And you should see that nothing is returned. Now, when you run it, it should be fine:

References

https://developercommunity.visualstudio.com/content/problem/198610/another-user-has-already-installed-an-unpackaged-v.html