Use Cases for the ConnectSoft Library Template¶
The ConnectSoft.LibraryTemplate is designed to streamline the development of reusable .NET libraries. Its flexibility and pre-configured features make it suitable for a variety of scenarios, from creating utility libraries to crafting core components for enterprise applications.
Use Cases¶
Utility Libraries¶
- Description:
- Create libraries that provide common utility functions for strings, numbers, dates, and more.
- Example:
- Develop a library with reusable extensions for data validation or string manipulation.
Implementation Example¶
- Generate the Library:
- Add Utility Methods:
- Distribute as a NuGet Package:
- Use the pre-configured pipeline to publish the library for internal or external use.
Core Framework Components¶
- Description:
- Build foundational libraries for shared use across microservices or enterprise applications.
- Example:
- Create a library for common domain entities, value objects, or aggregate roots.
Implementation Example¶
- Generate the Library:
- Define Domain Entities:
API Client Libraries¶
- Description:
- Create libraries for interacting with external APIs, abstracting complexities from application layers.
- Example:
- Build a client library for integrating with Azure Cognitive Services.
Implementation Example¶
- Generate the Library:
- Add API Integration:
public class TranslatorClient { private readonly HttpClient _httpClient; public TranslatorClient(HttpClient httpClient) => _httpClient = httpClient; public async Task<string> TranslateAsync(string text, string targetLanguage) { var response = await _httpClient.GetAsync($"translate?text={text}&to={targetLanguage}"); return await response.Content.ReadAsStringAsync(); } }
Localization Libraries¶
- Description:
- Build libraries to manage localization and translation resources for global applications.
- Example:
- Develop a localization library with pre-configured Resx or JSON support.
Implementation Example¶
- Generate the Library:
- Add Localization Resources:
- Include Resx files for multiple languages:
Testing Frameworks¶
- Description:
- Create libraries for unit, integration, or performance testing utilities.
- Example:
- Develop a testing library that includes custom assertions or mocks.
Implementation Example¶
- Generate the Library:
- Add Testing Utilities:
Multi-Tenant Components¶
- Description:
- Create libraries for managing multi-tenancy in SaaS applications.
- Example:
- Develop a library for tenant isolation and tenant-specific configuration.
Implementation Example¶
- Generate the Library:
- Add Multi-Tenant Logic:
Libraries with Cross-Cutting Concerns¶
-
Description:
- Create libraries that integrate with DI containers, expose configurable settings, or require logging capabilities.
-
Example:
- Develop a library for interacting with an external service that uses options for configuration and structured logging.
Implementation Example¶
- Generate the Library:
-
Configure Options
-
Add DI Setup
public static class ServiceCollectionExtensions { public static IServiceCollection AddExternalService(this IServiceCollection services, IConfiguration config) { services.Configure<ExternalServiceOptions>(config.GetSection(ExternalServiceOptions.SectionName)); services.AddOptions<ExternalServiceOptions>().ValidateDataAnnotations().ValidateOnStart(); services.AddSingleton<ExternalServiceClient>(); return services; } } -
Use Logging
-
Configure
appsettings.json
Real-World Examples¶
Reusable Extensions Library¶
- Scenario:
- A development team needs utility methods for string manipulation and date handling across projects.
- Solution:
- Use the Library Template to create
ConnectSoft.Extensions.
- Use the Library Template to create
Domain Model Library¶
- Scenario:
- A SaaS application needs a shared library of core domain entities.
- Solution:
- Generate
ConnectSoft.Domain.Coreand define domain models.
- Generate
API Integration Library¶
- Scenario:
- A microservice requires integration with an external payment gateway.
- Solution:
- Create
ConnectSoft.PaymentGatewaywith client classes for the gateway's API.
- Create
Testing Utilities Library¶
- Scenario:
- A QA team needs custom assertions and mocks for testing microservices.
- Solution:
- Build
ConnectSoft.Testing.Utilsto centralize testing utilities.
- Build
Multi-Framework Compatible Libraries¶
- Scenario:
- A developer wants to publish a library that can be used by both
.NET 8(LTS) applications and those already migrated to.NET 9.
- A developer wants to publish a library that can be used by both
-
Solution:
- Use the template as-is with multi-targeting (
net8.0;net9.0) already pre-configured in the.csproj. - Add runtime-specific logic using compiler directives if needed:
- Use the template as-is with multi-targeting (
Benefits¶
- Accelerated Development:
- Pre-configured settings eliminate setup time, allowing teams to focus on business logic.
- Consistency:
- Ensures libraries adhere to ConnectSoft’s standards for quality and reusability.
- Scalability:
- Enables seamless integration with CI/CD pipelines and artifact repositories.
- Cross-Cutting Concerns:
- Supports optional DI, logging, and configuration for libraries with complex requirements.
Parameter-Specific Use Cases¶
Minimal Library (No Optional Features)¶
Scenario: Create a simple utility library without cross-cutting concerns.
Template Command:
dotnet new connectsoft-library --name ConnectSoft.Extensions.StringUtils \
--useDI false --useLogging false --useOptions false --useMetrics false
Use Case: String manipulation utilities that don't need configuration or logging.
Example Implementation:
namespace ConnectSoft.Extensions.StringUtils
{
public static class StringExtensions
{
public static string ToTitleCase(this string value)
{
if (string.IsNullOrWhiteSpace(value))
return value;
return System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(value.ToLower());
}
public static bool IsValidEmail(this string value)
{
if (string.IsNullOrWhiteSpace(value))
return false;
try
{
var addr = new System.Net.Mail.MailAddress(value);
return addr.Address == value;
}
catch
{
return false;
}
}
}
}
Configuration-Only Library¶
Scenario: Library that provides configuration options and service registration.
Template Command:
dotnet new connectsoft-library --name ConnectSoft.Extensions.Configuration \
--useDI --useLogging --useOptions --useMetrics false --useTracing false
Use Case: Configuration library that binds settings and registers services.
Example Implementation:
namespace ConnectSoft.Extensions.Configuration
{
public class DatabaseOptions
{
public const string SectionName = "Database";
[Required]
public required string ConnectionString { get; set; }
[Range(1, 300)]
public int CommandTimeout { get; set; } = 30;
public bool EnableRetryOnFailure { get; set; } = true;
}
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddDatabase(
this IServiceCollection services,
IConfiguration configuration)
{
services.Configure<DatabaseOptions>(
configuration.GetSection(DatabaseOptions.SectionName));
services.AddOptions<DatabaseOptions>()
.Bind(configuration.GetSection(DatabaseOptions.SectionName))
.ValidateDataAnnotations()
.ValidateOnStart();
services.AddSingleton<IDatabaseService, DatabaseService>();
return services;
}
}
}
Observability Library¶
Scenario: Library focused on monitoring, metrics, and tracing.
Template Command:
dotnet new connectsoft-library --name ConnectSoft.Extensions.Observability \
--useDI --useLogging --useOptions false --useMetrics --useTracing
Use Case: Library that provides observability features for applications.
Example Implementation:
namespace ConnectSoft.Extensions.Observability
{
public class ObservabilityMetrics
{
private readonly Counter<long> _operationCounter;
private readonly Histogram<double> _operationDuration;
public ObservabilityMetrics(IMeterFactory meterFactory)
{
var meter = meterFactory.Create("ConnectSoft.Observability");
_operationCounter = meter.CreateCounter<long>("observability.operations.count");
_operationDuration = meter.CreateHistogram<double>("observability.operations.duration", "ms");
}
public void RecordOperation(string operationName, double durationMs)
{
_operationCounter.Add(1,
new KeyValuePair<string, object?>("operation", operationName));
_operationDuration.Record(durationMs,
new KeyValuePair<string, object?>("operation", operationName));
}
}
public static class ObservabilityDiagnostics
{
public const string ActivitySourceName = "ConnectSoft.Observability";
public static readonly ActivitySource ActivitySource = new(ActivitySourceName);
public static Activity? StartOperation(string operationName, string? itemId = null)
{
var tags = new List<KeyValuePair<string, object?>>
{
new("operation", operationName)
};
if (!string.IsNullOrEmpty(itemId))
{
tags.Add(new KeyValuePair<string, object?>("item.id", itemId));
}
return ActivitySource.StartActivity(operationName, ActivityKind.Internal, tags: tags);
}
}
}
Full-Featured Library¶
Scenario: Library with all features enabled for comprehensive functionality.
Template Command:
dotnet new connectsoft-library --name ConnectSoft.Integration.ExternalService \
--useDI --useLogging --useOptions --useMetrics --useTracing
Use Case: Integration library that needs configuration, logging, metrics, and tracing.
Example Implementation:
namespace ConnectSoft.Integration.ExternalService
{
public class ExternalServiceOptions
{
public const string SectionName = "ExternalService";
[Required]
[Url]
public required string BaseUrl { get; set; }
[Required]
public required string ApiKey { get; set; }
[Range(1, 300)]
public int TimeoutSeconds { get; set; } = 30;
}
public class ExternalServiceMetrics
{
private readonly Counter<long> _requestCounter;
private readonly Histogram<double> _requestDuration;
private readonly Counter<long> _errorCounter;
public ExternalServiceMetrics(IMeterFactory meterFactory)
{
var meter = meterFactory.Create("ConnectSoft.ExternalService");
_requestCounter = meter.CreateCounter<long>("externalservice.requests.count");
_requestDuration = meter.CreateHistogram<double>("externalservice.requests.duration", "ms");
_errorCounter = meter.CreateCounter<long>("externalservice.errors.count");
}
public void RecordRequest(double durationMs, string status)
{
_requestCounter.Add(1, new KeyValuePair<string, object?>("status", status));
_requestDuration.Record(durationMs, new KeyValuePair<string, object?>("status", status));
}
public void RecordError(string errorType)
{
_errorCounter.Add(1, new KeyValuePair<string, object?>("error.type", errorType));
}
}
public class ExternalServiceClient
{
private readonly ExternalServiceOptions _options;
private readonly ILogger<ExternalServiceClient> _logger;
private readonly ExternalServiceMetrics _metrics;
private readonly HttpClient _httpClient;
public ExternalServiceClient(
IOptions<ExternalServiceOptions> options,
ILogger<ExternalServiceClient> logger,
ExternalServiceMetrics metrics,
HttpClient httpClient)
{
_options = options.Value;
_logger = logger;
_metrics = metrics;
_httpClient = httpClient;
}
public async Task<string> CallApiAsync(string endpoint)
{
var sw = Stopwatch.StartNew();
using var scope = ExternalServiceDiagnostics.StartActivityScope(
_logger,
"ExternalService.CallApi",
new[] { new KeyValuePair<string, object?>("endpoint", endpoint) });
try
{
_logger.LogInformation("Calling external service endpoint {Endpoint}", endpoint);
var response = await _httpClient.GetAsync($"{_options.BaseUrl}/{endpoint}");
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsStringAsync();
sw.Stop();
_metrics.RecordRequest(sw.ElapsedMilliseconds, "success");
_logger.LogInformation("External service call completed in {Duration}ms", sw.ElapsedMilliseconds);
return result;
}
catch (Exception ex)
{
sw.Stop();
_metrics.RecordError(ex.GetType().Name);
_logger.LogError(ex, "Error calling external service endpoint {Endpoint}", endpoint);
throw;
}
}
}
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddExternalService(
this IServiceCollection services,
IConfiguration configuration)
{
services.Configure<ExternalServiceOptions>(
configuration.GetSection(ExternalServiceOptions.SectionName));
services.AddOptions<ExternalServiceOptions>()
.Bind(configuration.GetSection(ExternalServiceOptions.SectionName))
.ValidateDataAnnotations()
.ValidateOnStart();
services.AddSingleton<ExternalServiceMetrics>();
services.AddHttpClient<ExternalServiceClient>();
services.AddScoped<ExternalServiceClient>();
return services;
}
}
}
Integration Patterns¶
ASP.NET Core Integration¶
Scenario: Library that integrates with ASP.NET Core applications.
Implementation:
// In Startup.cs or Program.cs
services.AddMyLibrary(configuration);
// Use in controllers
public class MyController : ControllerBase
{
private readonly IMyService _service;
public MyController(IMyService service)
{
_service = service;
}
[HttpGet]
public IActionResult Get()
{
_service.DoWork();
return Ok();
}
}
Microservice Integration¶
Scenario: Library used across multiple microservices.
Benefits:
- Consistent patterns across services
- Shared observability
- Unified configuration
- Standardized error handling
Console Application Integration¶
Scenario: Library used in console applications.
Implementation:
var services = new ServiceCollection();
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
services.AddMyLibrary(configuration);
var serviceProvider = services.BuildServiceProvider();
var myService = serviceProvider.GetRequiredService<IMyService>();
myService.DoWork();
Best Practices by Use Case¶
Utility Libraries¶
- Keep it Simple: Don't add unnecessary dependencies
- Pure Functions: Prefer stateless, pure functions
- Extension Methods: Use extension methods for discoverability
- No Configuration: Avoid configuration for simple utilities
Integration Libraries¶
- Configuration First: Use Options pattern for all settings
- Resilience: Implement retry policies and circuit breakers
- Observability: Include metrics and tracing
- Error Handling: Provide clear error messages and exceptions
Domain Libraries¶
- Clean Architecture: Separate domain logic from infrastructure
- Value Objects: Use value objects for domain concepts
- Immutable Types: Prefer immutable types where possible
- Domain Events: Consider domain events for complex scenarios
Infrastructure Libraries¶
- Abstractions: Provide abstractions, not implementations
- Extension Methods: Use extension methods for registration
- Configuration: Support configuration via Options pattern
- Observability: Include metrics and logging
Conclusion¶
The ConnectSoft Library Template provides a powerful foundation for creating reusable, high-quality libraries in .NET Core. From utility libraries to multi-tenant components, it supports a wide range of use cases, ensuring faster development and robust integration with modern development workflows.
By choosing the right combination of template parameters, you can create libraries that are:
- Minimal: Simple utilities without unnecessary dependencies
- Configurable: Libraries with rich configuration options
- Observable: Libraries with comprehensive monitoring
- Full-Featured: Libraries with all capabilities enabled
Each use case benefits from the template's built-in best practices, testing support, and CI/CD integration.