This article shows how to setup a Raspberry Pi from scratch, install the .NET core SDK and debugger and then demonstrates publishing and debugging a couple of simple programs remotely from a desktop or laptop.
Having set up Raspberry Pis for .NET core and remote debugging manually, I wanted an easier, more automated solution. The benefits being that it would be:
- Easier and less time consuming
- Less error prone
- Easier to keep up with new versions of Raspbian
- Headless - i.e. no need for a monitor, keyboard or mouse.
There were plenty of other articles that cover this subject, probably the most useful to me was this article by Scott Hanselman. However, they all required a lot of manual setup. I wanted a solution that was as automated as possible. Obviously, there needs to be some manual intervention because you have to physically move SD cards, power up devices, etc., but other than that, my aim was to run a script and the setup would just happen. As Scott Hanselman says:
A good (kind of a joke, but not really) programmer rule of thumb is - if you do something twice, automate it.
I wanted the setup to achieve the following:
- Starting with a newly formatted SD card on the development machine
- Configure the card to allow remote ssh when transferred to the Raspberry Pi
- Configure the Raspberry Pi for secure passwordless ssh connection
- Install .NET Core and the VS remote debugger
Finally, I would add a couple of C# projects to demonstrate it all working.
Choice of Tooling
I've been using VS Code for a few years now and really like it - so that is what I decided to use (I've also used various versions of Visual Studio for decades now - but I'm not going to go into the advantages and disadvantages of each of them here. :))
I also like Powershell a lot, but decided to use Bash for the scripts. That would hopefully make this as cross platform as possible. You will need to configure VS Code to have bash as the default shell - the easiest way to do this is to press Ctrl+Shift+P and type
default shell. This will give the option of command prompt, Powershell or various flavors of Linux. The one that worked best for me was Git Bash but other ones should work too.
The VS Code solution can be copied anywhere on your development machine. When opening it in Visual Studio Code, use Open Folder from the File menu.
You'll need a way to get the Raspbian image onto the SD card. I would recommend the Raspberry Pi Imager. You don't have to download the image first but I think it is worth doing because otherwise you could find yourself using a lot of internet bandwith (images tend to be gigabytes even when zipped). Downloaded images are accessed via Use custom on the image list.
You'll need a Wifi router, and you'll need to know the SSID and PSK. I assume you have those :). And obviously a Raspberry Pi and power supply. I tested this on a Raspberry Pi 3 but any version from V2 upwards should be ok. Note that this won't work on a Raspberry Pi Zero because that uses ARMV6 which is (sadly) not supported by .NET core. If your Raspberry Pi doesn't have Wifi built in, you will also need a USB Wifi dongle.
Finally, you will need to download the latest version of .NET core SDK. At the time of writing, that was version 3.1. This should be copied to the PiFiles folder. You'll need the ARM32 version and you should expect it to be over 100MB in size.
Preparing the SD Card
Once you have a newly flashed SD card, it needs some extra configuration before inserting it into the Raspberry Pi. This is task 1 and 2. To run tasks, press Ctrl+Shift+P and select Tasks: Run Task. You should see a list of tasks like this:
Select task 1. Set Wifi Settings... This will ask you for your Wifi SSID and PSK. When you enter these, they will be stored in settings.json so you don't have to enter them again.
Then select task 2. Modify SD Card for SSH access... This will ask you for the drive with the SD card. Because this will be accessed in a bash script, this is likely to be something like /d or /mnt/d. If you have just imaged the card, it may need to be reinserted because the imaging program ejects it when it is finished. Once you have run task 2, you should eject the card and insert it into the Raspberry Pi. Power up the Raspberry Pi and wait for it to boot up before going onto the next step.
SSH Configuration and .NET Installation
The next step is to run task 3. Set Raspberry Pi Name. This will change the hostname from the default raspberrypi to a name of your choosing. You will also be asked if you want to set a static IP address. If you don't want a static IP, leave this blank. My experience with Windows 10 and local hostname lookups (mDNS) has been patchy - I'm not sure it is as reliable as it should be. However, even if you can't get local name resolution working at all, you should be able to use IP addresses instead. As before, these settings are remembered in settings.json so you don't have to reenter them.
Having set the new name, task 4. Add public SSH key to Raspberry Pi will reconfigure the Raspberry Pi and copy the public ssh key to it so that you don't have to enter the password when you (or the VS tools) connect via ssh. You will be asked if you want to connect (type
yes) and then for the raspberry pi password (type
raspberry). At this point, the Raspberry Pi will reboot, so you need to wait before running the next step. If you don't have an ssh key already setup, articles like this show you how to create one. You will now be able to login without having to type in the password, but only from your machine.
Task 5. Raspberry Pi Dotnet install will install the .NET core SDK and VS debugger on the Raspberry Pi. This will take a while but once complete, we are now able to write .NET programs either on the Raspberry Pi itself or remotely on our main development machine - obviously remotely is going to be a lot more fun!
I have created two example programs. The first one is a Hello World project. This will run both locally (i.e., on the development machine) and remotely. The easiest way to run it is to select the Run icon on the left hand side and choose the configuration from the dropdown:
You should now be able to set breakpoints and debug just as you would locally:
In order to run the Blink program, you will need to connect a LED to one of the GPIO pins. The blink program uses the excellent System.Device.Gpio library which should be automatically installed using NuGet.
In the next article I will show how to create a larger and more realistic solution including unit tests, dependency injection and mocking. That article can be found here:
Developing .NET Applications for the Raspberry Pi: Part 2
Points of Interest
So that's it for this article. It probably would have been a lot easier to write the blink program using Python, but for me, the whole point of using C# is that you can create much larger and more maintainable solutions with .NET (although I'm sure some people will disagree with that). Having said that, the demonstration programs in this article are not intended as templates for larger programs. I have written another article (see above) that sets out what I think is a good structure, including a library for the GPIO interfacing (still using System.Device.Gpio) and a unit test project. I've worked out how to mock the Gpio calls using Moq and dependency injection. I think it should also be possible to create a custom
Gpio.Device and make a simulator but that will have to wait until article 3...
- 1st May, 2020: Initial release
- 7th May 2020: Minor updates
- 25th May 2020: Add reference to Part 2