Convey
The core Convey library provides the foundation for building microservices with .NET. It includes dependency injection extensions, configuration utilities, and application bootstrapping features.
Installation
dotnet add package Convey
Overview
Convey is the foundational package that provides:
- Service registration and configuration - Fluent API for configuring services
- Application bootstrapping - Startup initialization patterns
- Configuration binding - Simplified configuration management
- Service identification - Unique service instance identification
- Decorator pattern support - Service decoration capabilities
Configuration
Configure Convey in your Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddConvey()
.AddInitializer<DatabaseInitializer>()
.AddInitializer<CacheInitializer>();
var app = builder.Build();
app.Run(); // Initializers run automatically via hosted services
App Options
Configure application metadata in appsettings.json:
{
"app": {
"name": "MyService",
"service": "my-service",
"instance": "instance-001",
"version": "1.0.0",
"displayBanner": true,
"displayVersion": true
}
}
Key Features
1. Service Builder Pattern
The IConveyBuilder interface provides a fluent API for configuring services:
public interface IConveyBuilder
{
IServiceCollection Services { get; }
IConfiguration Configuration { get; }
bool TryRegister(string name);
void AddBuildAction(Action<IServiceProvider> action);
IServiceProvider Build();
}
2. Configuration Binding
Simplified configuration binding with the GetOptions<T>() extension:
// Bind configuration section to a POCO
var dbOptions = builder.GetOptions<DatabaseOptions>("database");
// In appsettings.json
{
"database": {
"connectionString": "...",
"timeout": 30
}
}
3. Application Initializers
Implement IInitializer for startup logic:
public class DatabaseInitializer : IInitializer
{
public async Task InitializeAsync()
{
// Database setup logic
await EnsureDatabaseExists();
await RunMigrations();
}
}
// Register the initializer
builder.Services.AddConvey()
.AddInitializer<DatabaseInitializer>();
4. Service Identification
Automatic service instance identification:
public class MyService
{
private readonly IServiceId _serviceId;
public MyService(IServiceId serviceId)
{
_serviceId = serviceId;
}
public void DoWork()
{
var instanceId = _serviceId.Id; // Unique instance identifier
}
}
5. Decorator Pattern Support
Mark services for decoration:
[Decorator]
public class CachedUserService : IUserService
{
private readonly IUserService _userService;
private readonly IMemoryCache _cache;
public CachedUserService(IUserService userService, IMemoryCache cache)
{
_userService = userService;
_cache = cache;
}
public async Task<User> GetUserAsync(int id)
{
var cacheKey = $"user:{id}";
if (_cache.TryGetValue(cacheKey, out User cachedUser))
{
return cachedUser;
}
var user = await _userService.GetUserAsync(id);
_cache.Set(cacheKey, user, TimeSpan.FromMinutes(5));
return user;
}
}
API Reference
Extensions
AddConvey()
public static IConveyBuilder AddConvey(
this IServiceCollection services,
string sectionName = "app",
IConfiguration configuration = null)
Registers Convey core services and initializes the builder.
Parameters:
sectionName- Configuration section name for app options (default: “app”)configuration- Optional configuration instance
Returns: IConveyBuilder for fluent configuration
AddInitializer<T>()
public static IConveyBuilder AddInitializer<TInitializer>(this IConveyBuilder builder)
where TInitializer : class, IInitializer
Registers an application initializer.
Type Parameters:
TInitializer- Type implementingIInitializer
GetOptions<T>()
public static TModel GetOptions<TModel>(this IConfiguration configuration, string sectionName)
where TModel : new()
public static TModel GetOptions<TModel>(this IConveyBuilder builder, string settingsSectionName)
where TModel : new()
Binds a configuration section to a strongly-typed model.
Interfaces
IInitializer
public interface IInitializer
{
Task InitializeAsync();
}
Contract for application startup initializers.
IServiceId
public interface IServiceId
{
string Id { get; }
}
Provides unique service instance identification.
IIdentifiable
public interface IIdentifiable<out T>
{
T Id { get; }
}
Generic interface for identifiable entities.
Usage Examples
Basic Setup
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddConvey("myapp")
.AddInitializer<DatabaseInitializer>();
var app = builder.Build();
app.Run();
Custom Configuration Section
builder.Services.AddConvey("customSection")
.AddInitializer<CustomInitializer>();
Multiple Initializers
builder.Services.AddConvey()
.AddInitializer<DatabaseInitializer>()
.AddInitializer<CacheInitializer>()
.AddInitializer<MessageBrokerInitializer>();
Configuration Binding
public class DatabaseOptions
{
public string ConnectionString { get; set; }
public int CommandTimeout { get; set; } = 30;
public bool EnableRetryOnFailure { get; set; } = true;
}
// In startup
var dbOptions = builder.GetOptions<DatabaseOptions>("database");
builder.Services.AddSingleton(dbOptions);
Best Practices
- Use initializers for setup logic - Keep startup code organized and testable
- Bind configuration to POCOs - Use strongly-typed configuration objects
- Leverage service identification - Use
IServiceIdfor instance tracking - Register services through builder - Use the fluent API for service registration
- Keep app options simple - Focus on essential application metadata
Integration
Convey serves as the foundation for all other Convey packages. Other packages extend the IConveyBuilder with additional functionality:
builder.Services.AddConvey()
.AddWebApi() // From Convey.WebApi
.AddCommandHandlers() // From Convey.CQRS.Commands
.AddEventHandlers() // From Convey.CQRS.Events
.AddRabbitMq() // From Convey.MessageBrokers.RabbitMQ
.AddMongo() // From Convey.Persistence.MongoDB
.AddJwt(); // From Convey.Auth
Troubleshooting
Common Issues
- Banner not displaying
- Ensure
displayBanner: truein configuration - Verify the
nameproperty is set in app options
- Ensure
- Initializers not running
- Check that initializers implement
IInitializer - Ensure initializers are registered with
AddInitializer<T>()
- Check that initializers implement
- Configuration not binding
- Verify section names match between code and configuration
- Ensure configuration file is properly loaded
- Service registration issues
- Use
TryRegister()to avoid duplicate registrations - Check service lifetimes and dependencies
- Use