Skip to content

Code Documentation

Holger Imbery edited this page Sep 19, 2025 · 6 revisions

Code Documentation

Technical documentation of the ACSforMCS codebase, including architecture, key components, data models, and implementation details.

Architecture Overview

ACSforMCS is built as a .NET 9 web application that bridges Azure Communication Services (ACS) telephony with Microsoft Copilot Studio agents. The application follows a modular architecture with clear separation of concerns.

High-Level Architecture

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Phone Call    │───▶│  Azure Comm     │───▶│   ACSforMCS     │
│                 │    │  Services        │    │   Web App       │
└─────────────────┘    └──────────────────┘    └─────────────────┘
                              │                         │
                              ▼                         ▼
                       ┌──────────────────┐    ┌─────────────────┐
                       │   Event Grid     │    │   Azure Key     │
                       │   Webhooks       │    │   Vault         │
                       └──────────────────┘    └─────────────────┘
                                                        │
                                                        ▼
                                               ┌─────────────────┐
                                               │ Copilot Studio  │
                                               │ (DirectLine)    │
                                               └─────────────────┘

Request Flow

  1. Incoming Call: Phone call triggers ACS to send webhook notification
  2. Event Processing: ACSforMCS receives EventGrid notification via /api/incomingCall
  3. Caller ID Extraction: CallerInfoExtractor processes event data to identify caller and callee
  4. Call Answering: Application answers call with transcription and AI capabilities
  5. Bot Integration: DirectLine conversation established with Copilot Studio
  6. Caller Personalization: Caller information sent to bot for personalized responses
  7. Real-time Processing: Bidirectional audio/text processing via WebSockets
  8. Response Delivery: TTS conversion and audio playback to caller

Project Structure

ACSforMCS/
├── Program.cs                     # Application entry point and configuration
├── AgentActivity.cs               # Bot activity representation
├── CallContext.cs                 # Call session context
├── Conversation.cs                # DirectLine conversation model
├── Constants.cs                   # Application constants
├── Configuration/
│   └── AppSettings.cs            # Application configuration models
├── Services/
│   ├── CallAutomationService.cs  # Core call processing logic
│   └── CallerInfoExtractor.cs    # Caller ID/Callee ID extraction utilities
├── Middleware/
│   └── WebSocketMiddleware.cs    # WebSocket handling for real-time audio
├── HealthChecks/
│   └── DirectLineHealthCheck.cs  # Health monitoring for DirectLine API
├── Properties/
│   └── launchSettings.json       # Development launch configuration
└── scripts/                      # PowerShell deployment automation

Core Components

Program.cs - Application Bootstrap

The main entry point configures the entire application pipeline:

Key Responsibilities:

  • Azure Key Vault integration for secure configuration
  • Environment-specific service registration
  • HTTP pipeline configuration
  • Health check endpoints
  • API documentation (Swagger) in Development mode
  • Caller ID/Callee ID extraction and bot personalization

Configuration Sources:

  1. appsettings.json - Base configuration
  2. Azure Key Vault - Sensitive values (connection strings, secrets)
  3. Environment Variables - Runtime overrides (VS_TUNNEL_URL for dev tunnels)
  4. .NET User Secrets - Local development configuration

Environment Modes:

  • Development: Full monitoring, Swagger UI, detailed logging
  • Production: Minimal endpoints, optimized performance, security hardening

Caller ID Processing:

  • Extracts caller and callee information from EventGrid incoming call events
  • Sends caller information to Copilot Studio for personalized bot responses
  • Supports configurable caller ID processing and detailed logging
  • Handles multiple caller ID formats (PSTN, ACS users, international numbers)

CallAutomationService - Core Business Logic

Primary service handling all call processing and bot integration:

Key Capabilities:

  • DirectLine conversation management
  • Real-time WebSocket communication with bots
  • Speech-to-text and text-to-speech processing
  • Call transfer orchestration
  • Error handling and graceful degradation

Public Methods:

// DirectLine conversation lifecycle
Task<Conversation?> StartConversationAsync()
Task<Conversation?> StartConversationWithTokenAsync()

// Message processing
Task SendMessageAsync(string conversationId, string message)

