Fixing “a.zip” in Azure DevOps Pipelines

A screenshot of the Azure Pipleines Artifacts screen with an artifact called "a.zip"

If you’re using an Azure DevOps pipeline to build a project/solution and publish an artifact, you may have run into the magical situation where your artifact is automatically (and bafflingly) named a.zip.

A screenshot of the Azure Pipleines Artifacts screen with an artifact called "a.zip"

But how? Why? I didn’t ask for this!

I agree dear reader! This is actually the second time I’ve run into this particular issue without any clear documentation on why it happens, so I decided to be the change I wanted to see in the world (by writing this blog post).

The Cause

There are a few moving parts that need to align for this to happen:

  • You are using the DotNetCoreCLI@2 task with the publish command, e.g:
- task: DotNetCoreCLI@2
  inputs:
    command: 'publish'
    publishWebProjects: false
    projects: '$(project)'
    arguments: '--output $(Build.ArtifactStagingDirectory) --configuration $(buildConfiguration)'
    modifyOutputPath: false
  displayName: Publish my project
  • zipAfterPublish is true (in the above example it is missing but the default is true , so unless it’s specifically declared as false you can assume this is the case)
  • You’ve specified the --output flag with the $(Build.ArtifactStagingDirectory) variable (with no relative path on the end). This may also extend to other generated paths that the pipeline gives you access to

But why do these particular elements aligning cause your archive to be called a.zip? Because:

  • The project is zipped using the name of the folder it is located in
  • The path that $(Build.ArtifactStagingDirectory) expands to (in my instance) is… D:\a\1\a\!

Aha!

The Fix

