Introduction to VS Code: Part 1

I have to admit I have not used VS Code much. When coding on my personal projects, I am using Visual Studio for Mac on my MacBook Pro or Visual Studio on my work laptop. In my last blog, I discussed options for replacing Visual Studio for Mac. Just in case you did not know, the official retirement date for Visual Studio for Mac is August 31, 2024. You have some time to start switching over to another IDE. There are several options that I pointed out in that article.

So now it is time for me to really start learning VS Code. This series of blogs introduce you to VS Code with the new C# Dev Kit and related extensions. It will be focused on building a solution on a Mac but the same should apply to running VS Code on as Windows laptop.

Downloading and Installing VS Code

Where can you download VS Code? If you installed VS Code a while ago, you probably need to go ahead and install it again with the latest (VS Code 2). Here is the download link:

On the download page for VS Code, select the correct installer for your Mac or laptop.

Once downloaded, open your downloads folder. On a Mac, the download will be a zip file.

Unzip the file by double clicking it and you will now have an application called Visual Studio Code 2. You could run it from downloads folder but not highly recommended.

So instead drag it into your Applications folder on the left bar. Now you can easily access it via CMD Space shortcut and starting to type Visual Studio Code.

Pretty simple to do on a Mac. Also notice how long that took you to do. Maybe 10 minutes… That will be an underlying theme with VS Code. Starting VS Code is so much quicker than VS. Opening a solution is also so much faster.

Installing C# Dev Kit and other related Extensions

After installing VS Code, now comes the fun. You need to install some extensions. It seems like everything in VS Code is an extension.

In order to add extensions, tap the “Extensions” icon on the left navigation bar. You will notice a badge icon when you need to update or reload VS Code since an extension was updated.

Now you can search the market place for the extensions you want to install. Here is a list that you probably want to start with…

  • C# Dev Kit
  • IntelliCode for C# Dev Kit
  • C#
  • .NET Extension Pack
  • .NET Install Tool
  • and since most of my development is for Azure, I also added many extensions for Azure
    • Azurite
    • Azure Functions
    • Azure Databases
    • Azure Resources
    • and the list goes on and on…

VS Code Walkthroughs

When VS Code opens, you’ll notice Walkthroughs on the right side of the splash screen. There is a lot of great tutorials to help you learn VS Code.

Existing Visual Studio Solutions and Projects

Once VS Code is open, you can also easily open existing solutions you already created in Visual Studio for Mac. Just click the “Open” button to start. Browse to the folder where your existing solution is and open it.

Here is an existing project that I opened in VS Code.

I can edit, save, build and debug using VS Code.

Now let’s start something from scratch

My idea is to have an API that drops a message onto a Service Bus so an Azure Function can read the message. Let’s also add a class library to share between the API and the Azure Function. Hmm, am I biting off more than I can chew??? Probably but let’s see how easy or hard it is to do this… Once we have that working, we’ll add a Web Application and then continue building out a real world example…

My code can be found here: RWE Repo

Create a new Solution: Umm, where the #$@% do I start

Let’s create a new solution… This is soooo foreign to me. Where is my menu option to create a solution??? Well there is none. To create a new solution, you basically create a folder/workspace and run a command in the terminal. So let’s go ahead and do that.

Obviously open VS Code

Select File > Open Folder from the main menu.

In the Open Folder dialog, create a folder. I called my folder RWE for “Real World Example”. Next, click Open.

Now open terminal by selecting View > New Terminal. Terminal opens with the command prompt in the folder you just created.

In Terminal, run this command: dotnet new sln. This will output the following result: The template “Solution File” was created successfully.

Now I have a solution. But seriously nothing is in it.

So let’s create a Class Library

Most solutions in today’s world have a common class library to share across the various projects. This will be easy, right? It wasn’t terrible, but to be honest I fumbled around with all the commands. Luckily, you can just follow these steps…

In the terminal, run the command to create a class library.

  • dotnet new classlib -o RWE.Common

Now we need to add it to the solution so we need to run another command.

  • dotnet sln add RWE.Common/RWE.Common.csproj

Now open the solution file. You can see that it added a reference to the Project file.

The .NET Target Framework is set to 7.0. You can verify that in your project file.

Straight out of the box, you have to type every thing by hand in VS Code. Creating class files by hand each time seems a little tedious. I tried finding some CLI to create a class or an interface class. Most of what I found just created an empty file. It would be much better for me if I had menu that could help me create my classes. I quickly found an extension to do that. You might want to install the it before moving on.