// Real-time bot communication
Task ListenToBotWebSocketAsync(string streamUrl, CallConnection callConnection, CancellationToken cancellationToken)

// Call management
Task<bool> AnnounceAndTransferCallAsync(CallConnection callConnection, CallMedia callMedia, string phoneNumber, string transferMessage, CancellationToken cancellationToken)

// Audio processing
Task PlayToAllAsync(CallMedia callMedia, string textToPlay, CancellationToken cancellationToken)

// Utility methods
string GetCallbackUri()
string GetTranscriptionTransportUri()
void CleanupCall(string correlationId)

Bot Activity Processing:

  • Message Activities: Convert to speech and play to caller
  • Transfer Activities: Parse transfer commands and initiate call transfers
  • Error Activities: Handle errors gracefully with user-friendly fallbacks
  • End of Conversation: Terminate calls appropriately

WebSocketMiddleware - Real-time Communication

Handles WebSocket connections for streaming audio transcription from Azure Communication Services:

Functionality:

  • WebSocket upgrade handling for /ws path
  • Audio stream processing and correlation ID extraction
  • Integration with speech recognition services
  • Message routing to appropriate bot conversations

WebSocket Headers:

  • x-ms-call-correlation-id: Links WebSocket to specific call context
  • Standard WebSocket upgrade headers

CallerInfoExtractor - Caller Identification Service

Utility service for extracting and processing caller identification information from Azure Communication Services EventGrid events:

Key Capabilities:

  • Robust JSON parsing of EventGrid IncomingCall events
  • Multiple extraction strategies with fallback mechanisms
  • Phone number normalization and format validation
  • Caller type detection (PSTN, ACS users, international)
  • Privacy-aware handling of blocked or private caller IDs
  • Thread-safe caller information processing

Extraction Features:

// Primary extraction method with comprehensive error handling
CallerInfo ExtractCallerInfo(EventGridEvent eventGridEvent, string correlationId, ILogger logger)

// Caller ID status enumeration
public enum CallerIdStatus
{
    Available,           // Full phone number and display name
    PartiallyAvailable,  // Some identifier present
    Blocked,            // Caller intentionally blocked ID
    Unavailable,        // Technical issue prevented retrieval
    International,      // International number with format issues
    Internal            // Internal ACS user
}

Data Quality Assessment:

  • Complete: Both caller and callee information available
  • Partial: Either caller or callee information available
  • Minimal: No caller/callee information available

Bot Integration:

  • Sends caller information to Copilot Studio using simple pipe-delimited format
  • Format: CALLER_ID=xxx|CALLEE_ID=yyy|CALLER_NAME=zzz
  • Enables bot personalization based on caller identification
  • Supports anonymous callers with graceful fallbacks

Configuration Management

AppSettings.cs

Central configuration model with all required settings:

public class AppSettings
{
    public string AcsConnectionString { get; set; }      // Azure Communication Services
    public string CognitiveServiceEndpoint { get; set; } // Azure Speech Services
    public string AgentPhoneNumber { get; set; }         // Transfer target number
    public string DirectLineSecret { get; set; }         // Bot authentication
    public string BaseUri { get; set; }                  // Application URL
    public string DefaultTransferNumber { get; set; }    // Fallback transfer
}

CallerIdOptions.cs

Caller identification and personalization configuration:

public class CallerIdOptions  
{
    public bool EnableCallerIdProcessing { get; set; } = true;    // Enable/disable caller ID extraction
    public bool EnableDetailedLogging { get; set; } = true;      // Detailed caller ID logging
}

VoiceOptions.cs

Voice and speech recognition optimization settings:

public class VoiceOptions  
{
    public string VoiceName { get; set; } = "en-US-NancyNeural";
    public string Language { get; set; } = "en-US";
    public int InitialSilenceTimeoutMs { get; set; } = 800;    // Fast response
    public int EndSilenceTimeoutMs { get; set; } = 1500;      // Quick detection
    public bool EnableFastMode { get; set; } = true;          // Performance optimization
    public string SpeechRate { get; set; } = "fast";          // TTS speed
}

Data Models

CallContext.cs

Represents the relationship between an ACS call and its bot conversation, enhanced with comprehensive caller identification:

public class CallContext
{
    // Core call identifiers
    public string? CorrelationId { get; set; }    // ACS call identifier
    public string? ConversationId { get; set; }   // DirectLine conversation ID
    
    // Caller identification properties
    public string? CallerId { get; set; }         // Phone number or identifier of caller
    public string? CalleeId { get; set; }         // Phone number that was called
    public string? CallerDisplayName { get; set; } // Display name for caller ID
    public string CallerType { get; set; } = "unknown"; // Type of caller (pstn, acs, raw, unknown)
    public bool HasCallerInfo { get; set; } = false;    // Reliable caller info available
    public bool HasCalleeInfo { get; set; } = false;    // Reliable callee info available
    
    // Session management
    public DateTimeOffset CallStartTime { get; set; }   // Call initiation timestamp
    public DateTimeOffset? LastActivity { get; set; }   // Last message activity
    public bool IsActive { get; set; } = true;          // Call is currently active
    public int MessageCount { get; set; } = 0;          // Messages processed
    
    // Thread safety
    public readonly object Lock = new object();         // Synchronization object
}

Enhanced Methods:

// Thread-safe activity tracking
void UpdateLastActivity()

// Data quality assessment
string GetDataQuality() // Returns: "complete", "partial", or "minimal"

// Safe caller information access
(string CallerId, string CalleeId, string CallerDisplayName, bool HasCallerInfo, bool HasCalleeInfo, string CallerType) GetCallerInfoSnapshot()

Usage:

  • Stored in ConcurrentDictionary<string, CallContext> for thread-safe access
  • Key: CorrelationId from ACS
  • Enables routing transcribed speech to correct bot conversation
  • Facilitates cleanup when calls end
  • Provides caller identification context for bot personalization

AgentActivity.cs

Standardized representation of bot responses from DirectLine:

public class AgentActivity
{
    public string? Type { get; set; }    // Activity type (message, transfer, error)
    public string? Text { get; set; }    // Activity content/payload
}

Activity Types:

  • "message": Regular text responses for speech synthesis
  • "transfer": Call transfer commands (format: TRANSFER:+phone:message)
  • "error": Error responses (filtered from user playback)
  • "endOfConversation": Conversation termination signals

Conversation.cs

DirectLine conversation session information:

public class Conversation
{
    public string? ConversationId { get; set; }      // Unique conversation identifier
    public string? Token { get; set; }               // Optional authentication token
    public string? StreamUrl { get; set; }           // WebSocket URL for real-time communication
    public string? ReferenceGrammarId { get; set; }  // Optional speech recognition optimization
}

API Endpoints

Core Business Endpoints

GET /

  • Basic service health check
  • Returns: "Hello Azure Communication Services, here is Copilot Studio!"

POST /api/incomingCall

  • EventGrid webhook for incoming call notifications
  • Handles EventGrid subscription validation
  • Extracts caller ID and callee ID from event data
  • Sends caller information to Copilot Studio for personalization
  • Initiates call answering with transcription and bot integration

POST /api/calls/{contextId}

  • CloudEvent webhook for call automation events
  • Processes call lifecycle events (connected, disconnected, transfer events)
  • Manages bot communication and audio playback

Development Mode Monitoring Endpoints

Available only in Development mode with API key authentication:

GET /health/calls

  • Active call monitoring and statistics
  • Returns concurrent call counts and performance metrics

GET /health/metrics

  • System performance metrics (memory, CPU, threads)
  • Application-specific metrics (call capacity, performance)

GET /health/config

  • Configuration validation status
  • Security settings verification

GET /swagger

  • Interactive API documentation
  • Comprehensive endpoint testing interface

Security Implementation

Authentication and Authorization

API Key Protection:

// All monitoring endpoints require X-API-Key header
if (!context.Request.Headers.ContainsKey("X-API-Key") ||
    context.Request.Headers["X-API-Key"] != healthCheckApiKey)
{
    context.Response.StatusCode = 401;
    return;
}

Azure Key Vault Integration:

builder.Configuration.AddAzureKeyVault(
    new Uri(keyVaultEndpoint),
    new DefaultAzureCredential());

Managed Identity:

  • System-assigned managed identity for Key Vault access
  • RBAC-based permissions instead of access policies
  • No stored credentials in application code

