Bang & Olufsen HX wireless headphones: a delight

I’ve reviewed dozens of wireless headphones and earphones in the last six months, enough that I’m not easily impressed. The B&O HX wireless headphones are an exception; as soon as I heard them I was delighted with the sound and have been using them frequently ever since.


These are premium wireless headphones; they are over-ear but relatively compact and lightweight (285g). They are an upgrade of the previous model, Beoplay H9, with longer battery life (35 hours), upgraded ANC (Active Noise Cancellation), and four microphones in place of two. It is not top of the B&O range; for that you need to spend quite a bit more for the H95. Gamers are directed to the similarly-priced Portal model which has a few more features (Dolby Atmos, Xbox Wireless) but shorter battery life and no case; worth considering as it probably sounds equally good but I do not have a Portal to compare.


What you are paying for with the HX is a beautiful minimalist design and excellent sound quality. The sound is clean, sweet and exceptionally clear, perfect for extended listening sessions. Trying these out is a matter of “I just want to hear how they sound on [insert another favourite track]”; they convey every detail and are superbly tuneful. It is almost easier to describe what they don’t do: the bass is not distorted or exaggerated, notes are not smeared, they are never harsh. Listening to an old favourite like Kind of Blue by Miles Davis you can follow the bass lines easily, hear every nuance of the percussion. Applause on Alison Krauss and the Union Station live sounds like it does at a concert, many hands clapping. Listening to Richard Thompson’s guitar work on Acoustic Classics you get a sense of the texture of the strings plus amazing realism from the vocals. The drama on the opening bars of Beethoven’s 9th symphony, performed by the New York Philharmonic Orchestra conducted by Leonard Bernstein, is wonderfully communicated.

In other words, if you are a hi-fi enthusiast, the HX will remind you of why. I could also easily hear the difference between the same tracks on Spotify, and CD or high-res tracks on my Sony player. AptX HD is supported.


That said, there are unfortunately a few annoyances; not deal-breakers but they must be mentioned. First, the HX has touch controls for play/pause, volume, and skip track. I dislike touch controls because you get no tactile feedback and it is easy to trigger accidentally. With the HX you play/pause by tapping the right earcup; it’s not pleasant even when it works because you get a thump sound in your ear, and half the time you don’t hit it quite right, or you think you haven’t, tap again, then realise you did and have now tapped twice. Swipe for skip track works better, but volume is not so good, you have to use a circular motion and it is curiously difficult to get a small change; nothing seems to happen, then it jumps up or down. Or you trigger skip track by mistake. Ugh.

Luckily there are some real buttons on the HX. These cover on/off, and ANC control, which toggles between on, transparent (hear external sounds) and inactive. There is also a multi-button which activates voice assistants if you use these.

Want to use your headphones? Please sign in

Second, there is an app. I tried it on an iPad. Major annoyance here is that it does not work at all unless you create an account with B&O and sign in. Why should you have to sign in to use your headphones? What are the privacy implications? That aside, I had a few issues getting the app to find the HX, but once I succeeded there are a few extra features. In particular, you can set listening modes which are really custom EQ, or create your own EQ using an unusual graphic controller that sets a balance between Bright, Energetic, Warm and Relaxed. You can also update firmware, set wear detection on or off (pauses play when headphones are removed). Finally, and perhaps most important, you can tune the ANC, though changes don’t seem to persist if you then operate the button. You can also enable Adaptive ANC which is meant to adjust the level of ANC automatically according to the surroundings. It didn’t seem to me to make much difference but maybe it does if you are moving about.


The ANC is pretty good though. I have a simple test; I work in a room with a constant hum from servers and ANC should cut out this noise. It does. Further, engaging ANC doesn’t change the sound much, other than cutting out noise, which is how it should work.

There is a 3.5mm jack connection for wired use, but with two important limitations. First, this does not work at all if the battery is flat; the headphones must be turned on. Second, the jack connection lacks the extra connection that enables use for calling, so for listening only. The sound quality was no better wired, perhaps slightly worse, so of limited value.

