Skip to content

Development Guide

Complete guide to developing libraries created with the ConnectSoft Library Template.

Local Development Setup

Prerequisites

Required:

  • .NET SDK 8.0 or later
  • .NET SDK 9.0 (for multi-targeting)
  • Git
  • Code editor (Visual Studio 2022, VS Code, JetBrains Rider)

Optional:

  • Python 3.x with pip (for MkDocs documentation)
  • SQL LocalDB (for integration tests)

Initial Setup

  1. Generate Library:

    dotnet new connectsoft-library --name YourLibraryName
    

  2. Navigate to Directory:

    cd YourLibraryName
    

  3. Restore Packages:

    dotnet restore
    

  4. Verify Setup:

    dotnet build
    dotnet test
    

IDE Setup

Visual Studio 2022

  1. Open Solution:

    • Open YourLibraryName.slnx (preferred) or YourLibraryName.sln
    • Visual Studio 2022 v17.14+ required for .slnx support
  2. Configure:

    • Ensure .NET 8 and .NET 9 SDKs are installed
    • Verify NuGet package sources are configured
  3. Build:

    • Press Ctrl+Shift+B or use Build menu
    • Solution builds for both net8.0 and net9.0

Visual Studio Code

  1. Install Extensions:
    • C# Dev Kit (or C# extension)
  2. .NET Extension Pack

  3. Open Folder:

    • File → Open Folder → Select library directory
  4. Build:

    • Press Ctrl+Shift+B or use Terminal: dotnet build

JetBrains Rider

  1. Open Solution:

    • File → Open → Select YourLibraryName.slnx or .sln
  2. Configure:

    • Ensure .NET SDKs are detected
    • Configure NuGet feeds if needed
  3. Build:

    • Press Ctrl+F9 or use Build menu

Building and Testing

Building

Build All Projects

# Using .slnx (faster)
dotnet build YourLibraryName.slnx

# Using .sln (fallback)
dotnet build YourLibraryName.sln

# Specific configuration
dotnet build -c Release
dotnet build -c Debug

Build Specific Project

# Build library project
dotnet build src/YourLibraryName/YourLibraryName.csproj

# Build test project
dotnet build tests/YourLibraryName.UnitTests/YourLibraryName.UnitTests.csproj

Build Specific Framework

# Build for .NET 8 only
dotnet build -f net8.0

# Build for .NET 9 only
dotnet build -f net9.0

Testing

Run All Tests

# Run all tests
dotnet test

# With code coverage
dotnet test --collect:"XPlat Code Coverage"

# Verbose output
dotnet test --verbosity normal

Run Specific Tests

# Run tests in specific project
dotnet test tests/YourLibraryName.UnitTests/

# Run specific test class
dotnet test --filter "FullyQualifiedName~MyTestClass"

# Run specific test method
dotnet test --filter "FullyQualifiedName~MyTestClass.MyTestMethod"

Test Filtering

# Run tests by category
dotnet test --filter "Category=Integration"

# Run tests by name pattern
dotnet test --filter "Name~Process"

# Exclude tests
dotnet test --filter "FullyQualifiedName!~Integration"

Code Coverage

Collect Coverage

# Collect coverage
dotnet test --collect:"XPlat Code Coverage"

# Coverage output location
# $(TestResults)/{guid}/coverage.cobertura.xml

View Coverage Report

Option 1: ReportGenerator Tool

  1. Install tool:

    dotnet tool install -g dotnet-reportgenerator-globaltool
    

  2. Generate report:

    reportgenerator \
      -reports:"**/coverage.cobertura.xml" \
      -targetdir:"coverage" \
      -reporttypes:Html
    

  3. Open coverage/index.html in browser

Option 2: Visual Studio

  1. Run tests with coverage
  2. View Test Explorer → Code Coverage Results

Option 3: JetBrains Rider

  1. Run tests with coverage
  2. View Coverage tool window

Code Organization

Project Structure

Follow the template's feature-based organization:

src/YourLibraryName/
├── YourLibraryName.csproj
├── Options/              # Configuration (if UseOptions=true)
├── Metrics/             # Metrics (if UseMetrics=true)
├── Diagnostics/         # Tracing (if UseActivitySource=true)
└── YourFeature/        # Your custom features

Adding New Features

Create Feature Folder

  1. Create folder: src/YourLibraryName/YourFeature/
  2. Add classes in namespace: YourLibraryName.YourFeature
  3. Follow existing patterns

Example: Adding a Cache Feature

// src/YourLibraryName/Cache/CacheService.cs
namespace YourLibraryName.Cache
{
    public interface ICacheService
    {
        T? Get<T>(string key);
        void Set<T>(string key, T value, TimeSpan expiration);
    }

    public class CacheService : ICacheService
    {
        // Implementation
    }
}

Namespace Conventions

Main Namespace: Matches library name

namespace YourLibraryName
{
    // Main library code
}

Feature Namespaces: Feature folders map to namespaces

namespace YourLibraryName.Cache
{
    // Cache feature
}

namespace YourLibraryName.Validation
{
    // Validation feature
}

Test Namespaces: Mirror source with .UnitTests suffix

namespace YourLibraryName.Cache.UnitTests
{
    // Cache tests
}

Code Style

Follow Analyzer Rules

The template includes static code analyzers:

  • StyleCop.Analyzers
  • SonarAnalyzer.CSharp
  • Meziantou.Analyzer

