Writing Your Own Roslyn Analyzers for .NET MAUI

🧠 Writing Your Own Roslyn Analyzers for .NET MAUI

Enforcing Mobile Architecture, Performance, and UI Standards

As .NET MAUI applications grow, maintaining consistency across:

  • 📱 UI layers
  • ⚡ Performance-sensitive code
  • 🧩 MVVM boundaries
  • 🔄 Platform-specific implementations …becomes increasingly difficult. Code reviews help—but they don’t scale perfectly. That’s where Roslyn Analyzers become incredibly powerful. Instead of relying on humans to constantly detect issues, you can create custom compile-time rules that automatically enforce your MAUI architecture and coding standards. In this guide, we’ll go beyond generic analyzers and focus specifically on:
  • 📱 MAUI best practices
  • 🧩 MVVM enforcement
  • ⚡ Performance rules
  • 🚫 UI thread misuse
  • 🔄 Platform-specific patterns
  • 🏗️ Architecture validation

🧠 Why Roslyn Analyzers Matter More in MAUI

Mobile apps introduce challenges traditional desktop/web apps don’t have:

Mobile Concern Why It Matters
UI thread blocking ⚠️ Causes freezes and ANRs
Memory leaks 🧠 Mobile devices are constrained
Platform-specific APIs 📱 Hard to enforce consistency
MVVM separation 🧩 Easy to accidentally break
Performance-sensitive rendering ⚡ Critical for UX

Roslyn lets you enforce these rules before the app even runs.


🚀 Real MAUI Problems Roslyn Can Solve

Instead of generic naming rules, imagine analyzers that detect:

  • Task.Result on UI thread
  • ❌ Direct API calls from Views
  • ❌ Massive code-behind files
  • ❌ Missing MainThread.InvokeOnMainThreadAsync
  • ❌ Disallowed platform APIs in shared projects
  • ❌ Non-disposable image resources
  • ❌ UI controls created inside loops
  • ❌ Forbidden navigation patterns This is where analyzers become architectural superpowers.

🧩 Roslyn Architecture Refresher

Roslyn analyzers can:

  • Analyze syntax trees 🌳
  • Analyze symbols 🧠
  • Emit diagnostics ⚠️
  • Offer automatic fixes 🛠️

📊 Analyzer vs MAUI-Specific Use Cases

Analyzer Type MAUI Example
Naming Enforce ViewModel suffix
Performance Detect blocking calls on UI thread
Architecture Prevent Views from accessing repositories
Platform Rules Restrict #if ANDROID usage
Threading Ensure UI updates occur on MainThread

⚙️ Getting Started

📦 Create Analyzer Project

dotnet new analyzer -n MauiArchitectureAnalyzer

🧩 Example #1 — Enforce ViewModel Naming

In MAUI MVVM apps:

LoginViewModel ✅
LoginVM ❌

🔧 Diagnostic Definition

private static readonly DiagnosticDescriptor Rule = new(
    id: "MAUI001",
    title: "ViewModels must end with ViewModel",
    messageFormat: "Class '{0}' should end with 'ViewModel'",
    category: "Architecture",
    defaultSeverity: DiagnosticSeverity.Warning,
    isEnabledByDefault: true);

🔎 Register Analyzer

context.RegisterSymbolAction(
    AnalyzeSymbol,
    SymbolKind.NamedType);

🧠 Analyze Class

private void AnalyzeSymbol(SymbolAnalysisContext context)
{
    var symbol = (INamedTypeSymbol)context.Symbol;

    if (symbol.Name.Contains("VM"))
    {
        var diagnostic = Diagnostic.Create(
            Rule,
            symbol.Locations[0],
            symbol.Name);

        context.ReportDiagnostic(diagnostic);
    }
}

⚡ Example #2 — Detect Blocking Calls on UI Thread

One of the most common MAUI performance issues:

var result = myTask.Result; // ❌

