Share via


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 the RegisterSingleton 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.