Consuming a WebAPI Endpoint on Localhost from the Visual Studio Android Emulator

It is highly likely that any Xamarin Android application that you build will be consuming a RESTful API. And when you are developing the application, you don’t want to have to deploy that API to the Internet somewhere. You just want to run it up on localhost. It will make for a much faster development experience, as you will be able to iterate a lot quicker.

There’s not an abundance of help from the community on this and it took me about a day to figure it all out. So, hopefully this post will short-circuit the task for you.

My first port of call was this great post by the formidable Brian Noyes.

But it did not get me the whole way there. He left out a few important details, such as the fact that you need to run Visual Studio (“VS”) on elevated privileges to host the API on a IP address other than localhost. Otherwise, you will get the following error message Unable to connect to web server ‘IIS Express’.

So lets get to it…

You’ll need to install the Visual Studio emulator for Android which you can read about here. Note that it uses HyperV. This is great, but has a consequence. If you have VMWare’s VMWare player on your machine, you can forget about running any VMWare VMs as they are incompatible with HyperV. It is either one virtualization technology or the other. As the Visual Studio Android emulator is so good and fast, I ditched VMWare on my system.

So, here are the steps you need to do and I’ll assume you have already created an ASP.NET Core WebAPI project running on the full .NET framework (and not .NET Core).

  1. In this step, you need to configure your WebAPI project to serve up the API on a particular IP address (which is not localhost). Your Xamarin app needs to hit that IP address. Obviously, however, when production-ready, it will hit the full url of your production deployment of the Web API application. (I’m guessing you have already worked out that the localhost of your Android app is the Android device itself. So, localhost won’t help you.). To host the Web API on such an IP Address, open the applicationhost.config file, which lives in the hidden folder called .vs in the root directory of your ASP.NET Core solution (in a subfolder called config). Look for a bindings element inside the site element for your site and add a binding for; something like:
           <binding protocol="http" bindingInformation="*:57971:localhost" />					
           <binding protocol="http" bindingInformation="*:57971:" />

    Note the IP Address, which I will discuss in the next step. Remember, you have to run Visual Studio with elevated privileges to host the Web API on that IP address. So when you fire up Visual Studio, do it with Run as Administrator.

  2. From Noyes’ post, “With the VS Android Emulator running, click on the double caret >> button in the side toolbar. This opens up the settings UI, one of which is for Network.” Now, look through the Desktop Adapters for one which has the IP address For me, that was Desktop Adapter #4. It may have a different number for you. This is the one you have to use. It has to have an IP address of So, this step is really more to confirm that one of the Desktop Adapters has that IP address. The mistake I made was that Noyes’ article stressed the usage of Desktop Adapter #2. But it is the IP address which is important, not which adapter number it has. Once you have confirmed that is the IP Address for one of the adapters, you can move to the next step. Oh and obviously all calls to your local WebAPI in your Xamarin app should be made to that IP address.
  3. The last thing you need to do is open a port in your dev machine’s firewall for the port upon which your WebAPI project is listening. So, if you are running it on IIS Express on port 57543, then you need to create an inbound firewall rule permitting TCP connections to that port. This makes perfect sense, because the Emulator is a different machine, to all intents and purposes. It’s a stand alone virtual machine running in HyperV. And it is calling into your dev machine’s localhost services externally.

There’s not many steps, but the trick is figuring them out! Hopefully that saves you some time!

NDepend v2017

With NDepend v2017 being released recently, I thought I had to give it a test drive. Whilst I’m not an architect, sometimes I have to do a bit of architecture. Especially with home projects. It’s not like I can call Architects-R-Us and have them send an Architect around to produce an architecture for every app idea I have. And so I have a slowly growing interest in this space. This time I thought I’d write more of a tutorial about how to get going with NDepend.

Once you’ve downloaded NDepend and got the exe on your hard drive, you fire it up and point it at the sln file for a Visual Studio solution which you want to profile. It will pick up the projects in your solution and the dialog will look a little like this:

Figure 1 – Analyze Assemblies dialog

Click the Analyse 10 .NET Assemblies button and NDepend will perform its analysis and come back with another dialog:

Figure 2 – Analysis Complete dialog

The other thing it did was to launch an html NDepend Report Summary, because I had the Build Report checkbox ticked in the first dialog. More on that report summary later. So I clicked on the Show NDepend Interactive Graph button:

Figure 3 – Assemblies Graph

A dependency graph is displayed and it is interactive! I clicked on the UI node (far left) and it lit up the map with the dependant assemblies. More importantly, it showed a couple of windows which are yellow in colour and positioned at the left and foot of the screen. The window at the foot has help topics relevant to the current context. The window on the left is the most interesting. It is scoped to the selected graph node and provides a heap of at-a-glance information about that graph node and its descendants. Lets try again and click a node lower in the graph.

Figure 4 – Assemblies Graph with Descendant Selected

Figure 5 – The Dashboard

You can see that the ancestor nodes in the graph are green and the descendant nodes are blue. And again, the pop-up dialog (this time on the right) contains information scoped to the selected graph node (in this case, HomeLibrary.UiModel, a project which contains my DTOs): Despite a couple of issues in the code, I’m happy with the information which this graph is telling me. The dependencies are pretty much what I intended and I’m getting a good 50,000ft view of that. So lets poke around a bit more. I’ll click on the Dashboard tab a the foot of the main pane. This shows me a plethora of information and the thing I really like about it is the use of colour. Red – bad. Yellow – warn. Green – pass. At a glance, I can get a feel for the health of the application.

Figure 6 – Quality Gates

Figure 7 – Rule Violation

I can see I have 2 Quality Gate fails. That basically means I cannot release my application. Not until that number goes down to 0. Lucky this is just a sample application. So, lets take a look at what I need to fix! After clicking on the little red “2” link, I found that 1 of the 2 quality gates was a collection of 6 rules which I had transgressed:
There was one which immediately interested me, so I investigated further. It was called Attribute class name should be suffixed with ‘Attribute’. Absolutly! That would not like me to do otherwise. So, I double-clicked that rule to discover the culprit:

Looks like NoReorder was a class that was generated by JetBrains (probably Resharper). Being a generated class, I feel like I’m cool with this. And so here is where things get interesting. I’m going to try something here. If you look at the image immediately above, you can see some text which looks like a LINQ query. That’s called CQLinq and is what NDepend uses to return the results which show whether rules have been violated or not. As an extensibilty point, NDepend allows you to modify these queries and save them. And it saves them for this project. So, I made a quick and small modification to the query, taking advantage of the intellisense which is available in that context:

	// <Name>Attribute class name should be suffixed with 'Attribute'</Name>
	warnif count > 0 from t in Application.Types where 
	   t.IsAttributeClass && 
	  !t.NameLike (@"Attribute$") &&
	  t.FullName != "KesselRun.HomeLibrary.UiModel.Annotations.NoReorder"
	select new {
	   Debt = 5.ToMinutes().ToDebt(),
	   Severity = Severity.Major

I added the line of code t.FullName != "KesselRun.HomeLibrary.UiModel.Annotations.NoReorder". When I saved the query, that rule was no longer violated. I’m not sure if that is NDepend’s recommended way for handling that, but it is pretty cool that you can have such fine-grained control.

Moving on from Quality Gates, I want to take a look at a new Feature in NDepend 2017 called Technical Debt. They’ve taken this well-known concept and applied it in an innovative way into NDepend. You can see from the Dashboard screenshot above a section called Debt. Scoped to the overall solution, my app is receiving a B. But you can also see how this value changes depending on where your context is scoped to. If you take a look at the 2 dependency graph screenshot above which have the yellow information windows, you would have noticed a Debt Rating item. And it is scoped to whatever I have clicked. So what is this?

In a nutshell, they have used some algorithms to quantify the technical debt for each issue and rule violation. And that makes sense. If NDepend has found a problem, presumably there will be a time associated with fixing it. And even cooler, they have added an interest component. Every year the problem remains unfixed, the “time to fix” will grow. The debt grows with interest! That’s darn smart, because that’s how it works in the real world. The longer a code smell or bad design hangs around, the harder it becomes to fix. This kind of quantifying debt is great, because you can use it to buttress the business case to fix bad code (which, no doubt, you have inherited :)).

As with all things NDepend, the Debt data can be viewed from many different perspectives:

Figure 8 – Technical Debt Representations

The last feature I want to make mention of is the html report that you can generate with NDepend when it performs its analysis. The easiest way to do this is check the Build Report checkbox (under the Analyze button – see Figure 1 at the top of this post for that checkbox):

Figure 9 – Build Report

