Save Big on Cyber Monday! Up to 40% Off
ends in   {{days}}
Days
{{timeFormat.hours}}
:
{{timeFormat.minutes}}
:
{{timeFormat.seconds}}

How to Connect a .NET MAUI Application to Dynamics 365 CRM

Integrating Dynamics 365 with a .NET MAUI application brings enterprise-grade CRM capabilities directly into your cross-platform app. Whether it is tracking sales, managing customer service, or automating marketing workflows, you can easily work with Dynamics 365 data in .NET MAUI. Besides, using dotConnect for Dynamics 365 simplifies the process and unlocks powerful, real-time interactions with your business data.

This tutorial will walk you through the steps to connect a .NET MAUI application to Dynamics 365 with the help of dotConnect for Dynamics 365.

Why dotConnect for Dynamics 365?

dotConnect for Dynamics 365 enables direct access to Dynamics 365 data via standard ADO.NET and Entity Framework Core interfaces. Key benefits of this approach include:

  • Direct connection to Dynamics 365 without low-level API codes
  • Support for secure OAuth 2.0 authentication
  • ORM compatibility for flexible development approaches
  • Flawless integration with Visual Studio and .NET MAUI

Prerequisites

What you will need for this tutorial:

  • Visual Studio: Our IDE of choice. If you do not have it on your machine, go to the official website to download and install it. We will be using the Community version, so you can get it as well.
  • dotConnect for Dynamics 365: A high-performance ADO.NET data provider with EF Core, NHibernate, and LinqConnect support.
  • Dynamics 365 Account: access to a Dynamics 365 environment with permission to register applications.

Download and Activate dotConnect for Dynamics 365

30-day free trial version

Download and install dotConnect for Dynamics 365 directly on your machine, or install the Devart.Data.Dynamics NuGet package. No license key is required, and you can start exploring the product immediately.

Full version

After purchasing the full version, go to your profile's Licenses page. Choose your product and click Details. Here, you'll find the license details and the Activation Key.

License details and the activation key

To activate a connection in your application, add the License Key to your connection string.

Create a project

  1. Open your Visual Studio and click Create a new MAUI project. Let us name our test project DynamicsMAUI.
  2. Right-click the project in the Solution Explorer and select Manage NuGet Packages.
  3. Search for the Devart.Data.Dynamics package. When found, install it.

Or, you can run the following command in the terminal:

dotnet add package Devart.Data.Dynamics

Check Dynamics 365 objects

To connect to Dynamics 365 using the built-in Data Explorer, right-click Data connections and choose Add connection.

Add Dynamics 365 Connection

Select Dynamics 365 as the data source, choose Web Login to get credentials, and click Test Connection.

Test Dynamics 365 Connection

If the test connection is successful, click OK.

Once connected, you can browse tables, execute queries, and manage data directly within the Data Explorer.

View Dynamics 365 Role Data

Create a connection

Here is the sample code that will help you connect to Dynamics 365. Complete it with the following credentials: Server, User ID, Password, and License key.

Create a configuration class

Create a new class named AppConfig to store your connection string and other configuration settings.

namespace DynamicsMAUI {
  public static class AppConfig {
    public static string ConnectionString {
      get;
    } =
    "Server=******;User ID=******;Password=******;License Key=**********;";
  }
}

Now, let us illustrate the READ, INSERT, and DELETE operations.

Read Dynamics 365 data

In the example below, you can see how to retrieve and display data from Dynamics 365.

Update MainPage.xaml.cs

Have a look at the code fragment from the MainPage.xaml.cs file. Update the file as shown below to enable it to display the connection status and use the new SQL query.

using System;
using System.Collections.Generic;
using Devart.Data.Dynamics;
using Microsoft.Maui.Controls;

namespace DynamicsMAUI {
  public partial class MainPage: ContentPage {
	public MainPage() {
  	InitializeComponent();
  	CheckConnectionAndFetchData();
	}