Environment-Specific Security

Development Mode:

  • All endpoints secured with API key authentication
  • Swagger UI with authentication requirements
  • Detailed logging for debugging

Production Mode:

  • Minimal endpoint exposure (only business endpoints)
  • No debug information leakage
  • Optimized logging for performance
  • HSTS and security headers

Performance Optimizations

HTTP Client Configuration

DirectLine API Client:

.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler()
{
    MaxConnectionsPerServer = 10,    // Connection pooling
    UseCookies = false,              // Performance optimization
    UseProxy = false                 // Skip proxy detection
})
.AddTransientHttpErrorPolicy(policy => 
    policy.WaitAndRetryAsync(
        retryCount: 3,
        sleepDurationProvider: retryAttempt => 
        {
            var baseDelay = TimeSpan.FromSeconds(Math.Pow(2, retryAttempt));
            var jitter = TimeSpan.FromMilliseconds(Random.Shared.Next(0, 1000));
            return baseDelay.Add(jitter);  // Prevent thundering herd
        }));

Speech Recognition Optimization

Fast Mode Configuration:

TranscriptionOptions = new TranscriptionOptions(voiceOptions.Language)
{
    TransportUri = callAutomationService.GetTranscriptionTransportUri(),
    TranscriptionTransport = StreamingTransport.Websocket,
    EnableIntermediateResults = voiceOptions.EnableFastMode,  // Real-time results
    StartTranscription = true
}

Optimized Timing Settings:

  • InitialSilenceTimeoutMs: 800 - Quick response start
  • EndSilenceTimeoutMs: 1500 - Fast speech detection
  • SpeechRate: "fast" - Accelerated TTS playback

Memory Management

Call Context Storage:

// Thread-safe concurrent dictionary for call contexts
ConcurrentDictionary<string, CallContext> callStore

// Automatic cleanup on call disconnection
callAutomationService.CleanupCall(correlationId);

Resource Cleanup:

  • Cancellation tokens for WebSocket operations
  • Proper disposal of HTTP clients and connections
  • Memory cache for SSML templates

Caller ID and Personalization Features

ACSforMCS includes comprehensive caller identification and personalization capabilities that extract caller information from incoming call events and provide it to Copilot Studio for enhanced customer experiences.

Feature Overview

Caller Information Extraction:

  • Extracts caller ID, callee ID, and display names from EventGrid IncomingCall events
  • Supports multiple caller types: PSTN phone numbers, ACS users, international calls
  • Handles privacy scenarios like blocked or unavailable caller IDs
  • Provides data quality assessment for personalization decisions

Bot Personalization:

  • Sends caller information to Copilot Studio using simple pipe-delimited format
  • Enables personalized greetings and context-aware responses
  • Supports both identified and anonymous callers gracefully
  • Integrates with Power FX formulas for dynamic bot behavior

Implementation Architecture

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Incoming      │───▶│   EventGrid      │───▶│ CallerInfo      │
│   Call Event    │    │   Webhook        │    │ Extractor       │
└─────────────────┘    └──────────────────┘    └─────────────────┘
                              │                         │
                              ▼                         ▼
                       ┌──────────────────┐    ┌─────────────────┐
                       │   Call Context   │    │   Bot Message   │
                       │   Enhancement    │    │   Generation    │
                       └──────────────────┘    └─────────────────┘
                                                        │
                                                        ▼
                                               ┌─────────────────┐
                                               │ Copilot Studio  │
                                               │ Personalization │
                                               └─────────────────┘

Caller Information Data Model

CallerInfo Class:

public class CallerInfo
{
    public string CorrelationId { get; set; }           // Call correlation identifier
    public string CallerId { get; set; }                // Caller's phone number or ID
    public string CalleeId { get; set; }                // Called number (destination)
    public string CallerDisplayName { get; set; }       // Caller's display name
    public string CallerType { get; set; }              // Type: pstn, acs, raw, unknown
    public bool HasCallerInfo { get; set; }             // Reliable caller data available
    public bool HasCalleeInfo { get; set; }             // Reliable callee data available
    public CallerIdStatus Status { get; set; }          // Extraction status
    public DateTimeOffset ExtractedAt { get; set; }     // Extraction timestamp
    public string DataQuality { get; }                  // Quality: complete, partial, minimal
}