Despite a few annoyances I really like these headphones. I doubt I will use the app, other than for firmware updates, and rarely bother with the touch controls, which means I can enjoy the lovely sound, elegant design, good noise cancelling, and comfortable wear.

HP unhinged, refuses to honour warranty on its defective laptop

My son bought an HP laptop. He is a student and bought it for his studies. It was an HP ENVY – 13-aq0002na. It was expensive – approaching £1000 as I recall – and he took care of it, buying an official HP case. He bought it directly from HP’s site. A 3-year extended warranty was included. Here is how the HP Care Pack was described:


After  a few months, the hinge of the laptop screen started coming away from the base of the laptop at one side, causing the base to start splitting from the top part.


He was certain that it was a manufacturing defect. However he did not make a claim immediately, because he needed the laptop for his studies, and he knew he had a long warranty. (I think this was a mistake, but understand his position). The December vacation approached and he had time to have the laptop sorted so he raised the claim.

HP closed the case. He had a confusing conversation with HP who offered to put him through to sales for paid service, he agreed (another mistake) and ended up talking to someone who quoted hundreds of pounds for the repair, which he could not afford.

He attempted to follow up but had no success. He did engage with HP Support on Twitter who seemed helpful at first but ended with this:


At no point did HP even offer to look at the laptop.

My son replied:

“The problem is absolutely not accidental damage or customer-induced – I’ve never dropped the laptop, and have always taken very good care of it (there are no marks on the chassis, for example). Whenever I’ve moved it around, it’s been in an HP case designed for the laptop. The problem emerged during normal use within eight months of me purchasing the laptop, and others have reported the same issue – for example, see this post on the HP forum:

The problem is the sole result of HP’s hinge design being inadequate. It’s therefore a manufacturing fault and should be covered by the care pack.”

Follow that link and you find this:


It is the same model. The same problem at an earlier stage. And 10 people have clicked to say they “have the same question”. So HP’s claim that “nothing has been reported” concerning a similar defect is false.

See also here for another case

“I bought my HP Envy in 2017 for university, unfortunately that means it is now out of warranty. One of the hinges is loose and pops out of place every time I open the laptop”

and here for another

“I purchased HP ENVY 13-aq0011ms Laptop in December 2019. After using about 1 year, (I treated it very gently all the time), the issue started: when the screen of the laptop is being moved to open/close, the chassis of the bottom case pops and split-opens”

and here

“Just after 13 months of buying my new HP Envy and spending 1400£ for it, the right hinge broke. There were no falls/accidents”

My son did attempt to follow up with customer service as suggested but got nowhere.

He knows he could take it further. He could get an independent inspection. He could raise a small claim – subject to finding the right entity to pursue as that isn’t necessarily easy. But he found the whole process exhausting. He raised a claim which was rejected, he escalated it and it was rejected again. He decided life was too short, he is still using the broken laptop for his studies, and when he starts work and has a bit of money he plans to buy a Mac.

Personally I’ve got a lot of respect for HP. I have an HP laptop myself (x360) which has lasted for years. I was happy for my son to buy an HP laptop. I did not believe the company would work so hard to avoid its warranty responsibilities. I guess those charged with minimising the cost to the company of warranty claims have done a good job. There is a hidden cost though. Why would he ever buy or recommend HP again? Why would I?

Note: HP Inc is the vendor who supplies PCs and printers, like my son’s laptop. HP Enterprise sells servers, storage and networking products and is a separate company. None of the above has any relevance to HP Enterprise.

PS I posted a link to this blog on the HP support forum, where others are complaining about this issue. I was immediately banned.


A surprising favourite: Shure’s Aonic 215 True Wireless Sound Isolating Earbuds

I have reviewed numerous wireless earbuds over the last six months, but the real test is which ones I pick out of the pile when going out for a walk or run. Often it is the Shure Aonic 215, despite some limitations. They are an unusual design which hook right over the ear instead of just fitting within; I like this because they are more secure than most designs and I don’t like the inconvenience or potential expense of losing a valuable gadget when out and about. Plus, they sound good.


