.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