Service Fabric in ConnectSoft Microservice Template¶
Purpose & Overview¶
Azure Service Fabric is a distributed systems platform that simplifies packaging, deploying, and managing scalable and reliable microservices. In the ConnectSoft Microservice Template, Service Fabric enables hosting microservices on Azure Service Fabric clusters, providing automatic scaling, health monitoring, rolling upgrades, and built-in reliability patterns.
Service Fabric provides:
- Distributed Application Platform: Complete platform for building and managing microservices
- Automatic Scaling: Scale services up or down based on load
- Health Monitoring: Built-in health monitoring and automatic failover
- Rolling Upgrades: Zero-downtime deployments with automatic rollback
- Stateful Services: Built-in support for stateful microservices with reliable state management
- Service Discovery: Automatic service discovery and load balancing
- High Availability: Automatic failover and replication for reliability
- Multiple Programming Models: Support for Reliable Services, Reliable Actors, and guest executables
Service Fabric Philosophy
Service Fabric is a complete platform for building and managing microservices, providing infrastructure and orchestration capabilities that allow developers to focus on business logic rather than infrastructure concerns. The template integrates Service Fabric while maintaining Clean Architecture principles, ensuring that business logic remains independent of the hosting platform.
Architecture Overview¶
Service Fabric in the Template¶
Service Fabric integrates with the template's architecture:
Service Fabric Cluster
├── Service Fabric Application
│ ├── Stateless Service (StatelessService)
│ │ ├── Service Fabric Communication Listener
│ │ ├── CoreWCF Service Endpoint (optional)
│ │ └── ASP.NET Core Host (optional)
│ └── Stateful Service (StatefulService) - optional
│ ├── Reliable Collections
│ └── Reliable State Manager
│ ↓
Application Layer (ApplicationModel)
│ ├── Dependency Injection
│ └── Service Registration
│ ↓
Domain Model Layer (DomainModel)
│ ├── Processors (Commands/Writes)
│ └── Retrievers (Queries/Reads)
│ ↓
Persistence Layer (PersistenceModel)
│ └── Repository Implementations
Service Fabric Project Structure¶
ConnectSoft.MicroserviceTemplate.ServiceModel.ServiceFabric/
├── Services/
│ ├── MicroserviceStatelessService.cs
│ └── MicroserviceStatefulService.cs (optional)
├── Communication/
│ ├── IServiceFabricCommunicationListener.cs
│ └── ServiceFabricCommunicationListener.cs
└── Extensions/
└── ServiceFabricExtensions.cs
Service Types¶
Service Fabric supports multiple service types:
| Service Type | Use Case | Characteristics |
|---|---|---|
| Stateless Service | Most microservices, API endpoints | No persistent state, scales horizontally, stateless |
| Stateful Service | Services requiring local state | Persistent state, partitioning, replication |
| Reliable Actor | Stateful, single-threaded units | Virtual actors with automatic state management |
Service Fabric Application Model¶
Application and Service Concepts¶
Service Fabric Application: - Contains one or more services - Defines application version and upgrade policies - Manages service lifecycle and dependencies
Service Fabric Service: - Instances of application code - Can be stateless or stateful - Managed by Service Fabric runtime
Stateless Service¶
Purpose: Stateless microservices that don't require persistent local state.
Characteristics: - No persistent state in the service - Scales horizontally by adding instances - Automatic load balancing - Fast startup and shutdown
Example Structure:
// MicroserviceStatelessService.cs
namespace ConnectSoft.MicroserviceTemplate.ServiceModel.ServiceFabric
{
using System;
using System.Fabric;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;
/// <summary>
/// Stateless Service Fabric service hosting the microservice.
/// </summary>
public class MicroserviceStatelessService : StatelessService
{
private readonly IServiceProvider serviceProvider;
public MicroserviceStatelessService(
StatelessServiceContext context,
IServiceProvider serviceProvider)
: base(context)
{
this.serviceProvider = serviceProvider;
}
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[]
{
new ServiceInstanceListener(
context => new ServiceFabricCommunicationListener(
context,
"ServiceEndpoint",
this.serviceProvider))
};
}
protected override async Task RunAsync(CancellationToken cancellationToken)
{
// Background work can be performed here
// This method is called when the service instance is started
while (!cancellationToken.IsCancellationRequested)
{
// Perform periodic work
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}
}
}
}
Stateful Service¶
Purpose: Services that require persistent, replicated state.
Characteristics: - Persistent state stored in Reliable Collections - Automatic replication across replicas - Partitioning for scalability - Strong consistency guarantees
Example Structure:
// MicroserviceStatefulService.cs
namespace ConnectSoft.MicroserviceTemplate.ServiceModel.ServiceFabric
{
using System;
using System.Fabric;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;
using Microsoft.ServiceFabric.Data.Collections;
/// <summary>
/// Stateful Service Fabric service with reliable state management.
/// </summary>
public class MicroserviceStatefulService : StatefulService
{
private readonly IServiceProvider serviceProvider;
private IReliableDictionary<string, string>? stateDictionary;
public MicroserviceStatefulService(
StatefulServiceContext context,
IServiceProvider serviceProvider)
: base(context)
{
this.serviceProvider = serviceProvider;
}
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new[]
{
new ServiceReplicaListener(
context => new ServiceFabricCommunicationListener(
context,
"ServiceEndpoint",
this.serviceProvider))
};
}
protected override async Task RunAsync(CancellationToken cancellationToken)
{
// Initialize reliable collections
this.stateDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, string>>("StateDictionary");
while (!cancellationToken.IsCancellationRequested)
{
// Perform periodic work with state access
using var tx = this.StateManager.CreateTransaction();
var result = await this.stateDictionary.TryGetValueAsync(tx, "Key", TimeSpan.FromSeconds(4), cancellationToken);
// Process state...
await tx.CommitAsync();
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}
}
}
}
Communication Listeners¶
Purpose¶
Communication listeners handle incoming communication for Service Fabric services, supporting multiple communication protocols (HTTP, TCP, WCF/CoreWCF).
Communication Listener Implementation¶
// ServiceFabricCommunicationListener.cs
namespace ConnectSoft.MicroserviceTemplate.ServiceModel.ServiceFabric
{
using System;
using System.Fabric;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.ServiceFabric.Services.Communication.AspNetCore;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
/// <summary>
/// Service Fabric communication listener for ASP.NET Core.
/// </summary>
public class ServiceFabricCommunicationListener : ICommunicationListener
{
private readonly StatelessServiceContext context;
private readonly string endpointName;
private readonly IServiceProvider serviceProvider;
private IWebHost? webHost;
public ServiceFabricCommunicationListener(
StatelessServiceContext context,
string endpointName,
IServiceProvider serviceProvider)
{
this.context = context;
this.endpointName = endpointName;
this.serviceProvider = serviceProvider;
}
public void Abort()
{
this.webHost?.Dispose();
}
public Task CloseAsync(CancellationToken cancellationToken)
{
this.webHost?.Dispose();
return Task.CompletedTask;
}
public Task<string> OpenAsync(CancellationToken cancellationToken)
{
var endpoint = this.context.CodePackageActivationContext.GetEndpoint(this.endpointName);
var uri = new Uri($"{endpoint.Protocol}://{this.context.NodeContext.IPAddressOrFQDN}:{endpoint.Port}");
this.webHost = new WebHostBuilder()
.UseKestrel()
.UseUrls(uri.ToString())
.ConfigureServices(services =>
{
// Configure services from service provider
// Copy registered services from main application
})
.UseStartup<ServiceFabricStartup>()
.Build();
this.webHost.Start();
return Task.FromResult(uri.ToString());
}
}
}
ASP.NET Core Integration¶
Service Fabric services can host ASP.NET Core applications:
// ServiceFabricStartup.cs
namespace ConnectSoft.MicroserviceTemplate.ServiceModel.ServiceFabric
{
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
/// <summary>
/// Startup configuration for Service Fabric hosted ASP.NET Core service.
/// </summary>
public class ServiceFabricStartup
{
public void ConfigureServices(IServiceCollection services)
{
// Register services similar to main application
// Reuse service registration from ApplicationModel
}
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
// Configure endpoints (REST, gRPC, etc.)
});
}
}
}
Service Registration¶
Service Fabric Service Registration¶
Services are registered in the Service Fabric application:
// Program.cs (Service Fabric Application)
namespace ConnectSoft.MicroserviceTemplate.ServiceFabric
{
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.ServiceFabric.Services.Runtime;
/// <summary>
/// Service Fabric application entry point.
/// </summary>
public static class Program
{
public static void Main(string[] args)
{
try
{
ServiceRuntime.RegisterServiceAsync(
"MicroserviceStatelessServiceType",
context => new MicroserviceStatelessService(
context,
CreateServiceProvider(context)))
.GetAwaiter()
.GetResult();
Thread.Sleep(Timeout.Infinite);
}
catch (Exception ex)
{
ServiceEventSource.Current.ServiceHostInitializationFailed(ex);
throw;
}
}
private static IServiceProvider CreateServiceProvider(StatelessServiceContext context)
{
// Create and configure service provider
// Similar to Application startup configuration
var services = new ServiceCollection();
// Register services from ApplicationModel
// Configure logging, options, etc.
return services.BuildServiceProvider();
}
}
}
Dependency Injection Integration¶
Service Fabric services integrate with the template's dependency injection:
// ServiceFabricExtensions.cs
namespace ConnectSoft.MicroserviceTemplate.ServiceModel.ServiceFabric
{
using System.Fabric;
using Microsoft.Extensions.DependencyInjection;
/// <summary>
/// Extension methods for Service Fabric service registration.
/// </summary>
public static class ServiceFabricExtensions
{
/// <summary>
/// Registers Service Fabric services and dependencies.
/// </summary>
public static IServiceCollection AddServiceFabricServices(
this IServiceCollection services,
StatelessServiceContext context)
{
// Register Service Fabric context
services.AddSingleton(context);
services.AddSingleton(context.CodePackageActivationContext);
// Register domain services from ApplicationModel
// Reuse existing service registration logic
return services;
}
}
}
Service Fabric Application Package¶
Application Manifest¶
Service Fabric applications are defined using application and service manifests:
<!-- ApplicationManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest ApplicationTypeName="MicroserviceApplicationType"
ApplicationTypeVersion="1.0.0"
xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<Parameter Name="MicroserviceStatelessService_InstanceCount" DefaultValue="1" />
</Parameters>
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="MicroserviceStatelessServicePkg"
ServiceManifestVersion="1.0.0" />
<ConfigOverrides />
</ServiceManifestImport>
<DefaultServices>
<Service Name="MicroserviceStatelessService">
<StatelessService ServiceTypeName="MicroserviceStatelessServiceType"
InstanceCount="[MicroserviceStatelessService_InstanceCount]">
<SingletonPartition />
</StatelessService>
</Service>
</DefaultServices>
</ApplicationManifest>
Service Manifest¶
<!-- ServiceManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="MicroserviceStatelessServicePkg"
Version="1.0.0"
xmlns="http://schemas.microsoft.com/2011/01/fabric">
<ServiceTypes>
<StatelessServiceType ServiceTypeName="MicroserviceStatelessServiceType" />
</ServiceTypes>
<CodePackage Name="Code" Version="1.0.0">
<EntryPoint>
<ExeHost>
<Program>MicroserviceApplication.exe</Program>
<WorkingFolder>Work</WorkingFolder>
</ExeHost>
</EntryPoint>
</CodePackage>
<ConfigPackage Name="Config" Version="1.0.0" />
<Resources>
<Endpoints>
<Endpoint Name="ServiceEndpoint" Protocol="http" Port="80" Type="Input" />
</Endpoints>
</Resources>
</ServiceManifest>
Service Discovery and Communication¶
Service Fabric Naming Service¶
Service Fabric provides automatic service discovery:
// Service discovery example
using System.Fabric;
using System.Fabric.Description;
using Microsoft.ServiceFabric.Services.Client;
using Microsoft.ServiceFabric.Services.Remoting.Client;
// Resolve service URI
var serviceUri = new Uri("fabric:/MicroserviceApplication/MicroserviceStatelessService");
var servicePartitionResolver = ServicePartitionResolver.GetDefault();
var partition = await servicePartitionResolver.ResolveAsync(
serviceUri,
new ServicePartitionKey(),
CancellationToken.None);
// Create service proxy
var serviceProxy = ServiceProxy.Create<IMicroserviceService>(
serviceUri,
new ServicePartitionKey(),
TargetReplicaSelector.Default,
"ServiceEndpoint");
Service-to-Service Communication¶
Service Fabric services can communicate using:
- Service Remoting: High-performance RPC communication
- HTTP/REST: Standard HTTP communication
- WCF/CoreWCF: SOAP-based communication
- Reliable Messaging: Built-in messaging with Service Bus integration
Health Monitoring¶
Health Reporting¶
Service Fabric services report health status:
// Health reporting example
using System.Fabric;
using System.Fabric.Health;
public class HealthReporter
{
private readonly StatelessServiceContext context;
public HealthReporter(StatelessServiceContext context)
{
this.context = context;
}
public void ReportHealth(HealthState state, string message)
{
var healthInformation = new HealthInformation(
"ServiceHealthSource",
"ServiceHealth",
state)
{
Description = message,
TimeToLive = TimeSpan.FromSeconds(30)
};
var healthReport = new StatelessServiceInstanceHealthReport(
this.context.PartitionId,
this.context.InstanceId,
healthInformation);
this.context.ReportHealth(healthReport);
}
}
Health Checks Integration¶
Integrate with ASP.NET Core health checks:
// Health check registration
services.AddHealthChecks()
.AddCheck<DatabaseHealthCheck>("database")
.AddCheck<ExternalServiceHealthCheck>("external_service");
// Service Fabric health reporting
app.UseHealthChecks("/health", new HealthCheckOptions
{
ResponseWriter = async (context, report) =>
{
// Report health to Service Fabric
var healthReporter = context.RequestServices.GetRequiredService<HealthReporter>();
var state = report.Status == HealthStatus.Healthy
? HealthState.Ok
: HealthState.Error;
healthReporter.ReportHealth(state, report.Status.ToString());
// Return health check response
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonSerializer.Serialize(report));
}
});
Deployment¶
Packaging Service Fabric Application¶
Service Fabric applications are packaged for deployment:
# Package Service Fabric application
Copy-ServiceFabricApplicationPackage `
-ApplicationPackagePath ".\pkg\Debug" `
-ImageStoreConnectionString "fabric:ImageStore" `
-ApplicationPackagePathInImageStore "MicroserviceApplication"
# Register application type
Register-ServiceFabricApplicationType `
-ApplicationPathInImageStore "MicroserviceApplication"
# Create application instance
New-ServiceFabricApplication `
-ApplicationName "fabric:/MicroserviceApplication" `
-ApplicationTypeName "MicroserviceApplicationType" `
-ApplicationTypeVersion "1.0.0" `
-ApplicationParameter @{"MicroserviceStatelessService_InstanceCount"="3"}
Rolling Upgrades¶
Service Fabric supports zero-downtime rolling upgrades:
# Start application upgrade
Start-ServiceFabricApplicationUpgrade `
-ApplicationName "fabric:/MicroserviceApplication" `
-ApplicationTypeVersion "1.0.1" `
-HealthCheckStableDurationSec 60 `
-HealthCheckWaitDurationSec 30 `
-UpgradeDomainTimeoutSec 1200 `
-UpgradeTimeoutSec 3000 `
-FailureAction Rollback `
-Monitored `
-ApplicationParameter @{"MicroserviceStatelessService_InstanceCount"="3"}
Configuration¶
Application Parameters¶
Service Fabric applications use application parameters:
<!-- ApplicationParameters/Local.1Node.xml -->
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Name="fabric:/MicroserviceApplication"
xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<Parameter Name="MicroserviceStatelessService_InstanceCount" Value="1" />
</Parameters>
</Application>
Configuration Package¶
Configuration is stored in configuration packages:
<!-- Settings.xml -->
<?xml version="1.0" encoding="utf-8"?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Section Name="Microservice">
<Parameter Name="MicroserviceName" Value="ConnectSoft.MicroserviceTemplate" />
<Parameter Name="StartupWarmupSeconds" Value="20" />
</Section>
</Settings>
Accessing Configuration:
// Access configuration from Service Fabric
var configurationPackage = this.Context.CodePackageActivationContext.GetConfigurationPackageObject("Config");
var microserviceName = configurationPackage.Settings.Sections["Microservice"]
.Parameters["MicroserviceName"].Value;
Best Practices¶
Do's¶
-
Use Stateless Services for Most Microservices
-
Implement Health Reporting
-
Use Reliable Collections for Stateful Services
-
Handle Cancellation Tokens
-
Configure Appropriate Instance Counts
Don'ts¶
-
Don't Store State in Memory for Stateless Services
-
Don't Ignore Service Fabric Context
-
Don't Block RunAsync
-
Don't Skip Error Handling
// ❌ BAD - No error handling protected override async Task RunAsync(CancellationToken cancellationToken) { ProcessData(); // May throw } // ✅ GOOD - Proper error handling protected override async Task RunAsync(CancellationToken cancellationToken) { try { await ProcessDataAsync(cancellationToken); } catch (Exception ex) { // Log and report health } }
Integration with Template¶
Clean Architecture Compliance¶
Service Fabric services maintain Clean Architecture:
- Service Fabric Layer: Handles hosting and communication
- Application Layer: Business logic orchestration
- Domain Layer: Core business logic
- Persistence Layer: Data access
Service Model Integration¶
Service Fabric services use ServiceModel DTOs:
// Service Fabric service uses ServiceModel
public class MicroserviceStatelessService : StatelessService
{
private readonly IMicroserviceAggregateRootsProcessor processor;
private readonly IMapper mapper;
public async Task<CreateMicroserviceAggregateRootResponse> CreateAsync(
CreateMicroserviceAggregateRootRequest request)
{
// Map ServiceModel request to DomainModel input
var input = this.mapper.Map<CreateMicroserviceAggregateRootInput>(request);
// Execute domain logic
var entity = await this.processor.CreateMicroserviceAggregateRoot(input);
// Map DomainModel output to ServiceModel response
return this.mapper.Map<CreateMicroserviceAggregateRootResponse>(entity);
}
}
Troubleshooting¶
Issue: Service Not Starting¶
Symptoms: Service fails to start or crashes immediately.
Solutions: 1. Check application and service manifests for correct configuration 2. Verify endpoint configuration matches service code 3. Review Service Fabric event logs for errors 4. Ensure all dependencies are packaged correctly
Issue: Service Discovery Not Working¶
Symptoms: Services cannot find each other.
Solutions:
1. Verify service names match exactly (case-sensitive)
2. Check Service Fabric Naming Service is running
3. Use correct service URI format: fabric:/ApplicationName/ServiceName
4. Ensure services are registered and running
Issue: Health Check Failures¶
Symptoms: Service reports unhealthy status.
Solutions: 1. Implement proper health reporting in services 2. Check health check logic for false positives 3. Review health check timeouts and thresholds 4. Verify dependencies (database, external services) are accessible
Related Documentation¶
- Service Model: Service contracts and DTOs
- CoreWCF: SOAP/WCF service implementation
- Clean Architecture: Architectural principles
Summary¶
Service Fabric in the ConnectSoft Microservice Template provides:
- ✅ Distributed Platform: Complete platform for microservices
- ✅ Automatic Scaling: Scale services based on load
- ✅ Health Monitoring: Built-in health monitoring and failover
- ✅ Rolling Upgrades: Zero-downtime deployments
- ✅ Stateful Services: Support for stateful microservices
- ✅ Service Discovery: Automatic service discovery
- ✅ High Availability: Automatic failover and replication
By leveraging Service Fabric, teams can:
- Deploy Reliably: Zero-downtime deployments with automatic rollback
- Scale Automatically: Scale services based on load
- Monitor Health: Built-in health monitoring and reporting
- Manage State: Reliable state management for stateful services
- Discover Services: Automatic service discovery and communication
Service Fabric provides a robust platform for hosting microservices in production, with built-in reliability, scalability, and management capabilities.