How good? It was some years back that Shure opened my eyes (or ears) to how good in-ear monitors (IEMs) could sound. It was at a show, only a demo, and the IEMs had a four-figure price, but it made me realise the potential of in-ear electronics to sound better than any headphones I have heard.

I also have some lesser but much-used wired Shure wired IEMs which are a years old but still sound good. I’m happy to say that the Aonic 215s sounds substantially better in every way: clarity, frequency response, realism.

That said, the Aonic 215 true wireless has had a chequered history. Launched in April 2020, they were actually recalled by Shure because of problems with one earphone not playing, or battery issues. Shure fixed the issues to the extent of resuming supply but they are still a little troublesome.

If you value convenience above sound quality, you can get other earbuds that sound fine, have more features, and cost less – so go and do that.


Still reading? Well, if you like the Shure sound the True Wireless does have a lot going for it. It’s important to understand that this is a modular system. The Aonic 215 has Shure’s standard MMCX connector and you can get a cable that would let you use these wired. You can also get other Shure IEMs to connect to the True Wireless earhooks to let you use them wireless.

This package of course has them in one. You get a charging case too, which will charge the IEMs three times when fully charged. Play time is up to 8 hours (7 hours probably more realistic). Long enough for me.

Task number one is selecting the right ear sleeve. The aims is to create a seal in your ear. 6 pairs are supplied, including the one pre-attached. The best in my opinion are the foam type which form themselves to the shape of your ear, and which come in small, medium and large. Changing these is a little awkward and as ever one worries about damaging the unit but with a little twisting and tugging it is not too bad. Most other earbuds do not have these foam-type sleeves.

That done, you fit the earbuds and turn on. Now the fun starts. There is a single button on each ear hook, positioned on a circular piece which hangs behind your ear. You operate it either by squeezing this piece, or pressing the button which then presses into your head. I found the squeezing option better, but it is not super convenient.
Don’t worry too much though as functionality is limited. You can power on and off, pause, answer or end a call, and turn environment mode on or off. A triple click activates a voice assistant (I didn’t try this).

Environment mode? This is pretty useful, and lets you hear what is going on around you. If you want to have a conversation while listening, it is pretty much essential.

What’s missing though? Well, volume control and track skip are the key ones. You will have to use your player for that. Shure is still working on the firmware so this might improve, but one button is not much to play with.

Another potentially big deal is that calls only work in the right ear. This doesn’t bother me much, but for some it is a deal-breaker, depending on how you want to use them. I expect to use them almost entirely for music.

There is a Shure Play app for iOS and Android which describes itself as a high-res audio player. This has a graphic equalizer but it only works when playing music through the app, which excludes streaming sources. You can also adjust the environment mode. You need the app to update the firmware – which given the history of the product is quite important; the update history makes reference to “bug fixes.” The update is done over Bluetooth and takes around 30 minutes; my first effort failed because the mobile went to sleep. I got this done in the end by keeping the app open and touching it from time to time to stop it sleeping. Such are the things that lovers of high quality audio endure in pursuit of the best sound!

I use these earbuds mainly with a Sony Walkman music player and like the excellent sound quality, secure fit, and very useful environment mode. A few things to note about the sound, which is the main benefit here. You get aptX, AAC and SBC, with aptX best for quality but AAC important for Apple devices. There is only a single driver which limits the quality compared to the high-end Shure devices, like the ones I heard years ago, but it is still excellent. I would characterise it as neutral in tone, with particularly good separation and bass that is clean and not at all boomy. The lack of boom may come over as bass-light at first, but persevere and you appreciate this. It is important to have a good fit and if you don’t get the seal they will sound thin; of course every ear is different so how easy this is will vary. The design of the Shure also means that the sleeves can clog with wax and a little tool is supplied to help with cleaning.

Not for everyone then; but these suit me well. One last thing to mention: Shure unfortunately has a reputation as not the most reliable of earbud brands. In my case, one wireless unit went dead after a couple of weeks. Shure replaced it and all is well, but it is somewhat concerning.

Odd behaviour from Azure App Service: production version sometimes serves app from staging slot