	private async void CheckConnectionAndFetchData() {
  	try {
    	using(var connection = new DynamicsConnection(AppConfig.ConnectionString)) {
      	await connection.OpenAsync();
      	ConnectionStatusLabel.Text = "Connection Status: Connected";
      	ConnectionStatusLabel.TextColor = Colors.Green;

      	string query = "SELECT roleid, name, businessunitid, overriddencreatedon FROM Role LIMIT 10";

      	using(var command = new DynamicsCommand(query, connection)) {
        	using(var reader = await command.ExecuteReaderAsync()) {
          	var roles = new List < Role > ();

          	while (await reader.ReadAsync()) {
            	roles.Add(new Role {
              	RoleId = reader["roleid"].ToString(),
                	Name = reader["name"].ToString(),
                	BusinessUnitId = reader["businessunitid"].ToString(),
                	OverriddenCreatedOn = reader["overriddencreatedon"].ToString()
            	});
          	}

          	RolesListView.ItemsSource = roles;
        	}
      	}
    	}
  	} catch (Exception ex) {
    	ConnectionStatusLabel.Text = $"Connection Status: Error - {ex.Message}";
    	ConnectionStatusLabel.TextColor = Colors.Red;
    	await DisplayAlert("Error", ex.Message, "OK");
  	}
	}
  }

  public class Role {
	public string RoleId {
  	get;
  	set;
	}
	public string Name {
  	get;
  	set;
	}
	public string BusinessUnitId {
  	get;
  	set;
	}
	public string OverriddenCreatedOn {
  	get;
  	set;
	}
  }
  • DynamicsConnection: This Devart.Data.Dynamics class is used to connect to Dynamics 365.
  • OpenAsync(): This method asynchronously opens the connection to the Dynamics 365 server.
  • DynamicsCommand: This class is used to execute SQL queries against the Dynamics 365 data source.
  • ExecuteReaderAsync(): This method asynchronously executes the SQL query and returns a data reader to read the results.
  • reader.ReadAsync(): This method asynchronously reads the next row of data from the data reader.
  • Role Class: This class is used to store the data fetched from the Role table. It has properties for Name, BusinessUnitId, and OverriddenCreatedOn.
  • RolesListView.ItemsSource: This property binds the list of roles to the ListView in the UI.
  • DisplayAlert: This method displays an alert dialog with an error message if an exception occurs.

Update MainPage.xaml

The MainPage.xaml file should be updated as shown in the example to include a Label for displaying the connection status.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
          xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
          x:Class="DynamicsMAUI.MainPage">

  <StackLayout>
    <Label x:Name="ConnectionStatusLabel" HorizontalOptions="Center" VerticalOptions="Center" FontSize="Medium" Margin="0,10,0,10"/>