Next let’s create a new folder called “Logger”. You can do this by right clicking on the Project.

In this folder, let’s create a new class called “AppLogEvents.cs”. After installing the Extension above, you can right click and select “New C#”.

Here is the class I created.


using System;
using Microsoft.Extensions.Logging;

namespace RWE.Common.Logger;

public static class AppLogEvents
{
public static EventId Create = new(1000, "Created");
public static EventId Read = new(1001, "Read");
public static EventId Update = new(1002, "Updated");
public static EventId Delete = new(1003, "Deleted");
}

Now you will notice we are missing a reference.

So let’s add it. In the Terminal window, go ahead and type the following command:

  • cd RWE.Common
  • dotnet add package Microsoft.Extensions.Logging

Take a look at your project file and you will notice a new line referring to the new package that was added.

Lets add another class called: “AppLogTemplates.cs

using System;
using Microsoft.Extensions.Logging;

namespace RWE.Common.Logger;
public static class AppLogTemplates
{
    private const string IdPropertyName = "Id";
    private const string MessageIdPropertyName = "MessageId";
    private const string EmailPropertyName = "Email";
    public const string SendMessagePostBegin = $"Sending a message to Service Bus. Id: {{{IdPropertyName}}} Email: {{{EmailPropertyName}}}";
    public const string SendMessagePostEnd = $"Completed sending message to Service Bus. Id: {{{IdPropertyName}}} Email: {{{EmailPropertyName}}}";
    public const string SendMessageBegin = $"Begin - {MessageIdPropertyName}: {{{MessageIdPropertyName}}} {EmailPropertyName}: {{{EmailPropertyName}}}";
    public const string SendMessageEnd = $"End - {MessageIdPropertyName}: {{{MessageIdPropertyName}}} {EmailPropertyName}: {{{EmailPropertyName}}}";
}

Delete the class.cs class that was created when the project was created.

Finally, build the project by using the following command:

  • dotnet build

Let’s create the WebAPI

In the terminal, change the directory to the root folder of the solution and run the command to create a class library.

  • cd ..
  • dotnet new webapi -o RWE.WebApi

Now we need to add it to the solution so we need to run another command.

  • dotnet sln add RWE.WebApi/RWE.WebApi.csproj

The .NET Target Framework is set to 7.0. You can verify that in your project file.

Let’s add the class library to the is project using the following command:

  • dotnet add RWE.WebApi/RWE.WebApi.csproj reference RWE.Common/RWE.Common.csproj

Let’s create a new API controller. This is much easier now that we have the new extension. In the Explorer view, right click on the Controllers folder. Under New C#, select Api Controller. A box will appear in the top middle of VS Code. Type in the name for your file – SendMessageController.cs.

I added the logger in plus a Post action that just logs a begin and end.

using Microsoft.AspNetCore.Mvc;

namespace RWE.WebApi.Controllers;

[ApiController]
[Route("[controller]")]
public class SendMessageController : ControllerBase
{
private readonly ILogger<SendMessageController> _logger;

public SendMessageController(ILogger<SendMessageController> logger)
{
_logger = logger;
}

[HttpPost]
public ActionResult Post()
{
_logger.LogInformation(RWE.Common.Logger.AppLogEvents.Update, RWE.Common.Logger.AppLogTemplates.SendMessagePostBegin, 10, "someemail@gmail.com");

// Do something cool later...

_logger.LogInformation(RWE.Common.Logger.AppLogEvents.Update, RWE.Common.Logger.AppLogTemplates.SendMessagePostEnd, 10, "someemail@gmail.com");

return Ok();
}
}

Now, let’s build the project. You will notice that is build both projects and should be successful if everything was done right.

Time to debug… Open Program.cs. Then, click the fourth icon down on the navigation bar on the left. This is the your debugger. Click the “Run and Debug” button.

Select the language…

Now select the configuration you want to debug.

Swagger is pre-configured which is pretty slick and the browser opens ready for you to to start debugging API endpoints.

Add a breakpoint to the new controller and execute your “Post” action by clicking the execute button.

The debugger should stop on the line you added your breakpoint too.

Now we have a Class Library and a Web API in our solution. We can edit, build and debug the code in VS Code.

Conclusion

So when I first started, I was a little nervous about not having all the menus that Visual Studio offers but now I am getting the hang of it. Starting to see why people rave about using VS Code. It starts much faster than Visual Studio.

In the next article, we’ll add an Azure function to the solution. This will be a little more time consuming setting up this project and debugging it.

References

Visual Studio for Mac: Retiring August 2024