I am developing an application which is deployed to Azure App Service. It runs on .NET 5.0 on Linux. I have set up a simple DevOps process so that committing changes to GitHub runs an Azure DevOps pipeline that deploys the application to a staging slot on Azure App Service for Linux. Then I can use Swap in the Azure portal to update the production slot. Swap simply exchanges the content of the staging slot with that in the production slot, so there is a route back in the event of disaster. Swap also restarts the application and forces users to log back in.

Yesterday I fixed a bug, deployed the change to the staging slot, and performed a swap. Logged back into the application, but the bug was still there, though intermittent. That was the bit I could not figure out: what was causing the code to behave differently on different requests? I became suspicious that it was sometimes serving the old version. I proved this by refreshing a page that demonstrated the bug. My page has an application version in the footer, and I could see that when the bug appeared, the version was older.



Well this is odd. In the App Service Deployment slot settings I have traffic set to 100% for the production slot:


In general I tend to assume a bug in my code or an error in my configuration settings is more likely than an issue with the Azure App Service. This does look odd though: why, if traffic is going 100% to the production slot, does the application sometimes serve the old version?

The pragmatic fix was easy. A second deployment to the staging slot means both now have code that works. The bug no longer appears; but I have kept the version number different and can see that the issue is actually still occurring.

I will update this post when I have more information, just in case anyone else hits this issue.

Some of my favourite earbuds and headphones of 2020: part 1

I love technology that endures and one of my most treasured gadgets is a pair of Sennheiser HD600 headphones. Mine are not quite that old, but this is a model that was first released in 1997 and remains on sale; they sound fantastic especially with a high quality headphone amplifier, and I use them as a kind of reference for other headphones. The ear cushions and headband perished on mine and I bought the official spares at an unreasonable price because I so much wanted to keep them going.


Still on sale today: Sennheiser HD600

They are as good as ever; but it happens that this year I have reviewed a large number of headsets and earbuds some of which I also like very much. First though, a few observations.

Passive headphones like my HD600s are in decline. I call them passive because they have no built-in electronics other than the speaker drivers. They can only work when wired to the output from an amplifier. Wires can be a nuisance; and as wireless options become cheaper, better and more abundant, wired is in decline (though it will never go away completely).

Once you go wireless, something else happens. The signal the headset receives over Bluetooth or wi-fi is a digital one. Packed into the receiving electronics is not just a pair of speaker drivers,  but also a DAC (Digital to Audio Converter) and an amplifier. Further, the amplifier can be optimized for the drivers. The output can be equalized to compensate for any deficiencies in the drivers or the acoustics formed by their case and fit. This is an active configuration and has obvious advantages, getting the best possible performance from the driver and also enabling smart features like active noise cancellation (if you add microphones into the mix). It should not be surprising that the better wireless devices sound very good. I have also noticed that headsets which offer both wired and wireless modes often sound better wireless, despite the theoretical advantages of a wired connection.

Another significant development is that off-the-shelf chipsets for wireless audio have got better. The leader in this is Qualcomm whose Bluetooth audio chipsets are packed with advanced features. SoCs like the QCC 3506 include adaptive active noise cancellation, 24-bit 96Khz audio, low power consumption, voice assistant support, fast pairing, built in DSP (Digital Signal Processing), and of course programmability for custom features.

It is because of this that there are now numerous budget true wireless earbuds and headsets from brands you might not have heard of, with these exact features.

The importance of the fit

A few years ago I attended a press event at CES in Las Vegas. Shure was exhibiting there and I got to try a pair of its premium IEMs (In-ear monitors). Until then I had been convinced that earbuds could never be as good as headphones; but what I heard that day changed my mind. The audio amazed me, sounding full, rich, spacious, detailed and realistic. I thought for a moment about it and realised I should not be surprised. IEMs are designed to be fitted directly to your ears; why should they not be of the highest quality? The best ones, like those at CES, have multiple drivers.

There is something else though. Getting the best sound from IEMs requires getting an excellent fit since they are generally designed to sealed into your ears; the once with expandable foam ear seals are perhaps the best for achieving this. If they are badly fitted then you will hear sound that is tinny or bass-light.

