MAUI Mobile Template - Developer Preparation Guide¶
Overview¶
This guide provides essential information for developers implementing the ConnectSoft MAUI mobile template. It covers prerequisites, architecture principles, key patterns, development guidelines, and references to help you get started quickly.
Target Audience: Developers, architects, and engineers working on MAUI mobile template implementation
Prerequisites¶
Required Knowledge¶
- .NET MAUI Fundamentals:
- MAUI project structure and lifecycle
- XAML and data binding
- MVVM patterns
- Shell navigation
-
Platform-specific implementations
-
.NET Core/ASP.NET Core:
- Dependency Injection (Microsoft.Extensions.DependencyInjection)
- Logging (Microsoft.Extensions.Logging)
- Localization (Microsoft.Extensions.Localization)
- Options pattern (Microsoft.Extensions.Options)
-
Configuration (Microsoft.Extensions.Configuration)
-
ConnectSoft Ecosystem:
- Template layering architecture (Base Template + Specialized Templates)
- Git submodules for template composition
- Template metadata composition (template.json, extend files)
- ConnectSoft.Extensions.* libraries usage
Required Tools¶
- .NET 9.0 SDK - Latest version
- Visual Studio 2022 (17.8+) or Visual Studio Code with C# extension
- .NET MAUI workload installed:
- Platform SDKs:
- iOS: Xcode 15+ (macOS only)
- Android: Android SDK (API 34+)
- Git - For submodule management
- Azure DevOps CLI (optional) - For pipeline management
Development Environment Setup¶
-
Install .NET MAUI:
-
Verify MAUI Installation:
-
Platform-Specific Setup:
- iOS (macOS only): Install Xcode, configure provisioning profiles
-
Android: Install Android SDK, configure emulators or physical devices
-
Clone ConnectSoft Repositories:
Architecture Principles¶
Core Principle: Use Built-in Frameworks First¶
DO:
- Use ILogger<T> from Microsoft.Extensions.Logging directly
- Use IStringLocalizer<T> from Microsoft.Extensions.Localization directly
- Use MAUI Shell navigation (Shell.Current.GoToAsync()) directly
- Use SecureStorage and Preferences from Microsoft.Maui.Storage directly
- Use Connectivity from Microsoft.Maui.Networking directly
- Use MAUI lifecycle events (OnStart, OnSleep, OnResume) directly
DON'T:
- Create custom ILoggingService abstraction
- Create custom ILocalizationService abstraction
- Create custom INavigationService abstraction (unless minimal wrapper for testability)
- Create custom IStorageService abstraction
- Create custom IConnectivityService abstraction
- Create custom IAppLifecycleService abstraction
Minimal Abstractions Rule¶
Only create abstractions when absolutely necessary for testability. The only exception is DialogService which wraps Page.DisplayAlert() for testability purposes.
Example - DialogService (Minimal Wrapper):
// Infrastructure/DialogService.cs
public interface IDialogService
{
Task<bool> DisplayAlert(string title, string message, string accept, string cancel);
Task<string> DisplayActionSheet(string title, string cancel, string destruction, params string[] buttons);
}
public class DialogService : IDialogService
{
private readonly Page _page;
public DialogService(Page page)
{
_page = page;
}
public async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
{
return await _page.DisplayAlert(title, message, accept, cancel);
}
// ... other methods
}
Example - Direct Usage (Preferred):
// ViewModel - Use SecureStorage directly
public class LoginViewModel : BaseViewModel
{
public async Task SaveToken(string token)
{
await SecureStorage.SetAsync("oauth_token", token);
}
public async Task<string> GetToken()
{
return await SecureStorage.GetAsync("oauth_token");
}
}
Key Patterns¶
1. Dependency Injection Setup¶
MauiProgram.cs Pattern:
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
});
// Built-in services
builder.Services.AddLogging(logging =>
{
logging.AddDebug();
logging.AddConsole();
});
builder.Services.AddLocalization();
// ConnectSoft extensions
builder.Services.AddConnectSoftObservability(options =>
{
options.UseApplicationInsights();
});
// Minimal wrappers (only for testability)
builder.Services.AddSingleton<IDialogService, DialogService>();
// ViewModels and Services
builder.Services.AddTransient<MainViewModel>();
builder.Services.AddTransient<MainPage>();
return builder.Build();
}
}
2. Logging Pattern¶
Use ILogger
public class MyService : BaseService
{
private readonly ILogger<MyService> _logger;
public MyService(ILogger<MyService> logger) : base(logger)
{
_logger = logger;
}
public async Task DoWork()
{
_logger.LogInformation("Starting work");
try
{
// Work here
_logger.LogInformation("Work completed successfully");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred during work");
throw;
}
}
}
Structured Logging:
3. Localization Pattern¶
Use IStringLocalizer
public class MainViewModel : BaseViewModel
{
private readonly IStringLocalizer<MainViewModel> _localizer;
public MainViewModel(IStringLocalizer<MainViewModel> localizer, ILogger<MainViewModel> logger)
: base(logger)
{
_localizer = localizer;
}
public string Title => _localizer["Title"];
public string WelcomeMessage => _localizer["WelcomeMessage", UserName];
}
Resource Files:
Resources/
Strings/
Resources.resx (default)
Resources.en.resx (English)
Resources.es.resx (Spanish)
4. Navigation Pattern¶
Use Shell Navigation Directly:
// Navigate to route
await Shell.Current.GoToAsync("//login");
// Navigate with parameters
await Shell.Current.GoToAsync("//details", new Dictionary<string, object>
{
{ "ItemId", itemId }
});
// Register routes in AppShell.xaml.cs
Routing.RegisterRoute("details", typeof(DetailsPage));
5. Storage Pattern¶
Use SecureStorage for Sensitive Data:
// Save token
await SecureStorage.SetAsync("oauth_token", token);
// Get token
var token = await SecureStorage.GetAsync("oauth_token");
// Remove token
SecureStorage.Remove("oauth_token");
Use Preferences for Non-Sensitive Data:
// Save preference
Preferences.Set("user_preference", value);
// Get preference
var value = Preferences.Get("user_preference", defaultValue);
// Remove preference
Preferences.Remove("user_preference");
6. Application Lifecycle Pattern¶
Use Built-in Lifecycle Events:
public partial class App : Application
{
protected override void OnStart()
{
// App started - initialize services, load data
_logger.LogInformation("Application started");
}
protected override void OnSleep()
{
// App going to background - save state
_logger.LogInformation("Application sleeping");
SaveApplicationState();
}
protected override void OnResume()
{
// App resuming from background - restore state
_logger.LogInformation("Application resuming");
RestoreApplicationState();
}
}
Template Layering Architecture¶
Understanding the Three-Layer Model¶
The MAUI mobile templates follow ConnectSoft's three-layer template architecture:
flowchart TB
subgraph Layer1["Layer 1: Shared Libraries"]
LIB1[ConnectSoft.Extensions.Logging]
LIB2[ConnectSoft.Extensions.Localization]
LIB3[ConnectSoft.Extensions.Observability]
LIB4[ConnectSoft.Maui.UIKit]
end
subgraph Layer2["Layer 2: Base Template"]
BASE[ConnectSoft.MauiBaseTemplate<br/>Core Infrastructure<br/>Cross-Cutting Concerns]
end
subgraph Layer3["Layer 3: Full Template"]
FULL[ConnectSoft.MauiTemplate<br/>Base + Full Features<br/>API, Auth, Offline, Platform]
end
Layer1 -->|NuGet Packages| Layer2
Layer1 -->|NuGet Packages| Layer3
Layer2 -->|Git Submodule| Layer3
Base Template Structure¶
ConnectSoft.MauiBaseTemplate/
├── src/
│ ├── MauiBase.Application/ # Main app (MauiProgram.cs, AppShell)
│ ├── MauiBase.Core/ # BaseViewModel, BaseService
│ ├── MauiBase.Infrastructure/ # Minimal wrappers (DialogService)
│ └── MauiBase.Shared/ # Resources (localization, styles)
├── tests/
│ ├── MauiBase.UnitTests/
│ └── MauiBase.IntegrationTests/
├── docs/
└── .template.config/
└── template.json
Full Template Structure (with Submodule)¶
ConnectSoft.MauiTemplate/
├── base-template/ # Git submodule → ConnectSoft.MauiBaseTemplate
│ ├── src/
│ │ ├── MauiBase.Application/
│ │ ├── MauiBase.Core/
│ │ └── ...
│ └── tests/
├── src/
│ ├── MauiApp.Application/ # Full-featured app
│ ├── MauiApp.Domain/ # Domain logic (if needed)
│ └── MauiApp.Infrastructure/ # Full implementations
├── tests/
│ ├── MauiApp.UnitTests/
│ ├── MauiApp.IntegrationTests/
│ └── MauiApp.UITests/
├── docs/
└── .template.config/
└── maui.template.extend.json # Extends base template.json
Git Submodule Usage¶
Initializing Submodule:
# Clone full template repository
git clone <full-template-repo>
cd ConnectSoft.MauiTemplate
# Initialize and update submodule
git submodule update --init --recursive
Updating Submodule:
# Update to latest base template
cd base-template
git pull origin main
cd ..
git add base-template
git commit -m "Update base template submodule"
Development Workflow¶
1. Starting a New Feature¶
- Review Backlog Plan:
- Read the relevant Epic, Feature, and Task descriptions
- Understand acceptance criteria
-
Review dependencies
-
Set Up Development Environment:
- Clone repository (and submodule if needed)
- Restore packages:
dotnet restore - Build solution:
dotnet build -
Run tests:
dotnet test -
Create Feature Branch:
-
Implement Feature:
- Follow architecture principles
- Use built-in frameworks
- Write tests as you go
-
Update documentation
-
Verify Implementation:
- All tests pass
- Code builds successfully
- Manual testing on iOS and Android
- Code review ready
2. Testing Guidelines¶
Unit Tests: - Test ViewModels, Services, and business logic - Use Moq or NSubstitute for mocking - Use FluentAssertions for assertions - Aim for 80%+ code coverage
Integration Tests: - Test API integration, database operations - Use test app factory pattern - Test end-to-end flows
UI Tests: - Test navigation, user interactions - Test on both iOS and Android - Use Appium or MAUI UITest framework
3. Code Quality Standards¶
Follow ConnectSoft Standards: - Use StyleCop analyzers - Follow .editorconfig rules - Write XML documentation comments - Handle nullable reference types properly - Use async/await correctly
Code Review Checklist: - [ ] Uses built-in frameworks (no unnecessary abstractions) - [ ] Follows MVVM patterns - [ ] Has unit tests - [ ] Documentation updated - [ ] Builds successfully - [ ] Tests pass - [ ] Works on both iOS and Android
Common Pitfalls and Solutions¶
Pitfall 1: Creating Unnecessary Abstractions¶
Problem: Creating custom abstractions for built-in frameworks
Solution: Use built-in frameworks directly
Pitfall 2: Not Using Dependency Injection¶
Problem: Creating services with new keyword
Solution: Use dependency injection
// DO THIS
public class MyViewModel : BaseViewModel
{
private readonly IMyService _service;
public MyViewModel(IMyService service, ILogger<MyViewModel> logger)
: base(logger)
{
_service = service;
}
}
Pitfall 3: Hard-coding Strings¶
Problem: Hard-coding user-facing strings
Solution: Use localization
// DO THIS
private readonly IStringLocalizer<MyViewModel> _localizer;
Title = _localizer["Welcome"];
Pitfall 4: Not Handling Platform Differences¶
Problem: Assuming same behavior on iOS and Android
// DON'T DO THIS (without platform checks)
await SecureStorage.SetAsync("key", "value"); // May behave differently
Solution: Test on both platforms and handle differences
// DO THIS (with platform-specific handling if needed)
#if IOS
// iOS-specific code
#elif ANDROID
// Android-specific code
#endif
Reference Documentation¶
ConnectSoft Documentation¶
- Template Architecture Specification - Template hierarchy and composition
- Template Layering and Reuse - Three-layer architecture
- Template Metadata Composition - Template.json composition
- Templates Dependencies - Template relationships
- Templates Overview - All templates overview
- MAUI Mobile Template Backlog Plan - Development plan
External Documentation¶
- .NET MAUI Documentation
- Microsoft.Extensions.Logging
- Microsoft.Extensions.Localization
- MAUI Shell Navigation
- MAUI SecureStorage
ConnectSoft Code References¶
- ConnectSoft.BaseTemplate - Backend template patterns (DI, logging, options)
- ConnectSoft.Blazor.UIKit - UI component library patterns
- ConnectSoft.Blazor.ShellTemplate - Shell template patterns
- ConnectSoft.Extensions.* - Extension library usage examples
Getting Help¶
Internal Resources¶
- ConnectSoft Documentation:
- Review template architecture docs
- Check existing template implementations
-
Review extension library documentation
-
Code Examples:
- ConnectSoft.BaseTemplate for backend patterns
- ConnectSoft.Blazor templates for frontend patterns
-
ConnectSoft.Extensions.* for extension patterns
-
Team Communication:
- Ask questions in team channels
- Request code reviews early
- Share findings and patterns
External Resources¶
- .NET MAUI Community:
- .NET MAUI GitHub
-
Stack Overflow:
- Tag:
dotnet-maui - Tag:
xamarin.forms(legacy, but relevant)
Next Steps¶
- Read the Backlog Plan:
- Review MAUI Mobile Template Backlog Plan
-
Understand the Epic, Feature, and Task you're working on
-
Set Up Your Environment:
- Install required tools
- Clone repositories
-
Verify setup
-
Review Architecture:
- Understand the three-layer model
- Review base template structure
-
Understand template composition
-
Start Development:
- Pick a task from the backlog
- Follow development workflow
- Write tests and documentation
Summary¶
Key takeaways for developers:
- Use built-in frameworks first - ILogger
, IStringLocalizer , Shell navigation, SecureStorage, Preferences - Minimal abstractions - Only create wrappers for testability when absolutely necessary
- Follow ConnectSoft patterns - Template layering, Git submodules, template composition
- Test on both platforms - iOS and Android have differences
- Write comprehensive tests - Unit, integration, and UI tests
- Document as you go - Update documentation with code changes
Happy coding!