The report is kinda like the dashboard, but in html format. Here’s an online example of a report from an analysis that was run on NodaTime. In addition to the sections of the report (such as Diagrams, Quality Gates Summary, Rules Summary) on the front page, there is a fly-out menu from the left which gives you even more information. This includes items such as Dead Code, Hot Spots and even Trend Charts. This report is something you can host on a server, so it can easily be made available to stakeholders etc. in your organisation.

As an overall observation, I should also point out that the UX employed on NDepend is really innovative and clever. When you have that much information coming at you, it would be very daunting and confusing if the user interface was not good. But the NDepend user interface is excellent. It’s very intuitive. Navigating around is so easy and you only have to use it for half an hour or so before you feel really comfortable with all that data. That is a small amount of time to be able to get on top of a code analysis tool like NDepend. As time goes by, you become even more comfortable with it and stumble upon more of its hidden gems. And that is before I even thought about referring to the documentation on the NDepend site, which is very detailed and complete.

There’s so much more about this tool which could be covered, such as Continuous Integration, Visual Studio team Services build integration, Code Diffs … I’ve only really scratched the surface.

For people like me whose role slowly bleeds its way into the architecture space, we need all the help we can get. Tools like NDepend really help with this. Not only is it a hands-on-tool which gives a great overview of the health of your codebase, it also acts as a tutor. It gives advice and teaches with problem descriptions and suggestions. Resharper improved my code skills. NDepend will improve my design/architecture skills.

Dates in Javascript and UTC in the Browser

So dates are hard. Computer languages have varying success in implementing them. Take C#. If dates in C# were awesome, Jon Skeet would have had no cause to write Noda Time. I’m going to write a couple of posts about Javascript and dates, as they have caused me quite a bit of pain in recent months. Today, I will kick off with the UTC story (or lack thereof) for dates in Javascript (in the browser, anyway).

I’ll use C# to make a few comparisons in my analysis, just to highlight what is lacking.

As a really brief examination of what C# can do with dates in the context of UTC, just run the following:

var nowUTC = DateTime.UtcNow;
Console.WriteLine(nowUTC.ToLongDateString() + " " + nowUTC.ToLongTimeString() + " " + nowUTC.Kind);

You’ll see that you have a DateTime value which represents the UTC time for that point in time and has a Kind of UTC (not local). A DateTime can’t tell you what timezone it is in. It just knows whether it is local or UTC. Timezones (as distinct from offsets) are political and shift with policies of governments. So it is not trivial to build them into a computer language. Note: DateTimeOffsets are a generally better struct than DateTime and contain UTC and the offset from UTC. But the point is, here we have a UTC value representing a point in time and what that time is with a +0 UTC offset.

Now, lets turn our mind to Javascript. If you were to create a Date object, using the new keyword, and write that out to the console, it would look something like this:
Fri Jan 27 2017 22:04:36 GMT+1030 (Cen. Australia Daylight Time).

You can see there’s a time offset and even a helpful addition of the name of the timezone in brackets. Yay for Javascript. Now try and create a Javascript date object that is UTC (making sure you are located in a timezone other than the Zulu timezone, of course). Here’s a hint. You can’t. Not really, anyway.

But what about all those things you read on Stackoverflow, like toISOString and methods of the Date constructor such as getUTCFullYear etc.? Yes, lets talk about that.

First, I will dispense with toISOString. Some may say that to get UTC, you can just write:

var now = new Date();
var utcnow = now.toISOString();

The fact is, toISOString returns a string representation of UTC. Not a Date object. Now, you have a string. So my assertion holds.

What about a bit of sneaky epoch shifting? Say, we wrote something like this:

var now = new Date();
var now_utc = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(),  now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds());

Have we achieved a UTC Date in Javascript yet? I would say no. If you log that Date object out to console, it would look a little like this:
Fri Jan 27 2017 11:34:36 GMT+1030 (Cen. Australia Daylight Time)
Look familiar? Sure, it’s 10.5 hours before the actual local time, but it still has the same local offset and timezone of the browser. So what happens if you now give that to a component which shifts the epoch again based on the offset? Now we are behind UTC. And we’ll have a Date object which still has the same offset. UTC has turned into a moving target, always leaping back in time by 10.5 hours.