This means that it is worth taking extreme care with the selection of the right ear seals or ear sleeves, as they are sometimes called. Most earbuds come with a few sizes to accommodate different ear sizes. If the sound changes dramatically when you press the earbuds in slightly, they are not fitted right.

Something else regarding Shure, that I did not realise until recently, is that all its earbuds are designed to have a cable or (in the case of the wireless range) clip that fits behind your ears. The reason for this is that it makes it easier to get a good fit when the cable is not constantly pulling the IEMs out of position. Check out this video for details.

Earbuds that do not fall out

It is a common problem. You fit your earbuds and then go for a run or to the gym. With all that movement, one or both of the earbuds falls out. This can be a serious problem with wireless models. If you lose your earbud in the long grass or on a busy street; you might never find it again, or someone might trample on it.

There are a few solutions. The Shure approach makes it unlikely that the device will fall out. Another idea is to have a neckband that connects the two earbuds and hangs at the back of your head. I quite like this approach, since manufacturers can sneak some batteries into the neckband that give a longer play time than is typical with true wireless. It does not stop an earbud falling out, but it does mean you are less likely to lose it. Some people I’ve chatted to though feel it is the worst of both worlds, the battery and pairing issues of Bluetooth with the inconvenience or ugliness of wires. Up to you.

Airloop Snap 3-in-one

One brand, Airloop, claims to solve this by offering 3-in-one earbuds that can be used true wireless, or with a neckband, or with a lightweight “sports band” that has no batteries but does give a bit of security. The idea was good enough to raise hundreds of thousands in crowdfunding on Indiegogo and Kickstarter; they are nice devices but did not quite make my favourites list as I found the devices a little bulky for comfort, the firmware a little buggy, and the sound not quite what it should be at the price.

Don’t fret about the codec

One last remark before we get to my list of favourites. You will find a few variations when it comes to wireless standards and codecs. Headsets used for gaming generally use USB dongles for low latency. Other headsets generally use Bluetooth and support various codecs. The minimum today is SBC (low-complexity subband codec) which is part of A2DP (Advanced Audio Distribution Profile). Apple devices support AAC. Qualcomm’s aptX has advantages over SBC in compression, higher bitrate and lower latency. Sony has LDAC which supports higher resolutions.

In my experience though, the codec support is relatively unimportant to the sound quality. Yes, the better codecs like aptX or LDAC are superior to SBC; but compared to other factors like the number and quality of the drivers, the ease of getting a good fit (see above), and the quality of the electronics in other respects, the codec is less important. “As you may have noticed, it’s difficult to tell the difference between SBC and aptX by ear”, observes this article.

You can bypass these concerns by going wired; but when you consider the benefits of active amplification as well as the convenience of wireless, it is not a simple decision.

See part two (coming soon) for some of the headsets I have enjoyed in 2020.

A UI lesson: do not ask users to choose between Register and Login

I am developing a web site for playing bridge, a project which kicked off in March when lockdown caused bridge clubs everywhere to close. There are lots of sites where you can play bridge online, but not many options (particularly back in March) for clubs that wanted to run their own online sessions.

It’s going OK with a number of clubs now using it every week, though it is still in development. I have learned a painful lesson though. In order to proceed as quickly as possible, I started my project with the Visual Studio template for an ASP.Net Core application with ASP.NET Core Identity – the latter an easy decision since it handles all the complications of registration, password reset and so on. (I did end up having to re-plumb it to use int rather than GUID for the primary key but that is another story).

The default home page the template generates looks like this, with options in the menu to Register or Login.


Registration and login are fundamental concepts that have been part of the web forever. It’s simple for a developer to understand: you register to create an account, you login if you already have an account.

The painful discovery is that this is not obvious to everyone, particularly to an older demographic that did not grow up with computers. Another factor is that cookies, browser-saved passwords and single sign-on with Google/Facebook etc means that this whole area is a bit of a mess and there are people who just kinda expect web sites to know who they are (which in one way horrifies me but I do see the massive convenience).

