Replacing Xamarin DependencyService with Xamarin.Essentials: A Connectivity Example
Custom DependencyService implementations for device capabilities add maintenance overhead. Xamarin.Essentials offers a unified API, but teams must weigh abstraction trade-offs and independent versioning.
25 Dec 2025, 09:57 UTC

The DependencyService tax
Every Xamarin.Forms developer eventually writes the same code: an interface in shared code, two platform implementations, and a DependencyService attribute. For simple capabilities like network state, this boilerplate adds files to review and platform bugs to fix twice.
The interface itself is small, but the cost grows when you need to wire async methods, handle platform quirks, or onboard a new developer to your custom abstraction.
What Xamarin.Essentials actually replaces
Xamarin.Essentials bundles more than 50 cross-platform APIs for device capabilities—geolocation, secure storage, connectivity, and more—into a single NuGet package. For many projects, it removes the need to build and maintain custom DependencyService interfaces for common features.
It does not replace every platform API. Complex or less common features still require custom renderers or dependency services. But for standard capabilities, the unified async API is often faster to adopt than maintaining parallel implementations.
Worked example: connectivity monitoring
A common custom pattern defines an IConnectivity interface with IsConnected and a ConnectivityChanged event. Each platform project implements it, and the shared code calls DependencyService.Get<IConnectivity>(). With Essentials, you use Connectivity.Current directly.
Initialization
Essentials requires initialization in each platform project. In Android, call Xamarin.Essentials.Platform.Init() inside MainActivity.OnCreate after base.OnCreate(). In iOS, call Xamarin.Essentials.Platform.Init() inside AppDelegate.FinishedLaunching after LoadApplication(new App()).
// Android: MainActivity.cs
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
LoadApplication(new App());
}
In the shared Forms code, subscribe to the event and read the current access level:
// Shared code project
using Xamarin.Essentials;
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
Connectivity.ConnectivityChanged += OnConnectivityChanged;
}
private void OnConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
{
var access = e.NetworkAccess;
bool isOnline = access == NetworkAccess.Internet;
// Update UI or retry logic here
}
protected override void OnDisappearing()
{
base.OnDisappearing();
Connectivity.ConnectivityChanged -= OnConnectivityChanged;
}
}
The NetworkAccess property reports states such as Internet, Local, None, or Unknown. The ConnectivityChanged event fires when the access level changes. Unlike a custom service, there is no registration step and no per-platform project to inspect for this feature.
Platform behavior to verify
Test event behavior on Android and iOS simulators. Toggle airplane mode or Wi-Fi to observe transitions. On Android, verify that the event fires when the app returns from background after a connectivity change; on iOS, confirm behavior during background fetch or when suspended. Essentials abstracts the platform APIs, but the underlying OS still applies its own lifecycle rules.
Trade-offs: abstraction and versioning
The unified API hides platform-specific constraints. Android Doze mode and iOS background execution limits still affect when events fire, but the abstraction does not surface those constraints in the API signature. You must test on real devices or simulators to confirm timing and reliability.
Xamarin.Essentials is versioned independently from Xamarin.Forms. A project may reference Forms 5.x and Essentials 1.7.x, for example. After any NuGet upgrade, verify compatibility across shared and platform projects, then run connectivity and permission-dependent features on each target. Missing runtime permissions for other Essentials APIs—such as location or camera—can cause silent failures or exceptions, so review the documentation for your specific package version.
When to keep custom services
Essentials does not cover every platform API. If your app needs a vendor SDK, a proprietary hardware feature, or a platform capability not exposed by Essentials, a custom DependencyService or renderer is still appropriate. The goal is to reduce boilerplate for standard capabilities, not to force every abstraction into one library.
Actionable checklist
- Confirm Xamarin.Essentials is referenced in the shared project and each platform project.
- Initialize Essentials in Android
MainActivity.OnCreateand iOSAppDelegate.FinishedLaunching. - Replace
IConnectivityimplementations withConnectivity.Current.NetworkAccessandConnectivity.ConnectivityChanged. - Unsubscribe from events in
OnDisappearingorDisposeto avoid leaks. - Test connectivity changes on Android and iOS simulators or devices.
- Review the official Xamarin.Essentials documentation for your installed version to confirm permission and platform requirements.
Xamarin is in maintenance mode, so new projects should evaluate .NET MAUI. Many Essentials concepts map directly to MAUI, but the package names and initialization patterns differ. For existing Xamarin.Forms apps, Essentials remains a practical way to retire custom DependencyService code for common device capabilities.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.