CallerIdStatus Enumeration:

  • Available: Full phone number and display name present
  • PartiallyAvailable: Some identifier present but not standard format
  • Blocked: Caller intentionally blocked their ID
  • Unavailable: Technical issue prevented ID retrieval
  • International: International number with potential format challenges
  • Internal: Internal Azure Communication Services user

Configuration Options

CallerIdOptions Settings:

public class CallerIdOptions
{
    public bool EnableCallerIdProcessing { get; set; } = true;    // Master enable/disable switch
    public bool EnableDetailedLogging { get; set; } = true;      // Detailed extraction logging
}

Configuration Usage:

{
  "CallerId": {
    "EnableCallerIdProcessing": true,    // Set to false to treat all calls as anonymous
    "EnableDetailedLogging": true        // Enable detailed caller ID extraction logging
  }
}

Extraction Process

1. EventGrid Event Processing:

// Extract caller information from incoming call event
var callerInfo = callerIdOptions.EnableCallerIdProcessing 
    ? CallerInfoExtractor.ExtractCallerInfo(eventGridEvent, tempCorrelationId, logger)
    : CallerInfoExtractor.CallerInfo.CreateDefault(tempCorrelationId);

2. Multi-Strategy Extraction:

  • Primary Strategy: Parse structured EventGrid data fields
  • Secondary Strategy: Raw JSON property extraction with fallbacks
  • Tertiary Strategy: Text-based parsing of identifiers
  • Default Strategy: Create anonymous caller context

3. Phone Number Normalization:

  • Converts various phone number formats to consistent representation
  • Handles international numbers, domestic formats, and ACS identifiers
  • Preserves original format while providing normalized versions

4. Data Quality Assessment:

  • Complete: Both caller and callee information successfully extracted
  • Partial: Either caller or callee information available
  • Minimal: No identification information available (anonymous call)

Bot Integration Process

1. Caller Information Transmission:

// Send caller information as first bot message
var callerMessage = $"CALLER_ID={callContext.CallerId}|CALLEE_ID={callContext.CalleeId}|CALLER_NAME={callContext.CallerDisplayName}";
await callAutomationService.SendMessageAsync(conversation.ConversationId!, callerMessage);

2. Message Format:

  • Format: CALLER_ID=value|CALLEE_ID=value|CALLER_NAME=value
  • Example: CALLER_ID=+1234567890|CALLEE_ID=+1987654321|CALLER_NAME=John Smith
  • Anonymous: CALLER_ID=Unknown|CALLEE_ID=Unknown|CALLER_NAME=Anonymous Caller

3. Copilot Studio Processing:

// Power FX formula to parse caller information
Set(
    CallerData,
    Split(Trigger.Text, "|")
);

Set(
    CallerID,
    Last(Split(First(Filter(CallerData, StartsWith(Value, "CALLER_ID="))).Value, "=")).Value
);

Set(
    CallerName,
    Last(Split(First(Filter(CallerData, StartsWith(Value, "CALLER_NAME="))).Value, "=")).Value
);

Personalization Examples

Personalized Greeting:

// When caller information is available:
"Hello John Smith, thank you for calling from 555-123-4567. How can I help you today?"

// When caller is anonymous:
"Hello, thank you for calling. How can I help you today?"

// When partial information is available:
"Hello caller from 555-123-4567, how can I help you today?"

Department Routing:

// Based on called number (CalleeId):
"+1800SUPPORT" → "You've reached our technical support line..."
"+1800SALES" → "Welcome to our sales department..."
"+1800BILLING" → "You've called our billing department..."

Privacy and Security Considerations

Privacy-Aware Processing:

  • Respects caller privacy preferences and blocked IDs
  • Handles "Private Number" and "Blocked" caller scenarios gracefully
  • Provides appropriate messaging for privacy-conscious callers
  • Does not store sensitive caller information beyond call duration

Security Measures:

  • Caller information is processed in-memory only
  • No persistent storage of caller identification data
  • Thread-safe access to caller information
  • Cleanup of caller data when calls end