The consequence is that a surprising (to me) number of people had difficulty knowing whether Registration or Login was what they needed. They would Register, then return to the site and hit Register again. Why is this site asking for my details again? Maybe a security thing? Oh no, why does it now say username not available?

This is because asking the user to make this choice is not good design. Registration is rare, login is common. Further, Register is a confusing word. We sometimes use the word register when accounts already exist. Create Account is better. And a better UI is just Login. I need to access this website. Then, underneath the username/password request, an option that says “I need to create an account”. The two options should not be equally prominent; and if you look at how many prominent sites design this, that is what they do:

image image

Lesson learned; but I wish this had occurred to me sooner!

Cyber Privacy by April Falcon Doss

This is a book about pervasive data collection and its implications. The author, April Falcon Doss, is a lawyer who spent 13 years at the US National Security Agency (NSA), itself an organization controversial for phone-tapping and other covert surveillance practices. Disturbing though that is, one of Doss’s observations is that “in democratic countries … the government doesn’t have nearly as much data as private companies do.” She argues that government-held data is less troubling since its usage is well regulated, unlike privately held data – though these safeguards do not apply in authoritarian regimes.

Government use then is just one piece of something much bigger, the colossal amount of personal data gathered on so much of what we do, our buying habits, what we search for on the internet, our health, our location, our contacts, tastes and preferences, all tracked, stored, and used in ways that we might not expect. Most of the book simply describes what is happening, and this will be eye-opening to anyone who has not followed the growth of data collection and its use in marketing and advertising over the last twenty years or so. Doss describes how a researcher analyzed his iPhone activity and found that “within seven days, the phone had exported data via 5,400 hidden app trackers.” – and Google’s Android is even worse.

How much do we care and how much should we care? Doss looks at this question which to me is of particular interest. We like getting stuff for free, like social media, search, maps and directions; but how aware are we of hidden costs like compromised privacy and would we be willing to pay in other ways? Studies on the subject are contradictory; humans are not very logical on the matter, and it depends exactly how the trade-off between privacy and cost is presented. The tech giants know this and in general we easily succumb to the temptation to hand over personal information when signing up for free services.

Doss makes some excellent and succinct points, as when she writes that “privacy policies offer little more than a fig leaf of user notice and consent since they are cumbersome to read, difficult to understand, and individuals have few alternatives when it comes to using the major digital platforms.” She also takes aim at well-intended but ineffective cookie legislation – which have given rise to the banners you see, especially in the EU, inviting you to accept all manner of cookies when you visit a web site for the first time. “A great deal of energy and attention has gone into drafting and implementing cookie notice laws,” she says. “But it is an open question whether anyone’s privacy has actually increased.”

She also observes that we are in uncharted territory. “It turns out that all of us have been unwitting participants in a multifaceted, loosely designed program of unregulated research,” she writes.

Personally I agree that the issue is super-important and deserves more attention than it gets, so I am grateful for the book. There are a couple of issues though. One is that the reason personal data gathering has escalated so fast is that we’ve seen benefits – like free services and personalisation of advertising which reduces the amount of irrelevant material we see – but the harms are more hidden. What are the harms? Doss does identify some harms, such as reduced freedom in authoritarian regimes, or higher prices for things like Uber transport when algorithms decide what offers to show based on our willingness to pay. I would like to have seen more attention paid though to the most obvious harm of the moment, the fact that abuse of personal data and social media may have resulted in political upheavals like the election of Donald Trump as US president, or the result of the Brexit referendum in the UK. Whatever your political views, those who value democracy should be concerned; Doss gives this matter some attention but not as much as it merits, in my opinion.

Second, the big question is what can be done; and here the book is short of answers. Doss ends up arguing that we have passed the point of no return in terms of data collection. “The real challenge lies in creating sufficient restrictions to rein in the human tendency to misuse information for purposes that we’ve collectively decided are unacceptable in society,” she writes, acknowledging that how we do so remains an open question.

She says that her ambitions for the book become more modest as the research continued, ending with the hope that she has provided “a catalogue of risks and relevant questions, along with a useful framework for thinking about the future” which “may spark further, future discussions.”