But what about the static UTC method of the Date constructor? Something like:
var utc = Date.UTC(1900,08,18,0,0,0);
I hope you like milliseconds, because that is what that method returns. The number of milliseconds from Jan 1, 1970. And you can always pass that into a Date consructor, but you’ll just get a Date object with the browser offset and timezone.

And there’s one more scenario I’d like to cover. What if we call the Date constructor as a function? That is, without the new keyword?

var nowFromFunction = Date();

Sorry to disappoint, but that just returns a string. The string is local time as well. So, not a Date object and not UTC.

Now, it is true that Javascript dates track UTC internally. However, that is internals and components such as various HTML 5/Javascript datepickers don’t process internals.

Thus, unless someone can prove me wrong, I am asserting that you cannot create a UTC Date object in Javascript. Not like the way you can in C#.

Here’s a plunk to play with: Date plunk.

Oh and by the way, I was wondering why I did not pick this up when I learnt Javascript. So, I went back to the source – the Flanagan book. There is not a peep in there about how dates behave in the browser, vis-a-vis always stamping them with the local timezone and offset.

As I said at the outset, Dates are hard.

The Nightmare Contractor

I’ve always been told to be wary of contractors. We’ve all heard the story of the contractor who

  1. comes,
  2. destroys; then
  3. leaves.

And I’d never had to farm off any work to a contractor until now, so I had no real preconceptions. But you know that feeling you get when all of your worst fears about something are realised? I mean absolutely everything you feared came to pass. That is what happened with us, when we hired Igor (not his real name). He brought to bear all of our worst fears and more. In short, it has been a nightmare.

Red flags were raised with Igor right off from the start. In his interview, when asked what things in programming excited him today, he kinda sighed and told us, “nothing”. And that he only wrote code for the money to fund his round the world trips. See, Igor only works about 6-7 months every year. Then, he just sets off around the world on holiday. The ULTIMATE tourist. We weren’t spoilt for choice in interview candidates, so hard choices were made. Given that it was a short-term contract, we reasoned that it did not matter whether Igor enjoyed his job. And he kinda sold us on his ability with bold language. “I’ve been doing this for 10 years. I can just do it in my sleep.” “I’ve never encountered a problem I couldn’t solve.” Well, now he has. Multiple.

Things started in a promising fashion when Igor commenced his contract. He had this way of speaking which exuded confidence; like he always knew what he was talking about. When he “fixed” the first problem which was assigned to him, he had this way of explaining the issue and his “fix” which evoked the portrait of an experienced professional, who had taken control of the situation and conquered. There was a combination of authoritativeness, assertiveness and calmness to it. (Lets forget for a minute that he never actually fixed that problem, and like all of his messes, it was left to me to fix it.) But he spoke like that the whole time. Even in the end, when he must have known that his work was a house of cards.

Igor lambasted the work of all who came before him. I always found this amusing as the particular application which I am maintaining included code from some of Australia’s best .NET developers. It is the best codebase I have ever maintained and I’ve had nothing but respect for that work. You will probably find that amusing too, when I post a couple of Igor’s code samples (stay tuned for that). He seemed to think that he had it all worked out and had nothing to learn from anyone else. I confess, I was actually caught up in his “spell”. He was so convincing, and kinda knew how to talk the talk in such a way, that he came across as someone who was a master at his art. This ability to convince is what is so dangerous in a rogue contractor. You don’t check in on him, because you think he has it all under control. You think he is going to nail it. Big mistake…

There were some warning signs which I should have attached more importance to. For example, my employer uses GIT for source control. Igor had never used GIT. But he hated it. (He hated something he’d never used?!). I had to listen every day in that first week to how much better TFS was than GIT. Even 4 months into his ill-fated tenure, Igor had not really grasped GIT. Watching over his shoulder one day, I saw that he had around 20 copies of the application’s repository. I’ll just repeat that. He had 20 copies of the application’s repository, all lined up next to each other in separate folders. That might be something you would do with TFS and different Workspaces. But it’s just not necessary with GIT and he clearly did not understand how it worked (despite my free tuition, which he also did not seem to be grateful for).