OK, so we know why it happens now, but how do we change it? Thankfully the fix is nice and simple!

  • Change the --output flag to use a directory with the name that you actually want (for example, --output $(Build.ArtifactStagingDirectory)/MyArtifactName
  • If you’re using the PublishBuildArtifacts@1 task, update your PathtoPublish to the new directory:
- task: PublishBuildArtifacts@1
  inputs:
    PathtoPublish: '$(Build.ArtifactStagingDirectory)/MyArtifactName'
    ArtifactName: 'MyProjectArtifactName'
    publishLocation: 'Container'

And voila!

A screenshot of the Azure Pipleines Artifacts screen with an artifact called "MyArtifactName.zip"

What is Rust and do you need it?

A screenshot of a Rust error message in RustRover, stating "cannot borrow `s` as mutable more than once at a time" with clear ASCII arrows pointing at the usages

You may have heard of Rust in the news lately, what with Microsoft re-writing core Windows code in Rust and Linux officially accepting Rust in kernel development (standing now as only the third language alongside Assembly and C, which is genuinely really cool!). The common question that comes up shortly after reading about the rise of Rust is… should we be using this? Are we missing out? What are the downsides?

In this post I’m going to try and cover off the basics of what Rust is, where it fits (or could fit) into your existing software stack and whether it’s even worth the effort!

Continue reading “What is Rust and do you need it?”

HTTP 503 After Page Refresh in IIS Hosted Blazor Server App

An IIS exception reading "HTTP Error 503.0 - Server has been shutdown. The service is unavailable". The provided error code is 0x8007045b

Introduction

I’ve recently seen a very strange issue in a .NET 7 Blazor Server app; the problem was that when hosting it in IIS it started failing after any of the pages were refreshed (sometimes once, sometimes several times). I managed to reproduce it in multiple environments as well, indicating that it was very unlikely to be due to configuration (in IIS or for the server more generally).

There wasn’t really any documentation on this issue that I could find elsewhere, so I wanted to log it for future reference in the hope that it could help someone else in their hour of need!

In a rush? Jump straight to the fix!

Symptoms

  • Application is built using Blazor Server.
  • Running .NET 7, although it may happen with other versions.
  • Hosted on IIS.
  • The application crashes after a handful of page refreshes (approximately 1 – 5)
  • Error displayed is HTTP 503 “Server has been shutdown” (see image above).
  • The application works locally/in development using Kestrel (refreshing doesn’t lead to HTTP 503).
  • The application manages to launch and work correctly before the initial HTTP 503, but does not work after the error is seen.
  • Restarting the IIS site allows it to be accessed again until a user refreshes their browser or opens new tabs.
  • If a second tab/window is opened (and therefore there are two active circuits in Blazor Server), refreshing the first will cause it to return HTTP 503 but the other circuit will remain open and accessible, even supporting interactivity and allowing navigation through to other pages. Refreshing the second tab/window at this point however returns the same HTTP 503 error.
  • There are no exceptions thrown directly by the application.
  • There are minimal details in Event Viewer, such as:
    • Application Log
      • Source: IIS AspNetCore Module V2 error
      • Title: Failed to gracefully shutdown application ‘XYZ’.
      • Description: IIS ASP.NET Core Module V2 Request Handler
    • System Log
      • Source: WAS
      • Title: A process serving application pool ‘XYZ’ exceeded time limits during shut down. The process id was ‘123’.

Cause

The issue here was surprisingly simple: I had two instances of WebApplication.CreateBuilder() in Program.cs. I’m not clear as to why that causes an issue when running is IIS (especially when running it locally using Kestrel worked absolutely fine), but I speculate the HTTP 503 is caused by the first WebApplicationBuilder (which was the main app in my circumstance) ceding control to the second (which ended up being a kludgy hack that could be safely rewritten).

This would potentially explain why an open/active circuit continues to work after new connections start receiving a HTTP 503; the second has taken over on the IIS bindings and essentially shadows the first, preventing new connections. The reason that it is returning HTTP 503 is because the lifetime of that second is only during startup; once the garbage collector is able to invoke the disposal of the WebApplicationBuilder it shuts the “server” down.

The above reasoning on the cause is pure speculation (as I don’t have details of how IIS hosting works internally) but in my mind and based on the observable behaviour it seems to all fit.

Fix

Re-work your Program.cs startup so that there is only one WebApplicationBuilder being created, either by removing multiple calls to WebApplication.CreateBuilder() or by ensuring that there are no logical paths that could cause multiple builders to be generated.

C# struct, record class and record struct cheat sheet

A screenshot of C# code showing the creation of a record type called User and an example of instantiating and displaying that record

I’m not proud to admit it, but while I’ve known about the existence of struct and record for a while, I rarely reach beyond my faithful class.

I recently decided to do something about that though, which started with learning more about what these types are, what they should be used for and how I can interact with them. The issue though is that the information is spread all over and tends to look at each discretely which, considering the overlap between how they can be used, wasn’t really helping! That made comparing the available options more difficult and kept sending me running back to what I was used to.

While researching the types I ended up making a bunch of notes which I then decided to clean up and create a blog post out of as a sort of reference/cheat sheet for understanding where, why and how to use struct, record and record struct! Hopefully you find it as beneficial as I already have.

Continue reading “C# struct, record class and record struct cheat sheet”

An Honest Review of a Compressed Work Week

If you asked someone if they’d like to work four days a week instead of five, most people would jump at the chance. If, mid-leap, you informed them that they would still need to complete their normal weekly hours in that restricted set of days, I feel like a fair percentage of people would (much like a cartoon) freeze midair while contemplating the situation more thoroughly (and whether they should, in this tortured metaphor, complete their in-progress dive).

At Cortex we decided that during August, we’d give this exact scenario a bash. It’s a simple concept; take a 35 hour work week and compress it down into four days.

Now that we’ve finally slipped back into our old five-day routine I thought that it would be good to review the experience, what worked, what hurt and the things we didn’t even consider at the start.

Continue reading “An Honest Review of a Compressed Work Week”

Controlling and Preventing Navigation Events in Blazor Using NavigationLock

A screenshot of a Blazor application titled "Navigation Lock Demo" with controls and a series of links and buttons for testing the functionality of NavigationLock

NavigationLock is a component introduced in .NET 7 that provides a way to control or prevent navigation events in Blazor, something that was previously more difficult to pull off effectively.

With a single component you can now provide a handler for internal events and enable a flag to notify the user when they attempt to navigate away from the page, refresh the tab or close the window.

So how can you include it in your application, and how does it work? Let’s dive in and take a look!

Continue reading “Controlling and Preventing Navigation Events in Blazor Using NavigationLock”

“No suitable method found to override” error in Blazor/Razor pages

A screenshot of a series of errors in a Blazor application stating "No suitable method found to override"

I’ve run into an issue several times recently while working in Blazor where I’ll innocently try and run the application after some minor changes, only to be hit by a wall of errors seemingly out of nowhere:

ExamplePage.razor.cs(7, 29): [CS0115] 'ExamplePage.OnInitializedAsync()': no suitable method found to override
ExamplePage.razor.cs(12, 29): [CS0115] 'ExamplePage.OnAfterRenderAsync(bool)': no suitable method found to override
ExamplePage.razor.cs(17, 29): [CS0115] 'ExamplePage.OnParametersSetAsync()': no suitable method found to override
ExamplePage.razor.cs(22, 26): [CS0115] 'ExamplePage.SetParametersAsync(ParameterView)': no suitable method found to override

All of a sudden every single Razor component lifecycle function throughout the application is exploding and I’m left wondering how I managed to break things so spectacularly.

My approach to fixing this historically was:

  1. Take a look at my local changes in Git
  2. Try to tweak things to get it working again
  3. Fail
  4. Roll back everything and re-implement the change

It was frustrating and had wasted enough of my time over the past few months that I decided that I was going to figure it out once and for all, by gum.

Note: If you’re in a hurry the fix is quick and simple, so feel free to jump straight down to that section to skip my self-indulgent waffling.

Continue reading ““No suitable method found to override” error in Blazor/Razor pages”

SignalR Messaging Overview: A Look at How It All Hangs Together

A flow-chart representing the route a SignalR message takes through a standard SignalR implementation. A client browser is on the left, with a group called "MVC App" containing a Request Handler and ChatHubInstance. The flow goes starts with the request handler mapping the ChatHubInstance to the endpoint /ChatHubEndpoint. The client then connects to the SignalR hub using the defined endpoint and transmits a "SendChatMessage" message to the hub endpoint, which is translated into an actual procedure called SendChatMessage on the mapped hub. The SendChatMessage procedure then sends a "ReceiveChatMessage" message to all clients, which each invoke their "ReceiveChatMessage" handler on receipt.

SignalR is a fantastic library for enabling real-time applications, especially when using MVC or Blazor in ASP.NET Core. I’ve been using it a lot lately and while it is an excellent way to make your application feel super responsive through messaging and remote procedure calls, there are certain aspects of how the whole thing hangs together which can be very confusing.

This blog post is designed to give you an overview of the different parts of a “standard” SignalR implementation and explain how messages flow through the system. I won’t be going into details on how SignalR works internally (if I even could!), instead choosing to focus on the parts that you’ll come into direct contact with. This blog post also isn’t designed as a tutorial since there is great documentation for implementing SignalR already (which is where I sourced the below code examples from!).

Continue reading “SignalR Messaging Overview: A Look at How It All Hangs Together”

High Potentials Programme 2022 or: How I Learned to Stop Worrying and Love Project Management

A certificate that says "This certificate is awarded to Matthew Champion for the successful completion of the High Potentials Programme July 5th 2022", with logos and signatures from Avado and Blenheim Chalcot

Two days ago I graduated as part of the 2022 cohort of the High Potentials Programme, a 12 week leadership course delivered by Blenheim Chalcot and Avado Learning that looked at change/project management, leading teams and creating commercial value. Fancy.

A certificate that says "This certificate is awarded to Matthew Champion for the successful completion of the High Potentials Programme July 5th 2022", with logos and signatures from Avado and Blenheim Chalcot
I got a (digital) certificate and everything!
Continue reading “High Potentials Programme 2022 or: How I Learned to Stop Worrying and Love Project Management”

You Are Not Your Output

Maybe it’s just me, but if I look at our bug tracker at work one week and see my smiling face attached to a bunch of fixed bugs and implemented features then good lord do I feel chuffed with myself. When I manage to put together a blog post earlier than expected? Oh yeah, I’m amazing.

It’s not bad to feel proud of the things you produce of course, but the issue comes into focus when I look at Jira another week and I’ve only managed to clear a couple of tickets, or I barely manage to scrape together a blog post before the end of the month; my self-esteem plummets.

It’s honestly pretty ridiculous when I write it out like this, but it happens enough that I wanted to really take a look at why this happens. After a bit of introspection, I realised my issue; I’ve been judging myself by my output rather than my input.

Continue reading “You Are Not Your Output”