    <ListView x:Name="RolesListView">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <Grid Padding="10">
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
              </Grid.ColumnDefinitions>
              <Label Grid.Column="0" Text="{Binding Name}" FontAttributes="Bold"/>
              <Label Grid.Column="1" Text="{Binding BusinessUnitId}"/>
              <Label Grid.Column="2" Text="{Binding OverriddenCreatedOn}"/>
            </Grid>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
  </StackLayout>

</ContentPage>
  • ListView: A control that displays a list of items, bound to the RolesListView.ItemsSource property in the code-behind.
  • ItemTemplate: Defines the layout for each individual item displayed in the ListView.
  • ViewCell: A container that holds the content for a single item in the ListView.
  • Grid: A layout control that organizes content into a table-like structure with three columns.
  • ColumnDefinition: Specifies the columns in a Grid. Each column has a width of *, meaning they share the available space equally.
  • Label: A control that displays text. The Grid.Column property sets the column position, and the Text property is bound to a corresponding property in the Role class.

MAUI App – Connected Roles List

Insert new data

Let us see how to insert new data into Dynamics 365 from the application.

Update MainPage.xaml.cs

At this stage, we insert a predefined set of test data on clicking the Submit button.

private async void OnSubmitRole(object sender, EventArgs e) {
  try {
  using(var connection = new DynamicsConnection(AppConfig.ConnectionString)) {
    await connection.OpenAsync();

    string query = "INSERT INTO role (name, businessunitid, overriddencreatedon, importsequencenumber, isinherited, isautoassigned, description, summaryofcoretablepermissions, appliesto) " +
      "VALUES (:name, :businessunitid, NULL, NULL, :isinherited, :isautoassigned, :description, :summaryofcoretablepermissions, :appliesto)";

    using(var command = new DynamicsCommand(query, connection)) {
      // Predefined test data
      command.Parameters.AddWithValue("name", "13");
      command.Parameters.AddWithValue("businessunitid", "{You business unit ID}");
      command.Parameters.AddWithValue("isinherited", "Only the rights of the working group");
      command.Parameters.AddWithValue("isautoassigned", "No");
      command.Parameters.AddWithValue("description", "1");
      command.Parameters.AddWithValue("summaryofcoretablepermissions", "1");
      command.Parameters.AddWithValue("appliesto", "1");

      int rowsAffected = await command.ExecuteNonQueryAsync();

      await DisplayAlert("Success", $"Role added successfully! Rows affected: {rowsAffected}", "OK");
    }
  }
  } catch (Exception ex) {
  await DisplayAlert("Error", ex.Message, "OK");
  }
}

The fields in the SQL INSERT statement follow the standard structure of a Dynamics 365 Role entity. Each field plays a specific role in defining the entity's purpose and function within the system.

Update MainPage.xaml

Add a button to your MainPage.xaml to trigger the insertion of a new role:

<Button Text="Add New Role" Clicked="OnSubmitRole" Margin="0,10,0,0"/>

Let's test it.

MAUI App – Connected Roles List with Add New Role Button

Click Add New Role.

MAUI App – Role Added Success Dialog

Delete records

To add a method for removing a record and include a red Delete button in each row of the ListView, do the following:

Update MainPage.xaml.cs

Let us add a method to handle the deletion of a role:

private async void OnDeleteRole(object sender, EventArgs e) {
  var button = (Button) sender;
  var role = (Role) button.BindingContext;

  try {
  using(var connection = new DynamicsConnection(AppConfig.ConnectionString)) {
    await connection.OpenAsync();

    string query = "DELETE FROM role WHERE roleid = :roleid";

    using(var command = new DynamicsCommand(query, connection)) {
      command.Parameters.AddWithValue("roleid", role.RoleId);

      int rowsAffected = await command.ExecuteNonQueryAsync();

      await DisplayAlert("Success", $"Role '{role.Name}' removed successfully! Rows affected: {rowsAffected}", "OK");
    }
  }
  } catch (Exception ex) {
  if (ex.Message.Contains("iscomponentdeletionenabled")) {
    await DisplayAlert("Error", "Deletion is not enabled for this component. Please check the managed properties.", "OK");
  } else {
    await DisplayAlert("Error", ex.Message, "OK");
  }
  }
}

The OnDeleteRole method retrieves the RoleID from the BindingContext and executes a SQL query to delete the specified role.

Update MainPage.xaml

Add a method to handle the deletion of a role:

<ListView x:Name="RolesListView">
  <ListView.ItemTemplate>
    <DataTemplate>
      <ViewCell>
        <Grid Padding="10">
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
          </Grid.ColumnDefinitions>
          <Label Grid.Column="0" Text="{Binding Name}" FontAttributes="Bold"/>
          <Label Grid.Column="1" Text="{Binding BusinessUnitId}"/>
          <Label Grid.Column="2" Text="{Binding OverriddenCreatedOn}"/>
          <Button Grid.Column="3" Text="Delete" Clicked="OnDeleteRole" BindingContext="{Binding .}" BackgroundColor="Red"/>
        </Grid>
      </ViewCell>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

It adds a button control to the grid within the DataTemplate for each record. The clicked event gets bound to the OnDeleteRole method. The BindingContext of the button is set to the current item in the ListView, enabling the OnDeleteRole method to access the corresponding role's details.

Let's run our application.

MAUI – Connected Roles List and Delete Functionality

We can delete the role successfully.

MAUI App – Role Deletion Success Dialog

Conclusion

We have successfully connected a .NET MAUI application to Dynamics 365 with the help of dotConnect for Dynamics 365. This integration allows us to access the data directly and perform CRUD operations for enterprise CRMs directly from the application. You can try it yourself with a fully functional 30-day free trial and see how it can improve your work.

dotConnect for Dynamics 365

Get an enhanced ORM-enabled data provider for Dynamics 365 and develop .NET applications working with Dynamics 365 data quickly and easily!

Discover the ultimate capabilities of dotConnect for Dynamics 365 Download free trial