Fair enough, but I would like to have seen more practical suggestions. Should we regulate more? Should Google or Facebook be broken up? As individuals, does it help if we close social media accounts and become more wary about the data that we give away?

Nevertheless I welcome this thought-provoking book and hope that it does help to stimulate the future debate for which the author hopes.

BenBella Books (3 Nov. 2020)

Debugging Safari on an old iPad

Someone was trying to use the bridge application I have in progress, using an iPad 2.0. There were a couple of interesting things about this. One was that I had to rethink the warning thrown up, base on Modernizr, which detects incompatible web browsers. The problem (obvious when you think about it) is that if you use some potentially incompatible features in the same page where you are testing for them, then with an old web browser the JavaScript fails with a syntax error and the warning does not appear. The fix: I now show the warning by default, and the compatibility check hides it.

Still, I was interested in the Safari error and wanted to debug it, in case it was something I could fix. How do you debug Safari on an iPad?  The way it is meant to work is this:

– On a Mac, enable the Safari Develop menu (in Safari preferences, Advanced, Show Develop menu).

– On iOS, enable Safari Web Inspector (Settings – Safari – Advanced – Web Inspector).

– Connect the iPad to the Mac via USB. You can now use Web Inspector on the Mac to debug the Safari iOS pages and scripts.

This did not work for me on my Catalina Mac. The iOS Safari did not show up in the Web Inspector on Safari Mac. I could get it to show briefly, by switching Web Inspector on the iPad off and on again, but after than, no go. I tried a few things, but none of the proposed solutions I could find for this issue fixed it for me.

I have an older 2011 Mac Mini in a drawer, so I thought that might work, being a similar age to the iPad. I fired it up, marvelled at how old-fashioned the UI looked (I had reset it to OS X Lion), and connected the iPad. No go. Same problem as with Catalina.

Surprisingly, what did work were the instructions here (more or less) for debugging Safari iOS on Windows. This is based on the RemoteDebug iOS WebKit Adapter described here, a project which originated as an internal Microsoft experiment.


I did find it amusing that I could do this on Windows, having failed with the Mac.

The next generation of this is Inspect. This is in private beta, though the GitHub page for RemoteDebug says it has been superseded and to use Inspect instead.

It worked for me though.

Point-in-time restore: a handy built-in feature in Azure SQL

I am working on a project that is hosted in Azure and I made a mistake, running a SQL script that was dependent on another SQL script that I had forgotten to run. It messed up the foreign keys and I would have to restore a backup … but my most recent backup was from the day before. Annoying.

But wait. Looking the Azure portal I saw this:


This is a plain Azure SQL instance with no extras, but look, you can restore the database from 6 minutes ago.

I did it; it restored to a second database. I deleted the bad one, renamed the restored one, ran my scripts in the right order, and all was well.

I recommend you do not run scripts in the wrong order … but if you do, or make some other error, this is a handy feature of Azure SQL which I was not aware of before.

Wrestling with Azure DevOps Pipelines

Pipelines is an Azure service that enables a powerful feature: the ability to set up continuous integration. I have tangled with it before, in the context of trying Azure Kubernetes Service, but managed to avoid getting deep into the YAML which is the language of Pipelines. I am working on a web application and  trying to get it up to scratch as quickly as possible, especially as there are now a bunch of users who are being patient over glitches during development but whose patience may run out.

The application uses .NET Core which for the most part is working well for me. I am using Visual Studio 2019, with occasional forays into Visual Studio Code (VS Code), and deploying to a Linux Azure App Service. Everything was fine until one day when the Web Deploy feature in Visual Studio stopped working with “could not complete the request to remote agent … the operation has timed out.” I appealed for help but with no result yet.

All was not lost as I found that the VS Code Deploy to Azure extension worked pretty well. All I needed to do was to open the solution folder in VS Code, run:

dotnet publish -c Release -o ./publish

in the terminal, then right-click the publish folder and  then right-click the publish folder and choose Deploy to web app. There are a few annoyances but it solved the immediate problem.

