Migrating From VpnSDK v1 to v2
Introduction
Migrating a codebase using the original VpnSDK release requires updating from the original reactive/observable flow to the standard asynchronous and event patterns found in modern day C#. While reactive code can provide developers with the ability to manage more complex codebases, the new task/event-based model in v2 allows for faster iteration by any C# developer without having to know the in's and out's of reactive programming.
[!WARNING]
<Customers who have used a branded version of ConsumerVPN with v1 are suggested to follow our branding guide and use ConsumerVPN v2 as a fresh base.>While this guide is not aimed at how to adapt v2 in to a similar interface found in v1, using System.Reactive, developers more comfortable with the reactive programming model can convert the tasks and events in v2 to observable processes.
Make sure to read the quick start guide first as it will help show the simplification of the API in v2. The most significant changes that will affect your codebase can be found by comparing the v1 quick start guide to the v2 version.
Constructing the SDK Instance
[!TIP]
<Most namespaces have up from VpnSDK.Public to the root namespace of VpnSDK. Review the API documentation for specifics.>Constructing an instance of the SDK is similar to v1 which uses a builder pattern. SDKBuilder
now requires providing the type ISDK
as a generic to assist in versioning the main SDK interface. This is as simple as changing new SDKBuilder()
to new SDKBuilder<ISDK>()
. For applications using IKEv2, RasConfiguration
remains the same and for applications using OpenVPN, extraneous diagnostic log file related properties have been removed as all diagnostic logs are now handled through using LibLog to automatically supply log entries to any standard .NET logging framework.
Compare the differences between building an SDK instance in ConsumerVPN v1 and v2.
// VpnSDK v1
new SDKBuilder()
.SetApiKey(Helpers.Resource.Get<string>("API_KEY"))
.SetApplicationName(Helpers.Resource.Get<string>("BRAND_NAME"))
.SetAuthenticationToken(Helpers.Resource.Get<string>("AUTHORIZATION_TOKEN"))
.SetLogFilesPath(logFilesPath)
.SetServerListCache(TimeSpan.FromDays(1))
.SetOpenVpnConfiguration(new OpenVpnConfiguration
{
OpenVpnCertificateFileName = "ca.crt",
OpenVpnDirectory = "OpenVPN",
OpenVpnExecutableFileName = "openvpn.exe",
OpenVpnConfigDirectory = "OpenVPN",
OpenVpnConfigFileName = "config.ovpn",
OpenVpnLogFileName = "openvpn.log",
TapDeviceDescription = "TAP-Windows Adapter V9",
TapDeviceName = "tap0901"
})
.SetRasConfiguration(new RasConfiguration
{
RasDeviceDescription = Resource.Get<string>("BRAND_NAME")
})
.Create();
// VpnSDK v2
new SDKBuilder<ISDK>()
.SetApiKey(Resource.Get<string>("ApiKey"))
.SetAuthenticationToken(Resource.Get<string>("AuthenticationToken"))
.SetApplicationName(Resource.Get<string>("ApplicationName"))
.SetAutomaticRefreshTokenHandling(true)
.SetServerListCache(TimeSpan.FromDays(1))
.Create();
VpnSDK v2 has sane defaults in construction and no longer requires as much specification.
ISDK
ISDK operations are no longer subscribed to but rather invoked and awaited on. For cases where a task doesn't apply, like an external case of a user being logged out, there are standard C# events that can be subscribed to at any time. All events will be invoked on the same thread that the SDK is created on by default as to provide UI safe events without requiring extra effort from the developer to marshal events between threads.
The interface of the main SDK instance has changed significantly as a result and the API reference for the class should be directly reviewed here. For any functionality not covered below, the API reference will have an equivalent event and task using similar patterns as demonstrated.
Authentication
All authentication and data loading now occurs within the Login(username, password)
task. When user authentication fails, an appropriate exception will be fired for the cause of error and this should be expected of all async calls within the SDK.
The AuthenticationStatusChanged
event can be subscribed to at any time to monitor whether the user has logged in or not and the AuthenticationCredentialsExpired
event provides notification on when a users credentials have expired. If you are currently using a callback method in v1 for the login subscription, your exception catch clause for Login
and the previous two mentioned events will serve as replacements.
Locations (Regions)
The RegionsList
collection has now been renamed to Locations
and changed to a ReadOnlyObservableCollectionWhenLocationListChanged
can be replaced with the Locations.CollectionChanged
event.
Unlike v1, Locations
is automatically populated on login regardless of any subscriptions, so boilerplate code to observe WhenLocationListChanged
can be removed.
VPN Connectivity
The Connect
and Disconnect
methods still require the same signatures as before but are now tasks. Just like authentication, when either of these operations fail an exception will fire on the awaiter. Upon awaiting both of these methods it's safe to assume the VPN is connected/disconnected.
VpnConnectionStatusChanged
should be subscribed to make sure that in cases where the VPN tunnel is severed or connecting, the UI is updated without having to share the task's status throughout your UI code. This event should call what was once the .Subscribe
callback of .Connect
in v1.
Diagnostic Logs
Logging has changed from being automatically written to a file by the SDK to instead using LibLog to provide logs throughout the SDK to most logging frameworks under the VpnSDK::*
namespace. While we suggest using Serilog in your application, most are supported by default. To keep VpnSDK logs separated, use the appropriate namespace filtering option in your logging framework to make anything that starts with VpnSDK::
write to a different file.
Conclusion
Migrating from the v1 SDK to v2 will require moving away from the existing observable pattern found through v1 and instead use standard async patterns. To speed up your migration, you should ensure to review and compare the v1 and v2 documentation, especially the API reference. All of the example code repositories provide both v1 and v2 branches that serve as an easy way to compare the differences between the two versions and find equivalent code examples rapidly.