.NET MAUI

Best Practices & Architecture

7 question(s)

What are general best practices for a maintainable MAUI app?

Beginner
Use MVVM with compiled bindings, keep logic in testable view models/services, use DI instead of service location, centralize styles/resources, prefer CollectionView and shallow templates, handle async correctly, and isolate platform code behind interfaces. Consistency and small, focused classes keep the codebase healthy.
Real-world example A team codifies these practices in a style guide, and new features slot in predictably with high test coverage.

Common follow-ups: Why MVVM plus DI? | Where should platform code live?

Architecture MVVM Best Practices & Architecture

How should you organize code in a MAUI project?

Intermediate
Use feature folders (or layered folders: Views, ViewModels, Services, Models) and consider separate class libraries for domain/core and infrastructure so logic is reusable and testable. Keep the MAUI head focused on UI. Group platform code under Platforms and shared resources under Resources.
/Features/Orders/OrdersPage.xaml
/Features/Orders/OrdersViewModel.cs
/Core/Services/IOrderService.cs
/Infrastructure/Api/OrderApiClient.cs
Real-world example Grouping each feature's view, view model, and services together makes navigation and ownership clear as the app grows.

Common follow-ups: Feature folders vs layered folders? | Why extract a core library?

Architecture Dependency Injection Best Practices & Architecture

How do you implement a navigation service to keep view models testable?

Intermediate
Wrap Shell navigation behind an INavigationService interface (GoToAsync-style methods) registered in DI, so view models depend on the abstraction rather than static Shell.Current. Tests supply a fake navigation service and assert navigations without a UI.
public interface INavigationService { Task GoToAsync(string route, IDictionary<string,object>? p = null); }
public class ShellNavigationService : INavigationService
{ public Task GoToAsync(string r, IDictionary<string,object>? p = null)
    => Shell.Current.GoToAsync(r, p ?? new Dictionary<string,object>()); }
Real-world example View models call _nav.GoToAsync so unit tests verify navigation happened without touching Shell.

Common follow-ups: Why abstract navigation? | How does this help testing?

Navigation Dependency Injection Best Practices & Architecture

How do you handle errors and show user-friendly messages centrally?

Intermediate
Catch exceptions at boundaries (service calls, commands), log them via a logging/telemetry abstraction, and surface a friendly message through a shared dialog/toast service. Avoid swallowing exceptions silently; distinguish expected failures (validation, offline) from unexpected ones and only crash on truly unrecoverable states.
try { await _svc.SaveAsync(); }
catch (HttpRequestException) { await _dialogs.AlertAsync("You appear offline."); }
catch (Exception ex) { _log.Error(ex); await _dialogs.AlertAsync("Something went wrong."); }
Real-world example All command handlers route errors through one dialog service, giving consistent, friendly messaging and centralized logging.

Common follow-ups: Where should you catch exceptions? | Why distinguish expected failures?

Architecture Debugging Best Practices & Architecture

How do you keep a MAUI codebase testable and loosely coupled?

Advanced
Depend on interfaces (services, navigation, dialogs, device features) injected via DI; keep view models free of platform and UI types; use the MVVM Toolkit for commands/observables; and put integration-heavy code behind seams you can fake. Aim for the bulk of behavior to be unit-testable without a device.
public OrdersViewModel(IOrderService svc,
    INavigationService nav, IDialogService dialogs) { /* all injected */ }
Real-world example Because every dependency is an injected interface, the orders view model is fully unit-tested with mocks.

Common follow-ups: What types should view models avoid? | What is a test seam?

Architecture Testing & Debugging Best Practices & Architecture

What logging and observability practices suit a MAUI app?

Advanced
Use Microsoft.Extensions.Logging via the host, with providers for debug and a remote sink (Application Insights/Sentry). Log meaningful events and errors with context, track key user flows, and monitor crash-free rates and performance. Keep logging cheap and avoid logging sensitive data.
builder.Logging.AddDebug();
builder.Services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
_logger.LogInformation("Order {Id} submitted", order.Id);
Real-world example Structured logs and remote telemetry let the team diagnose a production issue without reproducing it locally.

Common follow-ups: What logging abstraction does MAUI use? | What must you never log?

Monitoring Architecture Best Practices & Architecture

How do you decide between native MAUI, Blazor Hybrid, and hybrid approaches for a project?

Advanced
Choose native MAUI (XAML/handlers) for the most native look, performance, and platform integration. Choose Blazor Hybrid to reuse web skills/components and share UI with a web app, accepting a WebView layer. You can mix both—native shells with Blazor content areas. Decide based on team skills, UI sharing needs, and performance requirements.
Real-world example A team with a large Blazor component library builds most screens as Blazor Hybrid but keeps performance-critical, gesture-heavy screens native.

Common follow-ups: When is Blazor Hybrid the better fit? | Can you mix both in one app?

Blazor Hybrid Architecture Best Practices & Architecture