One can do better though. Rather than manually deploying, you can create a pipeline using Azure DevOps (the thing that was once called Visual Studio Online and is the cloud version of Team Foundation Services). An attraction of using Azure Devops is that you get “1 Microsoft-hosted job with 1,800 minutes per month for CI/CD” free which seems decent.

I got started, creating an Azure DevOps project and adding a pipeline. You authorize it to access your GitHub repository (if that is what you have, as I do) and then end up in an editor that looks like this:


I soon got frustrated. The Pipelines service seems fundamentally excellent but spoilt by poor documentation and some odd behaviour – at least for .NET Core. It took me hours to achieve a basic setup that would upload, test and deploy my simple web application. Most of the time was spent observing pipelines fail to run and trying to figure out why.

When you run a pipeline you may notice that it uses .NET Core 2.1 and warns that 2.2 and 3.0 are end of life:

How do you get it to use .NET Core 3.1? You can add a snippet called UseDotNet@2 and specify the version. I put 3.1 and it was rejected as it likes a full version. I put 3.1.301 and it worked .

The most time-consuming thing for me was running tests. The application uses an Azure SQL database. It is unwise to put the database password in appsettings.json in the GitHub respository. How then do you connect to the database? The docs anticipate this and you can use a feature called variable substitution. In the Pipeline editor, you can add variables and mark them secret, so they are not included in logs. You can also use variables from Azure Key Vault. Then you can use the FileTransform@2 task to replace the connection string in appsettings.json with the one you need including the password. I do not think this is ideal from a security perspective – you are still putting the password in plain text in a configuration file – but it beats having it in the GitHub repository.

I had many issues. The main documentation on variable substitution is here. This is terrible. Note that if you look at the YAML example for JSON file substitution (which is what we need) it does not even use FileTransform@2. It uses AzureRmWebAppDeployment@4 which does a whole lot of other stuff as described here. Maybe I should have tried that. But FileTransform@2 looked like the right thing. Unfortunately it generally gives the error “Cannot perform XML transformations on a non-Windows platform.” No, I am not trying to do an XML transformation. Even if you specify the fileType as json and set enableXmlTransform to false, you still get the error. Later research suggests you can beat this error by setting xmlTransformationRules to an empty string. I gave up though and used FileTransform@1 (an older version of the task) which works as expected.

I still did not get the result I wanted though. All the tests using the database failed. Eventually I figured out that I had to set the folderPath to $(Build.SourcesDirectory). Then it works.

This was good. Now my tests run in Linux rather than on Windows, matching the deployed environment. In a full production environment I would use a second Azure SQL database for the tests, but for development this will do.

I then created a staging slot in the App Service and added a deployment step to deploy the application to that slot. Again, this is good. The application will not deploy unless it passes all the tests (this is a built-in feature of Pipelines, as each step does not run unless the previous steps succeeded). It deploys to staging which has a separate URL so you can try it out and not swap it to production until you are ready.

Overall, it is a better solution than the Visual Studio web deploy which it replaces, so perhaps the error did me a favour. It will work with Visual Studio as well as with VS Code, since it triggers automatically on every code commit. The Publish option in Visual Studio becomes redundant.

Note that Visual Studio also has an option to set this up automatically.


I tried it, letting the wizard do what it wanted including creating a new Azure DevOps project and a new App Service plan. Notable things:

– It created a pipeline using the Classic UI rather than the YAML based editor

– It uses an agent (the VM where the pipeline runs) called vs2017-win2016

– the pipeline did not get very far, failing on NuGet restore

No, I am not going to bother troubleshooting this.

This time yesterday I hated Azure DevOps pipelines. Nothing worked first time, YAML is a hostile editing environment (whitespace matters), and the documentation frustrated me. Now I feel pleased and I have this nice badge in my repository.


I am left with a nagging feeling though that all this is more difficult than it should be. It seems to me that what I wanted to do was commonplace: use .NET Core, use Azure App Service, have my pipeline build the project, run tests and deploy to staging. You could add, apply entity framework migrations in many cases. I did not find this documented in any one place and the result was that it took more time to figure out.

Tech Writing