Whether you are an experienced .NET developer or exploring the power of .NET MAUI for the first time, this guide aims to equip you with the knowledge and tools to successfully design your projects, and development that lays a solid foundation for successful cross-platform internal requests.

This tutorial is a step-by-step walkthrough that guides developers through the process of configuring these essential components in a .NET MAUI project. From defining platform-specific services to using IoC containers to manage dependencies, from creating ViewModels to creating Content Pages, every aspect will be explored in depth

By the end of this course, developers will have a detailed understanding of how to optimize their .NET MAUI projects, ensuring scalability, maintainability, and optimal performance If you are an experienced developer looking to dive into the intricacies of .NET MAUI or a newcomer eager to explore the possibilities of cross-platform development Or, this guide will give you the knowledge and skills needed to build compelling native applications with ease.

Maui Program Setup

using Microsoft.Extensions.Logging;
using Microsoft.Maui.Controls.Hosting;
using Microsoft.Maui.Hosting;
namespace BingoMania;
public static class MauiProgram
{
//1. Passing MauiAppBuilder builder as an argument to be supplied from Platform Specific Project so that
// We can register Platform Specific Services to our IOC container
public static MauiApp CreateMauiApp(MauiAppBuilder builder)
{
builder
.UseMauiApp<App>()
.RegisterServices() //2. Extension to Register Shared Services
.RegisterViewModels() //3. Extension to Register all ViewModels
.RegisterViews() //4. Extension to Register all Views/Pages
.RegisterStartupSequenceItems() //5. Extension to register our application Startup Process
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}
view raw MauiProgram.cs hosted with ❤ by GitHub

Important Setup in this class:

  • CreateMauiApp to take the MauiAppBuilder from Platform Specific projects
  • Creating an Extension to separate all the registrations into a separate file

IocRegistrationExtensions.cs

We will use this class to register all of our Shared Dependencies including Pages, ViewModels, Services, and Application Startup-related services. When the project grows more and in the future we might have to manage dependencies scoped to certain features or modules, then we can create them separately so this file will contain only global service registrations.

using BingoMania.Features.Database;
using BingoMania.Features.Startup;
using BingoMania.Framework.Navigation;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Hosting;
namespace BingoMania
{
internal static class IocRegistrationExtensions
{
public static MauiAppBuilder RegisterViews(this MauiAppBuilder builder)
{
builder.Services.AddTransient<StartupPage>();
return builder;
}
public static MauiAppBuilder RegisterViewModels(this MauiAppBuilder builder)
{
builder.Services.AddTransient<StartupPageViewModel>();
return builder;
}
public static MauiAppBuilder RegisterServices(this MauiAppBuilder builder)
{
builder.Services.AddSingleton<INavigation, NavigationService>();
builder.Services.AddTransient<IStartupSequencer, StartupSequencer>();
return builder;
}
public static MauiAppBuilder RegisterStartupSequenceItems(this MauiAppBuilder builder)
{
builder.Services.AddTransient<IStartupSequencer, StartupSequencer>();
return builder;
}
public static MauiAppBuilder RegisterAppDb(this MauiAppBuilder builder)
{
builder.Services.AddTransient<IBingoManiaDb, BingoManiaDb>();
return builder;
}
}
}

Setting up platform-specific

I would like to set the platform-specific concerns to go through the process of Bootstrapping the Platform-specific processes, dependency registration etc. At a high level this is how my basic setup looks like:

Bootstrap.cs

I have added Bootstrap.cs to each of my platform-specific projects because each of them will have their implementations of the Bootstrap process.

Example: EnvironmentContext is to expose the Application Environment Configurations like Database Path, Database Name, etc. In Android, we may want to access the Android Specific folder and so for iOS, we may want to read those from the pList File.
In this class, we may want to do other service registration too like File Upload Service, GPS/geolocation-related Services – anything that is related to platform-specific.

The same class can be used to register the Loggers, Application Crash Analytics, Push Notifications, etc if any depending on the application features.

I hope you got the idea!

This is what my EnvironmentContext looks like:

using BingoMania.Features.Environment;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BingoMania.Platforms.iOS
{
public sealed class EnvironmentContext : IEnvironmentContext
{
public Features.Environment.Environment Environment => Features.Environment.Environment.DEV; //Read Environment From PList!
public string DbPath => Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), Constants.DataStore);
}
}
using BingoMania.Features.Environment;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BingoMania.Platforms.Android
{
public sealed class EnvironmentContext : IEnvironmentContext
{
public Features.Environment.Environment Environment => Features.Environment.Environment.DEV; //Read Environment From Manifest!
public string DbPath => Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), Constants.DataStore);
}
}