Fix Analyzer Issues:

# Format code
dotnet format

# Analyze without fixing
dotnet build /p:TreatWarningsAsErrors=false

XML Documentation

Document all public APIs:

/// <summary>
/// Provides caching functionality for the library.
/// </summary>
/// <remarks>
/// This service implements an in-memory cache with configurable expiration.
/// </remarks>
public class CacheService : ICacheService
{
    /// <summary>
    /// Gets a value from the cache.
    /// </summary>
    /// <typeparam name="T">The type of the cached value.</typeparam>
    /// <param name="key">The cache key.</param>
    /// <returns>The cached value, or <c>null</c> if not found.</returns>
    public T? Get<T>(string key)
    {
        // Implementation
    }
}

Debugging

Visual Studio Debugging

  1. Set Breakpoints:

    • Click in left margin or press F9
    • Red dot indicates breakpoint
  2. Start Debugging:

    • Press F5 or Debug → Start Debugging
    • Select test project or library project
  3. Debug Tests:

    • Right-click test method → Debug Test
    • Or use Test Explorer → Debug
  4. Debug Options:

    • Step Over: F10
    • Step Into: F11
    • Step Out: Shift+F11
    • Continue: F5

VS Code Debugging

  1. Create launch.json:

    {
      "version": "0.2.0",
      "configurations": [
        {
          "name": ".NET Core Launch",
          "type": "coreclr",
          "request": "launch",
          "preLaunchTask": "build",
          "program": "${workspaceFolder}/src/YourLibraryName/bin/Debug/net8.0/YourLibraryName.dll",
          "args": [],
          "cwd": "${workspaceFolder}",
          "stopAtEntry": false
        },
        {
          "name": ".NET Core Attach",
          "type": "coreclr",
          "request": "attach"
        }
      ]
    }
    

  2. Debug:

    • Press F5 or use Run and Debug view
    • Set breakpoints and debug

JetBrains Rider Debugging

  1. Set Breakpoints:

    • Click in left margin or press Ctrl+F8
  2. Start Debugging:

    • Press Shift+F9 or use Run menu
    • Select configuration (test or application)
  3. Debug Tests:

    • Right-click test → Debug
    • Or use Unit Test Sessions tool window

Common Debugging Scenarios

Debugging Tests

[TestMethod]
public void MyTest()
{
    // Set breakpoint here
    var service = new MyService();
    var result = service.DoWork(); // Step into here
    Assert.IsNotNull(result);
}

Debugging Library Code

  1. Create a test or console app that uses your library
  2. Set breakpoints in library code
  3. Debug the test/app
  4. Step into library methods

Debugging Configuration Issues

// Add logging to see configuration values
var options = serviceProvider.GetRequiredService<IOptions<MyOptions>>();
_logger.LogInformation("Options: {Options}", JsonSerializer.Serialize(options.Value));

Debugging Metrics

// Use TestMeterFactory to inspect metrics
var meterFactory = new TestMeterFactory();
var metrics = new MyMetrics(meterFactory);
// Use metrics and inspect TestMeterFactory

Performance Considerations

Build Performance

  1. Use .slnx Format: 48% faster than .sln
  2. Parallel Builds: Enable in IDE settings
  3. Incremental Builds: Only rebuild changed files

Test Performance

  1. Parallel Execution: Tests run in parallel by default
  2. Test Filtering: Run only relevant tests during development
  3. Skip Slow Tests: Use [Ignore] attribute for slow integration tests

Runtime Performance

  1. Avoid Premature Optimization: Profile first
  2. Use Appropriate Data Structures: Choose right collection types
  3. Async/Await: Use for I/O operations
  4. Caching: Cache expensive computations

Best Practices

Code Quality

  1. Write Tests First: TDD approach helps design
  2. Keep Methods Small: Single responsibility
  3. Use Meaningful Names: Clear, descriptive names
  4. Document Public APIs: XML comments for all public members

Dependency Management

  1. Minimize Dependencies: Only include what's needed
  2. Keep Versions Updated: Regularly update packages
  3. Use CPM: Central Package Management for consistency
  4. Review Dependencies: Check for deprecated/vulnerable packages

Testing

  1. Test Coverage: Aim for 70%+ coverage
  2. Test Organization: Mirror source structure
  3. Test Naming: Descriptive test method names
  4. Test Isolation: Each test should be independent

Documentation

  1. Keep README Updated: Document usage and examples
  2. XML Comments: Document all public APIs
  3. Code Examples: Include usage examples
  4. Changelog: Document breaking changes

Troubleshooting

Build Errors

Error: NETSDK1045: The current .NET SDK does not support targeting .NET 9.0

Fix: Install .NET 9 SDK

Error: NU1101: Unable to find package

Fix:

  • Check nuget.config for feed configuration
  • Restore packages: dotnet restore

Test Errors

Error: Tests not found

Fix:

  • Verify test project name contains "test"
  • Check test project references library project
  • Ensure IsTestProject=true in .csproj

Error: Coverage not collected

Fix:

  • Verify coverlet.collector package reference
  • Check test run settings file

IDE Issues

Issue: IntelliSense not working

Fix:

  • Restore packages: dotnet restore
  • Rebuild solution
  • Restart IDE

Issue: Analyzers not running

Fix:

  • Check Directory.Packages.props for analyzer packages
  • Verify analyzers are not suppressed in GlobalSuppressions.cs

References