Compliance Features:

  • Configurable caller ID processing (can be disabled entirely)
  • Detailed logging for audit trails (when enabled)
  • Support for regulatory requirements around caller identification

Performance Optimizations

Efficient Processing:

  • Single-pass JSON parsing with multiple extraction attempts
  • Thread-safe concurrent access to caller information
  • Memory-efficient string processing and normalization
  • Fast fallback mechanisms for extraction failures

Caching Strategy:

  • Caller information cached in CallContext for call duration
  • No cross-call caching to ensure privacy
  • Automatic cleanup when calls disconnect

Monitoring and Analytics

Extraction Success Metrics:

// Log extraction results for monitoring
logger.LogInformation("Extracted caller information - Status: {Status}, CallerId: {CallerId}, CalleeId: {CalleeId}, Quality: {Quality}",
    callerInfo.Status, callerInfo.CallerId, callerInfo.CalleeId, callerInfo.DataQuality);

Data Quality Tracking:

  • Success/failure rates for caller ID extraction
  • Distribution of caller types (PSTN, ACS, International)
  • Data quality metrics (complete, partial, minimal)
  • Performance metrics for extraction processing time

Troubleshooting

Common Issues:

  1. No Caller Information: Check EventGrid event payload format
  2. Extraction Failures: Enable detailed logging to see parsing attempts
  3. Bot Not Personalizing: Verify Power FX formulas in Copilot Studio
  4. International Number Issues: Check phone number normalization logic

Debug Configuration:

{
  "CallerId": {
    "EnableCallerIdProcessing": true,
    "EnableDetailedLogging": true     // Enable for troubleshooting
  },
  "Logging": {
    "LogLevel": {
      "ACSforMCS.Services.CallerInfoExtractor": "Debug"  // Detailed extraction logs
    }
  }
}

Error Handling

Graceful Degradation

Bot Communication Failures:

try
{
    conversation = await callAutomationService.StartConversationAsync();
}
catch (HttpRequestException ex) when (ex.Message.Contains("403"))
{
    // Fallback to token-based authentication
    conversation = await callAutomationService.StartConversationWithTokenAsync();
}

Audio Playback Error Handling:

try
{
    await PlayToAllAsync(callConnection.GetCallMedia(), agentActivity.Text, cancellationToken);
}
catch (Exception ex)
{
    _logger.LogWarning(ex, "Could not play audio, call may have ended: {Message}", ex.Message);
    // Continue processing - don't fail entire call for individual playback issues
}

User-Friendly Error Messages

Error Message Filtering:

// Filter out technical errors from user playback
if (agentActivity.Text.Contains("An error has occurred") || 
    agentActivity.Text.Contains("error has occurred"))
{
    _logger.LogWarning("Filtered out generic error message from bot: {ErrorText}", agentActivity.Text);
    continue; // Don't play technical errors to users
}

Health Monitoring

DirectLineHealthCheck.cs

Monitors DirectLine API connectivity:

public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
    try
    {
        // Test DirectLine API accessibility
        var response = await _httpClient.GetAsync("", cancellationToken);
        
        return response.IsSuccessStatusCode ? 
            HealthCheckResult.Healthy("DirectLine API is accessible") :
            HealthCheckResult.Unhealthy($"DirectLine API returned {response.StatusCode}");
    }
    catch (Exception ex)
    {
        return HealthCheckResult.Unhealthy("DirectLine API is unreachable", ex);
    }
}

Custom Telemetry

Application Insights Integration:

  • Custom event tracking for call success/failure rates
  • Performance counters for speech processing times
  • Dependency tracking for DirectLine API calls

Metrics Collection:

  • Active call counts
  • Average call duration
  • Speech recognition accuracy
  • Bot response times

Deployment Considerations

Container Readiness

Health Check Endpoints:

  • Kubernetes/Docker health probes supported
  • Multiple health check levels (basic, detailed, specific services)

Environment Variables:

  • Support for container orchestration configuration
  • Override capabilities for all Key Vault settings

Scaling Considerations

Stateless Design:

  • Call contexts stored in memory (consider Redis for multi-instance)
  • No session affinity requirements
  • Horizontal scaling capabilities