Do you love your MacBook? Do you love coding on it using Visual Studio For Mac? Well, I have some sad news for you. Visual Studio for Mac is being retired. The announcement was less than two years after releasing Visual Studio for Mac with the all new native macOS UI. The official retirement date is August 31, 2024.

I remember being so excited installing Visual Studio on my Mac. For the development I was doing, it worked great. I was able to easily migrate my Xamarin app into Visual Studio for Mac. Also built several .NET Core web apps and APIs I still use today. Unfortunately, I still ran Parallels with Windows and Visual Studio for all my legacy .NET apps that I still had to migrate. But I was looking forward to the day when I could jettison the VM and only code using Visual Studio for Mac. That dream is over…

So now what? Microsoft is proposing using one of these options.

  • VS Code with the new C# Dev Kit and related extensions.
  • Visual Studio IDE running on a Windows VM on a Mac
  • Visual Studio IDE running on a Windows VM in the Cloud

Another option might be giving up on my Mac altogether but I have always enjoyed building apps for iOS and Android using Xamarin. I also want to explore building a Blazor App for iOS. So giving up my Mac is not an option. I don’t want to buy a Windows laptop since I already own a nice MacBook. I certainly don’t want to install a Windows VM on my Mac again. That always felt kludgy. I never really explored using VS Code on my Mac. So maybe it’s time. But after a little googling, I found another option. Honestly kind of forgot about Jet Brains. I haven’t used any of their products in over a decade. It is kinda hard to find budget to buy Jet Brains when you have the Visual Studio Enterprise License.

So it seems if your goal is to avoid running a VM on your Mac, then you have two descent options:

  • VS Code with the new C# Dev Kit and related extensions.
  • Jet Brains Rider with dotUltimate (but not free)

My next article will be an introduction to VS Code on a Mac, installing extensions, creating a solution, creating some projects, writing some code and finally some debugging.

Advertisements

References

Off the beaten path: Thanksgiving Pie

For those of you who celebrate Thanksgiving in the good old US, I hope you had a wonderful Thanksgiving! I had a great Thanksgiving this year. Once again my kids and I made our favorites… Pumpkin Pie, Buttermilk and Lemon Chess. I decided a long time ago to carry on the pie making tradition in my family. My Grandmother made all her pies from scratch and my Mom continues to make all her favorite pies as well. Most of the recipes have been passed down on hand written notes.

This year my wife bought me a book on pie making that really helped out. If you are starting out for the first time or just dabble a couple times a year, I highly recommend this book. The book is “Pie Is Messy” by Rebecca Grasley with Willy Blackmore. Here is the link to checkout the book (FYI, I am not an affiliate with Amazon, just including links to Amazon since really easy for most people):

I normally bake my pies in glass pie dishes. However, after reading the first few pages, I purchased a set of metal pie pans from Amazon. As Rebecca explains on Page 9 in the “Pie Is Messy” book, metal pans produce a flaky crust and a bottom crust that is fully browned. My wife thought this was the best crust we ever made due to the metal pans. Here is a link to the ones I bought for Thanksgiving this year:

Advertisements

Rolling pie dough is pretty messy in my house. We get flour pretty much everywhere causing the OCD in my wife to go off the charts!!! But this year she bought us the OXO Good Grips Silicone Pie Dough Rolling Bag. It is awesome. The mess is minimal. Sorry Rebecca… Making Pies is not as messy in my house anymore thanks to OXO.

This year I made another major change in my approach to making our pies. I did NOT use my KitchenAide Mixer. Instead, I make mixed everything by hand. I think this helped the pie dough turn out better as well as the pies since I did not over mix.

Advertisements

Hope you found this little diversion off the beaten path useful. Now I have a couple more blogs coming out this soon on Visual Studio for Mac retirement and switching to VS Code on a Mac.

Azure Function Tip: Configuring Schedule for Timer Triggers

When setting op your first trigger you normally hard code the schedule like so:

Function("ProcessExternalMessageTrigger")]
public void ProcessMessageTrigger([TimerTrigger("0 */2 * * * *")] TimerInfo myTimer)
{
     _logger.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

This setup works just fine. But if you need to change your timer, you have to change the code, check it in, get your PR approved, deploy it to your QA and Test environments and finally deploy to prod. Inevitably, as soon as you get it to production someone says “Opps, you thought we meant to run every 5 minutes but we meant to run once an hour, blab, blah…” And now you have to repeat the process. Or do you…

Instead you can easily add a configuration in your local.settings.json file for this. You simply add a new setting and set the value to your CRON expression. Here is a sample of two timer schedules:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "AzureWebJobs.ProcessInternalMessageTrigger.Disabled": false,
    "AzureWebJobs.ProcessExternalMessageTrigger.Disabled": false,
    "Schedule.ProcessInternalMessageTrigger": "0 */2 * * * *",
    "Schedule.ProcessExternalMessageTrigger": "0 */3 * * * *"
  }
} 

