Using Git to Sync Scripts Between PC and Pi
I run my Raspberry Pi headless most of the time; Connecting to it from my PC via SSH.
Nano is a fine text editor, but I’m more comfortable in Visual Studio on my PC. I could work in Visual Studio on the PC then copy and paste into Nano on the Pi, but that’s not ideal. It’s also easy to get out of sync and loss track of what’s where.
To improve my situation I set up a Git repository in Visual Studio Team Services. To be able to access it from the Pi it’s necessary to setup Alternate Credentials.
EDIT: VSTS now supports
I can now work on my code in Visual Studio, version control it with Git and pull changes straight on to my Raspberry Pi.
First set up a Git Team Project in Visual Studio Team Service.
Then, from the Pi shell, first clone the remote repository:
git clone https://{youraccount}.visualstudio.com/DefaultCollection/_git/{yourteamproject}
Then simply pull changes to the Pi when necessary:
git pull
Your credentials will be required every time you interact with the remote repository, but you can have Git store your credentials so you only need to enter them once:
git config credential.helper store
Warning: Your password will be stored in a file in plain text. Replace ‘store’ with ‘cache’ if you’d prefer your credentials were stored in memory instead, and not persisted at all.
UPDATE: VSTS now supports SSH connections, so there’s no need for alternative credentials or credential caching:
First, create an SSH key on the Raspberry Pi. (You could also use an existing key)
ssh-keygen -t rsa -b 4096 -C "you@email.com"
Press ‘Enter’ when prompted to accept the default file location.
Next, add the contents of ~/.ssh/id_rsa.pub to Visual Studio Team Services:
https://<you>.visualstudio.com/_details/security/keys
Finally, you can clone your git repo via SSH:
git clone ssh://{you}@{youraccount}.visualstudio.com:22/DefaultCollection/_git/{yourteamproject}
Handling Unhandled Exceptions in .NET 4.0
When an exception is thrown, the stack is unwound until a catch block is encountered that accepts the thrown exception type or a base class of it.
If a suitable catch block isn’t found in the call stack, the exception is unhandled and the application terminates immediately with a Windows error message, control of the application is lost.
To regain control, one of the .NET unhandled exception events can be hooked. These allow the developer to save the state of the application, log the exception appropriately, provide custom feedback to the user, or sometimes, stop the application from terminating.
Three unhandled exception events applicable to WPF applications are described below.
The AppDomain.CurrentDomain.UnhandledException event is raised when the entire stack for a thread has been unwound without finding an applicable exception handler. Even when using this event to catch unhandled exceptions, the application process can still be forced to terminate. Therefore, it is best to ensure unhandled exceptions cannot be raised by background threads.
static App() // Static Constructor { AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler; } static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e) { // Log the exception, save state, etc. }
The method below will trigger the UnhandledException event.
static void ThrowThreadException() { ThreadPool.QueueUserWorkItem(_ => { throw new ApplicationException("Exception thrown from within a separate Thread."); }); }
The TaskScheduler.UnobservedTaskException event is raised when an exception occurs within a Task and is not subsequently ‘observed’ before the task is disposed. If this event isn’t handled, or the UnobservedTaskExceptionEventArgs.SetObserved method isn’t called, the exception escalation policy is triggered which terminates the application by default.
static App() // Static Constructor { TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler; } static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs e) { e.SetObserved(); // Stop the exception from escalating. // Log the exception, save state, etc. }
The method below will trigger the UnobservedTaskException event. Garbage collection forces the unhandled exception to be thrown immediately for demonstration purposes.
static void ThrowTaskException() { Task.Factory.StartNew(() => { throw new ApplicationException("Exception thrown from within a Task."); }); Thread.Sleep(500); // Ample time for the task to execute. GC.Collect(); // Force the task to be garbage collected. }
The Application.DispatcherUnhandledException event is raised when an exception occurs within the UI thread but is not handled. If this event isn’t handled, or the DispatcherUnhandledExceptionEventArgs.Handled property isn’t set to true, the application is terminated.
protected override void OnStartup(StartupEventArgs e) { DispatcherUnhandledException += DispatcherUnhandledExceptionHandler; base.OnStartup(e); } static void DispatcherUnhandledExceptionHandler(object sender, DispatcherUnhandledExceptionEventArgs e) { e.Handled = true; // Stop the exception from escalating. // Log the exception, save state, etc. }
The method below will trigger the DispatcherUnhandledException event.
static void ThrowDispatcherException() { throw new ApplicationException("Exception thrown from within the UI thread."); }
Additional References
Design Guidelines for Exceptions
Handling and Throwing Exceptions