Resource Limits:

  • Concurrent call capacity monitoring
  • Memory usage tracking
  • Auto-scaling integration points

Development Patterns

Dependency Injection

Service Registration:

// Singleton services for shared resources
builder.Services.AddSingleton<CallAutomationClient>(connectionString: appSettings.AcsConnectionString);
builder.Services.AddSingleton<ConcurrentDictionary<string, CallContext>>();
builder.Services.AddSingleton<CallAutomationService>();

// HTTP clients with retry policies
builder.Services.AddHttpClient("DirectLine", client => { /* configuration */ })
    .AddTransientHttpErrorPolicy(/* retry policy */);

Configuration Patterns

Options Pattern:

builder.Services.Configure<AppSettings>(builder.Configuration);
builder.Services.Configure<VoiceOptions>(builder.Configuration.GetSection("Voice"));
builder.Services.Configure<CallerIdOptions>(builder.Configuration.GetSection("CallerId"));

// Usage in services
public class CallAutomationService
{
    private readonly AppSettings _appSettings;
    private readonly CallerIdOptions _callerIdOptions;
    
    public CallAutomationService(IOptions<AppSettings> appSettings, IOptions<CallerIdOptions> callerIdOptions)
    {
        _appSettings = appSettings.Value;
        _callerIdOptions = callerIdOptions.Value;
    }
}

Logging Patterns

Structured Logging:

_logger.LogInformation("📞 Call connected - Active calls: {ActiveCallCount}, New call correlation ID: {CorrelationId}", 
    callStore.Count, correlationId);

Performance Logging:

  • Environment-specific log levels
  • Correlation ID tracking
  • Performance metrics logging

Testing Strategies

Unit Testing Considerations

Testable Components:

  • CallAutomationService business logic
  • Configuration validation
  • Health check implementations
  • Data model serialization

Mocking Points:

  • HTTP clients for DirectLine API
  • Azure Communication Services clients
  • Configuration providers

Integration Testing

Test Scenarios:

  • End-to-end call flow simulation
  • DirectLine API integration
  • Azure Key Vault configuration retrieval
  • Health endpoint validation

Load Testing

Performance Benchmarks:

  • Concurrent call capacity
  • Speech processing latency
  • Memory usage under load
  • DirectLine API response times

Troubleshooting Guide

Common Issues

Configuration Problems:

// Validate all required settings at startup
ArgumentNullException.ThrowIfNullOrEmpty(appSettings.AcsConnectionString);
ArgumentNullException.ThrowIfNullOrEmpty(appSettings.DirectLineSecret);

DirectLine Authentication:

// Multiple authentication fallback strategies
try
{
    return await StartConversationAsync();
}
catch (HttpRequestException ex) when (ex.Message.Contains("403"))
{
    return await StartConversationWithTokenAsync();
}

Debugging Tools

Development Mode Features:

  • Comprehensive Swagger documentation
  • Real-time call monitoring endpoints
  • Configuration validation endpoints
  • Detailed application logging

Production Monitoring:

  • Application Insights integration
  • Azure Monitor compatibility
  • Custom telemetry collection

Extension Points

Custom Voice Processing

SSML Customization:

  • Custom SSML template generation
  • Voice personality configuration
  • Language-specific optimizations

Bot Framework Integration

Activity Processing:

  • Custom activity type handlers
  • Enhanced transfer logic
  • Multi-bot support capabilities

Azure Services Integration

Additional Cognitive Services:

  • Language understanding (LUIS)
  • QnA Maker integration
  • Custom speech models

Security Best Practices

Configuration Security

  • Never store secrets in source code
  • Use Azure Key Vault for all sensitive data
  • Implement proper RBAC for Key Vault access
  • Regular secret rotation capabilities

Runtime Security

  • API key authentication for monitoring endpoints
  • HTTPS enforcement for all communication
  • Proper input validation and sanitization
  • Error message filtering to prevent information disclosure

Network Security

  • Restrict inbound traffic to required endpoints only
  • Use Azure Private Endpoints for internal communication
  • Implement proper firewall rules
  • Monitor and log all API access

Next Steps

External Resources

ACSforMCS Documentation

Getting Started

Advanced

Development

Quick Actions

External Links

Demo

Clone this wiki locally