In your method, use your setting key surrounded by %. For example “%{Setting Key}%”. Now you can change your schedule across your environments easily without changing your code, redeploying, etc…

[Function("ProcessInternalMessageTrigger")]
public void ProcessInternalMessageTrigger([TimerTrigger("%Schedule.ProcessInternalMessageTrigger%")] TimerInfo myTimer)
{
    Do Something Cool...
}

[Function("ProcessExternalMessageTrigger")]
public void ProcessExternalMessageTrigger([TimerTrigger("%Schedule.ProcessExternalMessageTrigger%")] TimerInfo myTimer)
{
    Do Something Cool...
}

Final note is that Azure Functions use NCRONTAB expressions. If you are looking for a tool to evaluate your expression check out this one by Neils Swimberghe:

Also check out his blog while you’re at it. He has a lot of great articles on C#, Twilio, Visual Studio, and more!

References:

Azure Function: Failed to verify “AzureWebJobStorage” connection specified in “local.settings.json”

Since Visual Studio for Mac is being retired, I finally started learning Visual Studio Code (vscode). Still getting used to a few things but really starting to like it. I setup an Azure function and was debugging just fine a few days ago. After restarting VSCode, I started getting the following error.

Based on the error message and after googling a little, I figured Azurite was not running locally. Completely forgot I had to start Azurite each time I need it after restarting VS Code. I am so used to Visual Studio on my Windows laptop just running the Azure dev storage environment automatically for me.

In VSCode, you need to open Command Palette to start Azurite. This is the first item under the View menu. Or if you’re pretty good at remembering shortcuts, then use Shift + Command + P. In the prompt type “Azurite: Start Blob Service”. This will start Azurite and you can now start debugging your Azure Function again.

So now I have to remember how to do that every time I restart VS Code and try to debug/run a project that relies on Azurite. That seems a bit annoying. Maybe there is another way…

Rescued by VSCode Tasks

VS Code Tasks are pretty slick. You can setup tasks that automatically run for you. In my case, I really want Azurite to start when I open my Workspace for my solution.

In order to get this to work, I needed to install Azurite via npm. If you do not have Node.js installed, please install it from this link.

Then run this command in your terminal: npm install -g azurite. Note: you may have to install this using sudo depending on how your Mac is configured.

Now we need to update the tasks.json file to automatically start Azurite for us.

Here is the task to copy into the file:

		{
			"label": "🟣 Launch Azurite storage emulator",
			"type": "shell",
			"command": "azurite --blobHost 127.0.0.1",
			"windows": {
                           "command": "azurite --blobHost 127.0.0.1"
                        },
			"group": "build",
			"isBackground": true,
			"runOptions": {
                            "runOn": "folderOpen",
			}
		}    

Save the file. Now close your workspace and open it again. This time notice the terminal starts and automatically runs Azurite for you. That’s super easy to setup and pretty cool feature of VSCode!!! VSCode certainly gives the dev so much power over their environment.

References:

Azure Function Tip: Enabling and Disabling a Trigger via Config

You can configure your Triggers to be enabled or disabled in your Azure Function via the configuration settings.

In order to test this, setup an Azure Function with a couple triggers.

In your local.settings.json, you can configure one or more or your triggers to be disabled. The syntax is AzureWebJobs.{Function Name}.Disabled.

    "AzureWebJobs.ProcessInternalMessageTrigger.Disabled": false,
    "AzureWebJobs.ProcessExternalMessageTrigger.Disabled": true

Now run the debugger for your Azure Function. You will notice the following output based on your settings. Try flipping your flags and rerun.

Why would I use this feature…

I can think of a couple reasons.

First, when I am developing, it might be nice to disable all the triggers except for the one trigger you are currently working on.

Second reason is for managing your deployments based on features. For instance, you might have an existing Azure Function that you added several new triggers too. These triggers are for new features your clients want. Once you deploy to production, you could have the triggers disabled via this setting. This way your new functionality is in prod just waiting to be turned on when the time is right.

Finally, this configuration would be really useful when deploying with slots. One slot can have the triggers disabled and the other slot could have them configured to enabled.

Reference