App.cs

After setting up all of the dependencies, the next item is to set up the App.cs. In this class, we set up the default page that will appear right after the Splash. I like to use this page as the entry point for our application where we want to check or bootstrap the actual business logic processes.

I would like to call this page a Startup Page, when this page appears in the application, this will run the Application Startup Sequence! So that It can handle concerns like:

  • Do we have a user logged in? If not, let’s show the Login Prompt
  • Is the Database created? If not, let’s initialize them
  • Do we have to show the application walkthrough?
  • Do we want to start any process like downloading the configuration from API etc

These are a few examples, this list can become huge based on what our application does. I hope you got the idea here i.e we want to handle all these kinda conerns while this page goes.

When application goes through Startup Process and if everything completed, we will display the Home Page that could be using Shell or any type of Home page.

MVVM Setup

I hope you understand the basic concept of MVVM, since this tutorial is not focused about MVVM I’m not going to describe what it is – however it is most important part of the Application Architecture. So I’m sharing how I would like to setup this.

When I’m setting up the MVVM pattern, I would like to solve at minimum below concern:

  • Dependency Injection – I want my ViewModels and Views to be injected by the IOC container, which in our case we already have setup that in the separate Extensions.
  • All the ViewModel dependencies should be injected as well.
  • Having both two concerns to be injectable will enable us Unit test our Page, and ViewModels etc separately.
  • Memory Management – This is very critical for any application. We want our Pattern to expose the way for parts of our application to be able to Dispose the resources like Subscriptions, Events, or any other unmanaged resources. Remember we have to use the IOC registration Scope (Singleton, Transient, Scoped) to manage the Services resource disposal. When we set up those things correctly, as soon as our ViewModel gets disposed of, they will be disposed of as well. And when our ViewModel gets disposed of – we want to dispose of all the ViewModel-related resources, in my example, I have added the CompositeDisposable to handle that and called that Trashbin 🙂
See it in action:
using BingoMania.Framework.Views;
using Dawn;
using Microsoft.Maui.Controls;
using ReactiveUI;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace BingoMania.Features.Startup
{
public sealed class StartupPageViewModel : ViewModelBase
{
public IReactiveCommand StartCommand { get; }
public StartupPageViewModel(IStartupSequencer startupSequencer, INavigation navigation)
: base(navigation)
{
_startupSequencer = Guard.Argument(startupSequencer, nameof(startupSequencer))
.NotNull()
.Value;
//Disable the Button once it is started!
var canStart = _startupSequencer.IsInProgress
.StartWith(false)
.Select(x => !x);
StartCommand = ReactiveCommand.CreateFromTask(ExecuteStartCommand, canStart)
.DisposeWith(TrashBin); //Dispose the Command when ViewModel will be disposed!
}
private async Task ExecuteStartCommand()
{
var result = await _startupSequencer.Run();
if (result)
{
//Continue to load Home Page!
}
else
{
//Show the Error or whatever
}
}
private readonly IStartupSequencer _startupSequencer;
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<view:ContentPageBase
x:Class="BingoMania.Features.Startup.StartupPage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://schemas.microsoft.com/dotnet/2021/maui/design"
xmlns:local="clr-namespace:BingoMania.Features.Startup"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:view="clr-namespace:BingoMania.Framework.Views"
x:DataType="local:StartupPageViewModel"
x:TypeArguments="local:StartupPageViewModel"
mc:Ignorable="d">
<StackLayout>
<Label Text="Please wait while application is loading through the startup process" />
<Button Command="{Binding StartCommand}" Text="Start Application" />
</StackLayout>
</view:ContentPageBase>

Source code

Here’s the link to the full source code https://github.com/beginnerapps/BingoMania/tree/Architecture-Setup

I hope you like the effort. Please comment to share your thoughts.

Leave a Reply

Discover more from Learn Everything .NET

Subscribe now to keep reading and get access to the full archive.

Continue reading