A Xamarin Native Sample with MvvmCross for the Microsoft Graph
Hem NyheterTech News A Xamarin Native Sample with MvvmCross for the Microsoft Graph

A Xamarin Native Sample with MvvmCross for the Microsoft Graph

Publicerat av: Redaktionen

There is a great way to call a massive amount of Microsoft APIs – using one single endpoint.

This endpoint, so called the Microsoft Graph (https://graph.microsoft.io/) lets you access everything from data, to intelligence and insights powered by the Microsoft Cloud. This post is about the recently released Property Manager code sample, that takes a complete dependency on the Microsoft Graph as its sole and only backend.

The intention of this post is to break down the code sample and give you an overview of a few important topics that went into building this native and cross-platform experience, while sharing common code and great user experiences. This is achieved through the use of Xamarin Native, MvvmCross and a few other techniques and patterns that I will cover in this post. You can find and clone the sample itself here: https://github.com/microsoftgraph/xamarin-csharp-propertymanager-sample

Getting started with the sample is easy, simply get it and dig into the Constants and update them with your own values of your registered application. If you want to know how to go on about doing this, view the README file of the GitHub repository.PM_OSes-1024x642

Building great experiences with Xamarin Native

Xamarin is a solution that you can leverage to build native cross-platform experiences using your .NET tools and knowledge. It comes in a couple of flavors; Xamarin Native and Xamarin Forms. The short explanation of these two offerings is that Xamarin Forms lets you create user interfaces and share it across platforms – whereas Xamarin Native lets you take care of the user interfaces for each platform individually. The code sample uses Xamarin Native to gain full control over the user experiences and leverage the tools used by “regular” platform developers (such as Layouts for Android, Storyboards for iOS and XAML for UWP). You can still mix and match both native user interfaces and Xamarin Forms, but that’s outside the scope of this blog post and the code sample.

Using Xamarin Native, we were able to achieve user experiences that felt like they belonged to the platform – which for many application developers is a crucial and important aspect.

You can read more and get started with Xamarin here: https://www.xamarin.com/

Achieving a common core with MvvmCross

When using Xamarin Native, you can take advantage of this brilliant library called MvvmCross (https://mvvmcross.com/docs). This library allows you to separate your core logic into a core project, while keeping the platform specific code in individual platform projects – using the MVVM pattern. The MVVM pattern is well know and used in the code sample, but it will not be covered in this blog post, read more about it here: https://msdn.microsoft.com/en-us/library/hh848246.aspx

This pattern is great for maintainability of the project, as you can develop your core business logic once – and have it “mapped” with the individual platform experienced. In addition, you can apply fixes and updates to the core project and enjoy the benefit across all of the platforms immediately (unless it requires user interface adjustments that is).

If you’re familiar with the concept of bindings, the following should make sense for you. Consider the LoginViewModel (located in the core project, https://github.com/microsoftgraph/xamarin-csharp-propertymanager-sample/blob/master/XamarinNativePropertyManager/ViewModels/LoginViewModel.cs#L25), containing a command named LoginCommand. This hosts the trigger for logic that takes care of signing the user into the application.

public class LoginViewModel : BaseV { private readonly IGraphService _graphService; private readonly IConfigService _configService; public ICommand LoginCommand => new MvxCommand(LoginAsync);

Now each individual platform project will implement a button that binds its click event to this command, firing the logic:

Android (LoginActivity.axml)

local:MvxBind="Click LoginCommand;"

iOS (LoginView.cs)

set.Bind(SignInButton).To(vm => vm.LoginCommand);

UWP (LoginView.xaml)

Command="{Binding LoginCommand}"

As you’ll see, the pattern is similar, yet flavored by the platform. If anything, you will probably see the point of this. I now kept the logic for what’s going to happen when a user clicks on the login button in a single place, allowing me to alter the experience for each platform with a single code base.

This is how everything in the application is structured to achieve a common core. With everything from button clicks to item lists.

PM_Android   PM_iOS  


Dealing with Services using MvvmCross

There is usually a large piece of logic that goes into applications, called services. These will provide the functionality to do everything from network calls, picking files, to taking photos and much more. These can sometimes be implemented entirely within the core project, but sometimes they rely on platform specific features  that aren’t accessible within the core project. This forces you to place the implementation in the individual platform projects, so how do you construct a common core with this challenge in mind?

The way it’s achieved is through a concept known as Inversion of Control (https://en.wikipedia.org/wiki/Inversion_of_control). To cut straight to the point, this means that we will be implementing interfaces and working with those in the core project. MvvmCross provides the functionality to “magically” supply the implementation of those interfaces during runtime. It doesn’t matter if the service implementation is made entirely within the core project (such as the HttpService and GraphService in the code sample) or in the platform projects. MvvmCross will take care of feeding the implementations (usually though class constructors, such as in the view models) for you.

Consider the GroupViewModel class. You’ll find that it needs to be instantiated with a couple of services, some of which are implemented in the core and some of which are implemented on a platform basis. Notice that only interfaces of the services are supplied.

public GroupViewModel(IGraphService graphService, IConfigService configService, ILauncherService launcherService, IFilePickerService filePickerService) { _graphService = graphService; _configService = configService; _launcherService = launcherService; _filePickerService = filePickerService; Files = new ObservableCollection<FileModel>(); Conversations = new ObservableCollection<ConversationModel>(); Tasks = new ObservableCollection<TaskModel>(); }

MvvmCross will instantiate the view model with the implementations as long as it has been told where to find them. This can be done in various of clever ways, but in the code sample it is done fairly simple. For the services implemented in the core project, in the App class:

public class App : MvxApplication { public override void Initialize() { Mvx.LazyConstructAndRegisterSingleton<IHttpService, HttpService>(); Mvx.LazyConstructAndRegisterSingleton<IConfigService, ConfigService>(); Mvx.LazyConstructAndRegisterSingleton<IGraphService, GraphService>(); RegisterAppStart<ViewModels.LoginViewModel>(); } }

And for the platform implementations of the services, in each individual platform Setup class. This one is for the iOS project (they all resemble each other):

protected override IMvxApplication CreateApp() { // Register platform services. Mvx.RegisterSingleton(typeof(IAuthenticationService), new AuthenticationService()); Mvx.RegisterSingleton(typeof(ILauncherService), new LauncherService()); Mvx.RegisterSingleton(typeof(IFilePickerService), new FilePickerService()); Mvx.RegisterSingleton(typeof(IDialogService), new DialogService()); return new App(); }

Using the Microsoft Graph without an SDK

Have a look at the GraphService. This is the service that deals with the Microsoft Graph calls (by leveraging the HttpService). You might be aware that the Microsoft Graph has a bunch of SDKs available, but the code sample is making primitive network calls. This is because the code sample heavily relies on the beta branch of the Microsoft Graph. This branch contains a lot of the new features that are currently being tested and worked out. While this does mean that the code sample is subject to changes as the beta branch is updated, it also means that we are able to leverage all of the new and exciting operations of the Microsoft Graph (before they are available in the production ready v1.0 branch).

If you find yourself with everything you need in the v1.0 branch of the Microsoft Graph (http://graph.microsoft.io/en-us/docs/) – I would encourage you to leverage the Microsoft Graph SDKs (http://graph.microsoft.io/en-us/code-samples-and-sdks) in your own solutions. This allows you to get going faster, but it also minimizes a lot of room for error that comes along when making the network calls on your own.

The code sample does however leverage ADAL (Active Directory Authentication Library), which takes care of presenting the authentication experience on each platform (and making necessary network calls and providing caching features). Its functionality is exposed through the IAuthenticationService, which delivers the results (objects from ADAL) and performs the ADAL logic within the platform implementations. They are all very similar. You can learn more about getting started with the Microsoft Graph and ADAL here: http://simonjaeger.com/understand-the-microsoft-graph-with-a-console-app/

Sharing is caring – contribute!

If you find yourself with a bug fix or an improvement – please do share it! If you can’t implement it on your own, create an issue within the GitHub repository and it will be looked at. If you can, go ahead and create your implementation and submit a pull request. It will only make the code sample even better! Thanks!


-Simon Jaeger

Relaterade Artiklar

Vi använder cookies och andra identifierare för att förbättra din upplevelse. Detta gör att vi kan säkerställa din åtkomst, analysera ditt besök på vår webbplats. Det hjälper oss att erbjuda dig ett personligt anpassat innehåll och smidig åtkomst till användbar information. Klicka på ”Jag godkänner” för att acceptera vår användning av cookies och andra identifierare eller klicka ”Mer information” för att justera dina val. Jag Godkänner Mer Information>>