He also believed that all enterprise web applications should be done using WebForms and not MVC. Given how awful Webforms is, I found that puzzling. But then I noticed a pattern. Igor did not like AngularJs. He did not like using any tools I showed him, like Resharper or Fiddler. Then it snapped into focus and became clear. He didn’t like learning new things. He was inherently lazy. That also gelled with the fact that you could never get a full day’s work out of him. Clock-watcher extraordinaire. His idea of starting at 9am is walking in the door at 9am, chatting in the kitchen with all and sundry until finally being logged in on his machine at 9:25am at the earliest. 25 minutes at contractor’s rates! I couldn’t, in good conscience, do that (I am also a contractor). And don’t get me started about the other end of the day. And then there were the long disappearances throughout the day, during which he could not be found.

Another great memory of Igor was the handover. It was definitely a red flag when he started getting stroppy and aggressive. When we were looking at a gigantic service with gigantic methods and an over-abundance of regions (I swear, there was one case where he surrounded 1 line of code with a region), Resharper lit up a veritable slew of issues. So I picked one and asked whether a particular variable that Resharper had “greyed out” was being used. “I don’t know”, came his curt reply. So we checked and it wasn’t being used anywhere. The function-call which was on the right-hand side of the assignment was very expensive. So I checked that for side-effects. There were none. So I asked, quite ernestly, do you think we can get rid of that? His reply was a juvenile, “I don’t care. Do what you like. This is not my problem in 3 days time.” This is why you should use Resharper kids. Mmmkay. Mmmkay. He could not tell me much about his code, but he assured me it worked. As it turned out, it didn’t. Not even close. It was littered with gotchas, including logic errors such as “if” guards which always resolved to true (in every possible scenario). Again, Resharper kids.

There were a handful of times where I had to “pull rank” on Igor. That is, we’d disagree and after no side budging, I would say, “please do it my way”. And there was 1 issue of this type where he was consistently insubordinate. If he was a full time employee, it would have been a serious problem. It was all about when to push to origin using GIT. I am of the view that when you are working on a team, you push to origin at least once per day (usually the end of the day). Even if your code throws a run-time exception, so long as the code builds, it is fine to push. Even if you have to comment out a block of code to make it build, you push to origin at the end of the day. It is not a problem if it throws an exception at run-time. Other team members know it is in development, and thus, not finished. They can easily check whatever tool they are using to track tasks to verify the status, anyway (Jira, whatever).

Anyway, that is how I’ve always been taught to do it. Igor was of the view that you push to origin once you have completed work on the feature which you are working on. I am flabbergasted that a dev can hold that view after a decade of development experience. Imagine the merge hell that would ensue if it took him 3 weeks to complete that feature. And I’d argue, “What if your PC gets stolen over night, or your hard disk fails when you boot up one morning”.  His scientific response to me was, “Yeah, like that will ever happen”.  Well guess what happened? We had a power outage which toasted Igor’s machine. So, we were having a meeting about how to handle this situation and I said to our manager, “Won’t be a problem. Igor will lose almost no work because he would have pushed before he went home yesterday. He can bring it all down again onto another machine” At that point, Igor said, “I haven’t pushed since last week”. And this next bit is the bit that made me “see red”. He turns to our manager with a straight face and says, “I wasn’t in a position to push anyway”. At this point I had a choice to make. I call him out in front of our manager, effectively telling our manager that, not only is he bullshitting her, but that he has been blatantly not following my procedure, despite me reminding him to do so quite often. Or do I sit there silently. I did the latter. Then after the meeting, I walked up to his desk and with a cold stare said, “Hey! Push to origin every night. Just do it”. He knew what he had done. Incredibly, even after this fiasco, we were to have this argument again several weeks later where he was still putting forward his position of push-when-done. I could not believe we were still talking about this and suggested we take it up with the head of the Applications Development department. Strangely and reluctantly, Igor declined and agreed (once again) to start pushing every night. CourageOfHisConvictions == null.

On that note, sometimes, to settle arguments, I would drag in one of the other developers in the company for their view (we all communicated via Slack every day). Igor would suddenly back away. Stand down. Step off. Deep down, the dude knew he was wrong. He just hated standing down, 1-on-1, from me because I was less senior than he was. I was his lesser in the unhealthy dynamic which had developed between us. The difference between us is that I would concede things, from time to time. If he raised good points and was correct, I would admit it and walk away having learnt something. He never conceded a thing and maintained that he was right, at all times. A complete and utter lack of wisdom. And that’s how Igor walks through life.

