Xamarin.Forms DependencyService Registration and Resolution
When using the Xamarin.Forms DependencyService
to invoke native platform functionality, platform implementations must be registered with the DependencyService
, and then resolved from shared code to invoke them.
Register platform implementations
Platform implementations must be registered with the DependencyService
so that Xamarin.Forms can locate them at runtime.
Registration can be performed with the DependencyAttribute
, or with the Register
and RegisterSingleton
methods.
Important
Release builds of UWP projects that use .NET native compilation should register platform implementations with the Register
methods.
Registration by attribute
The DependencyAttribute
can be used to register a platform implementation with the DependencyService
. The attribute indicates that the specified type provides a concrete implementation of the interface.
The following example uses the DependencyAttribute
to register the iOS implementation of the IDeviceOrientationService
interface:
using Xamarin.Forms;
[assembly: Dependency(typeof(DeviceOrientationService))]
namespace DependencyServiceDemos.iOS
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
...
}
}
}
In this example, the DependencyAttribute
registers the DeviceOrientationService
with the DependencyService
. This results in the concrete type being registered against the interface it implements.
Similarly, the implementations of the IDeviceOrientationService
interface on other platforms should be registered with the DependencyAttribute
.
Note
Registration with the DependencyAttribute
is performed at the namespace level.
Registration by method
The DependencyService.Register
methods, and the RegisterSingleton
method, can be used to register a platform implementation with the DependencyService
.
The following example uses the Register
method to register the iOS implementation of the IDeviceOrientationService
interface:
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
DependencyService.Register<IDeviceOrientationService, DeviceOrientationService>();
return base.FinishedLaunching(app, options);
}
}
In this example, the Register
method registers the concrete type, DeviceOrientationService
, against the IDeviceOrientationService
interface. Alternatively, an overload of the Register
method can be used to register a platform implementation with the DependencyService
:
DependencyService.Register<DeviceOrientationService>();
In this example, the Register
method registers the DeviceOrientationService
with the DependencyService
. This results in the concrete type being registered against the interface it implements.
Alternatively, an existing object instance can be registered as a singleton with the RegisterSingleton
method:
var service = new DeviceOrientationService();
DependencyService.RegisterSingleton<IDeviceOrientationService>(service);
In this example, the RegisterSingleton
method registers the DeviceOrientationService
object instance against the IDeviceOrientationService
interface, as a singleton.
Similarly, the implementations of the IDeviceOrientationService
interface on other platforms can be registered with the Register
methods, or the RegisterSingleton
method.
Important
Registration with the Register
and RegisterSingleton
methods must be performed in platform projects, before the functionality provided by the platform implementation is invoked from shared code.
Resolve the platform implementations
Platform implementations must be resolved before being invoked. This is typically performed in shared code using the DependencyService.Get<T>
method. However, it can also be accomplished with the DependencyService.Resolve<T>
method.
By default, the DependencyService
will only resolve platform implementations that have parameterless constructors. However, a dependency resolution method can be injected into Xamarin.Forms that uses a dependency injection container or factory methods to resolve platform implementations. This approach can be used to resolve platform implementations that have constructors with parameters. For more information, see Dependency resolution in Xamarin.Forms.
Important
Invoking a platform implementation that hasn't been registered with the DependencyService
will result in a NullReferenceException
being thrown.
Resolve using the Get<T> method
The Get<T>
method retrieves the platform implementation of interface T
at runtime, and either:
- Creates an instance of it as a singleton.
- Returns an existing instance as a singleton, that was registered with the
DependencyService
by theRegisterSingleton
method.
In both cases, the instance will live for the lifetime of the application, and any subsequent calls to resolve the same platform implementation will retrieve the same instance.
The following code shows an example of calling the Get<T>
method to resolve the IDeviceOrientationService
interface, and then invoking its GetOrientation
method:
IDeviceOrientationService service = DependencyService.Get<IDeviceOrientationService>();
DeviceOrientation orientation = service.GetOrientation();
Alternatively, this code can be condensed into a single line:
DeviceOrientation orientation = DependencyService.Get<IDeviceOrientationService>().GetOrientation();
Note
The Get<T>
method returns an instance of the platform implementation of interface T
as a singleton, by default. However, this behavior can be changed. For more information, see Manage the lifetime of resolved objects.
Resolve using the Resolve<T> method
The Resolve<T>
method retrieves the platform implementation of interface T
at runtime, using a dependency resolution method that's been injected into Xamarin.Forms with the DependencyResolver
class. If a dependency resolution method hasn't been injected into Xamarin.Forms, the Resolve<T>
method will fallback to calling the Get<T>
method to retrieve the platform implementation. For more information about injecting a dependency resolution method into Xamarin.Forms, see Dependency resolution in Xamarin.Forms.
The following code shows an example of calling the Resolve<T>
method to resolve the IDeviceOrientationService
interface, and then invoking its GetOrientation
method:
IDeviceOrientationService service = DependencyService.Resolve<IDeviceOrientationService>();
DeviceOrientation orientation = service.GetOrientation();
Alternatively, this code can be condensed into a single line:
DeviceOrientation orientation = DependencyService.Resolve<IDeviceOrientationService>().GetOrientation();
Note
When the Resolve<T>
method falls back to calling the Get<T>
method, it returns an instance of the platform implementation of interface T
as a singleton, by default. However, this behavior can be changed. For more information, see Manage the lifetime of resolved objects.
Manage the lifetime of resolved objects
The default behavior of the DependencyService
class is to resolve platform implementations as singletons. Therefore, platform implementations will live for the lifetime of an application.
This behavior is specified with the DependencyFetchTarget
optional argument on the Get<T>
and Resolve<T>
methods. The DependencyFetchTarget
enumeration defines two members:
GlobalInstance
, which returns the platform implementation as a singleton.NewInstance
, which returns a new instance of the platform implementation. The application is then responsible for managing the lifetime of the platform implementation instance.
The Get<T>
and Resolve<T>
methods both set their optional arguments to DependencyFetchTarget.GlobalInstance
, and so platform implementations are always resolved as singletons. This behavior can be changed, so that new instances of platform implementations are created, by specifying DependencyFetchTarget.NewInstance
as arguments to the Get<T>
and Resolve<T>
methods:
ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);
In this example, the DependencyService
creates a new instance of the platform implementation for the ITextToSpeechService
interface. Any subsequent calls to resolve the ITextToSpeechService
will also create new instances.
The consequence of always creating a new instance of a platform implementation is that the application becomes responsible for managing the instances' lifetime. This means that if you subscribe to an event defined in a platform implementation, you should unsubscribe from the event when the platform implementation is no longer required. In addition, it means that it may be necessary for platform implementations to implement IDisposable
, and cleanup their resources in Dispose
methods. The sample application demonstrates this scenario in its TextToSpeechService
platform implementations.
When an application finishes using a platform implementation that implements IDisposable
, it should call the object's Dispose
implementation. One way of accomplishing this is with a using
statement:
ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);
using (service as IDisposable)
{
await service.SpeakAsync("Hello world");
}
In this example, after the SpeakAsync
method is invoked, the using
statement automatically disposes of the platform implementation object. This results in the object's Dispose
method being invoked, which performs the required cleanup.
For more information about calling an object's Dispose
method, see Using objects that implement IDisposable.