Skip to content

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

  1. Use Stateless Services for Most Microservices

    // ✅ GOOD - Stateless service for API endpoints
    public class MicroserviceStatelessService : StatelessService
    {
        // Stateless service implementation
    }
    

  2. Implement Health Reporting

    // ✅ GOOD - Report health status
    this.Context.ReportHealth(new StatelessServiceInstanceHealthReport(...));
    

  3. Use Reliable Collections for Stateful Services

    // ✅ GOOD - Use Reliable Collections
    var dictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, string>>("MyDictionary");
    

  4. Handle Cancellation Tokens

    // ✅ GOOD - Respect cancellation tokens
    protected override async Task RunAsync(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            // Work
        }
    }
    

  5. Configure Appropriate Instance Counts

    <!-- ✅ GOOD - Scale based on load -->
    <Parameter Name="MicroserviceStatelessService_InstanceCount" DefaultValue="5" />
    

Don'ts

  1. Don't Store State in Memory for Stateless Services

    // ❌ BAD - State will be lost on restart
    private Dictionary<string, string> cache = new();
    
    // ✅ GOOD - Use external cache (Redis, etc.)
    

  2. Don't Ignore Service Fabric Context

    // ❌ BAD - Not using Service Fabric context
    var port = 8080; // Hardcoded
    
    // ✅ GOOD - Use Service Fabric endpoint
    var endpoint = this.Context.CodePackageActivationContext.GetEndpoint("ServiceEndpoint");
    

  3. Don't Block RunAsync

    // ❌ BAD - Blocking operation
    protected override async Task RunAsync(CancellationToken cancellationToken)
    {
        Thread.Sleep(1000); // Blocks
    }
    
    // ✅ GOOD - Async operation
    protected override async Task RunAsync(CancellationToken cancellationToken)
    {
        await Task.Delay(1000, cancellationToken);
    }
    

  4. 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

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.