This can freeze the UI.


🧠 Analyzer Logic

context.RegisterSyntaxNodeAction(
    AnalyzeMemberAccess,
    SyntaxKind.SimpleMemberAccessExpression);

🔍 Detection

private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context)
{
    var memberAccess = (MemberAccessExpressionSyntax)context.Node;

    if (memberAccess.Name.Identifier.Text == "Result")
    {
        var diagnostic = Diagnostic.Create(
            Rule,
            memberAccess.GetLocation());

        context.ReportDiagnostic(diagnostic);
    }
}

🧩 Example #3 — Prevent Repository Access from Views

Bad MAUI pattern:

public partial class MainPage : ContentPage
{
    private readonly UserRepository _repository;
}

Views should talk to ViewModels—not repositories.


🧠 Architectural Analyzer

if (classSymbol.BaseType?.Name == "ContentPage")
{
    foreach (var field in classSymbol.GetMembers().OfType<IFieldSymbol>())
    {
        if (field.Type.Name.EndsWith("Repository"))
        {
            context.ReportDiagnostic(...);
        }
    }
}

📱 Example #4 — Enforce MainThread Usage

Incorrect:

MyLabel.Text = "Updated";

from background threads.


Correct:

await MainThread.InvokeOnMainThreadAsync(() =>
{
    MyLabel.Text = "Updated";
});

You can build analyzers to detect unsafe UI access.


🛠️ Code Fixes for MAUI

Roslyn becomes even more powerful with auto-fixes.


Example Fix

Convert:

myTask.Result

into:

await myTask

🧪 Unit Testing MAUI Analyzers

Testing analyzers is critical.


Example

[TestMethod]
public async Task DetectsBlockingTaskResult()
{
    var code = """
        public async Task Load()
        {
            var x = task.Result;
        }
    """;

    var expected = new DiagnosticResult("MAUI002");

    await VerifyAnalyzerAsync(code, expected);
}

📦 Shipping Your Analyzer Across MAUI Solutions

Option 1 — NuGet Package

Perfect for:

  • Enterprise MAUI apps
  • Internal company standards
  • Multi-team consistency

Option 2 — CI/CD Enforcement

Analyzers work beautifully in:

  • GitHub Actions ⚡
  • Azure DevOps 🚀
  • Pull request validation 🔍

🧠 Advanced MAUI Analyzer Ideas

Rule Purpose
Detect large XAML pages UI maintainability
Detect unawaited Tasks Prevent async bugs
Prevent direct SQLite access from UI Architecture
Enforce DI registration Scalability
Detect excessive BindableProperties Performance
Restrict GraphicsView misuse Rendering optimization

⚖️ Why This Is Powerful for MAUI Teams

Traditional Review Roslyn Analyzer
Human-dependent Automated
Inconsistent Deterministic
Happens after coding Happens while coding
Easy to miss issues Immediate feedback

🚀 Performance Benefits

Analyzers can help catch:

  • UI freezes ⚠️
  • Over-rendering 🎨
  • Threading violations 🔄
  • Memory leaks 🧠
  • Architecture drift 🏗️ …before they hit production.

🔗 Reference Links


🧠 Key Takeaways

  • Roslyn analyzers are incredibly valuable for MAUI apps 📱
  • Mobile-specific problems are perfect candidates for compile-time analysis ⚡
  • You can enforce architecture, performance, and threading rules automatically 🧩
  • Custom analyzers scale much better than manual PR reviews 🚀

🔚 Final Thoughts

In large MAUI applications, maintaining consistency manually becomes almost impossible over time. Roslyn analyzers allow you to transform:

  • tribal knowledge
  • PR comments
  • architecture documents …into real, enforceable compiler rules.

And that changes how teams build mobile apps.

Instead of hoping developers follow best practices…
you can make the IDE enforce them automatically. ⚡


An unhandled error has occurred. Reload 🗙