Another toxic aspect to Igor was the fact that he could go into a meeting, lay down a position to non-IT people (advice/recommendations) and do so with all the confidence in the world, when he really had absolutely no idea what he was talking about. An example of this was an offline app which we are currently building. Igor was adamant that it had to be native. He had security concerns, otherwise. I did not quiz him in the meeting, but over lunch I started to probe about these security concerns. Not because I was looking to show him up or expose him. But because I am naturally curious, love learning and can be a bit deterministic in my questions – meaning I wanted a real answer, as distinct from a general shrugging off and hanging it on “security concerns”. A person who knew their stuff could cite those concerns. Possibly give an example. Again, Igor showed his colours by getting irritated when I kept asking for specifics. The best defence is offence and he started getting churlish again. I probed a bit more generally and discovered that he had never even heard of Apache Cordova or Ionic. So he was giving definitive, expert advice on a topic which he knew very little about. Note, we are currently building the app using Ionic.

Before concluding, I want to re-iterate that part of the reason I’m writing this is because of Igor’s hubris and (almost) callous disregard for his client. He had an opportunity to fix his messes, but he chose to cut and run. And he will probably tell anyone who’ll listen that he did a great job here (although I doubt very much that he will be using us for a reference).

Igor has left in his wake a team of people that curse his name on a near-daily basis, on account of the pain they are living with because of his mistakes/bad designs. All future developers who have encountered his work react with either a shake of the head or an exclaimed “WTF!”. That is his legacy here.

So, after all that fun storytelling, it is time to take a look at some code snippets (there were many, many more doozies, I just don’t have time to go looking for them. Remember, this is the code of a 10-year code-cutter):

The “if guard” Logic Disaster

These were everywhere:

if (categoryName != null || categoryName != "")
	// will ALWAYS come in here
	// will NEVER come in here

He meant to write:

if (!string.IsNullOrEmpty(categoryName))
	// will ALWAYS come in here if the string is not null and not empty
	// will NEVER come in here if string is null or empty


He wrote a method called AlwaysPositive which does exactly what Math.Abs does. WTF! There’s not too much wrong with AlwaysPositive, but just use Math.Abs! It is in the framework and has useful error-checking built in:

private int AlwaysPositive(int i)
	if (i >= 0)
		return i;
		return i * -1;

To Null-Coalesce or Not to Null-Coalesce

The next one is no big deal. Technically, it works. But I feel like it separates people who know the language from those who don’t.

DateTime? rangeStart = null;
var fromDate = Convert.ToDateTime(rangeStart);

should be

DateTime? rangeStart = null;
var fromDate = rangeStart ?? DateTime.MinValue;

jQuery Sets

jQuery has been around for a long time. Most competent developers understand how its selectors work and how it returns sets which contain items (if any) that match the selector. They also understand that where no items match a selector, an empty set is returned. So, when Igor wrote the following code:

  if($('#someDiv') !== typeof undefined) {
    // flow will come in here every time because the set will never ever ever ever ever be undefined.

mayhem ensued on the client side. Easily fixed with:

   if($('#someDiv').length > 0) {
    // flow will only come in here where a div with the id "someDiv" exists in the dom.

Lesson learnt. I will not be stung by the proverbial Nightmare Contractor again. And if I ever see Igor’s resume again in any job I am in, it will be fast-tracked beyond the recycle bin with a shift-delete permanent delete.

Regex Support in Notepad++

I’ve always loved Notepad++ and still think it has a place in this new world of Atom, Brackets, Sublime, Visual Studio Code et al. Notepad++ fills that sweet spot where you need something more powerful than a simple text editor, but something short of the “new coding editors”.

I recently had to massage some data, which I had extracted from an Excel file, into a csv file. It kinda looked like this and went for 800 lines or so:

15,Lower leg
22,Upper limb

I needed to change that, so that the text was enclosed in single quotes as so:

15,’Lower leg’
22,’Upper limb’

I did not really want to manually type those single quotes around the text for a file with 800 lines “and change”. And there was no simple find and replace opportunity unless I turned to regex!

The pattern I used was reasonably straight forward. There were 2 things I had to match:

  1. the integer before the comma (a primary key); and
  2. the text following the comma.

This would allow me to leave the primary key in tact, whilst replacing the text with itself wrapped in single quotes.

In the Find what input, I added the regex: (\d+),(.*)$
And in the Replace with input: $1,'$2'

I’ve included a screenshot below:


And don’t forget to click the Regular Expression radio button at the foot of the dialog. Pretty nice regex support saving a huge amount of time for me.