# Providers

FlexBase provides unified abstractions for external service providers, enabling you to switch implementations without changing application code. All providers follow consistent patterns for configuration, usage, and error handling.

## Available Providers

### Communication Providers

| Provider Type                                                          | Description                        | Use Cases                                 |
| ---------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------- |
| [**AI Providers**](/data-and-providers/providers/ai-providers.md)      | LLM chat, embeddings, streaming    | RAG, semantic search, content generation  |
| [**Email Providers**](/data-and-providers/providers/e-mail.md)         | Transactional and templated emails | Notifications, password resets, receipts  |
| [**Message Providers**](/data-and-providers/providers/text-message.md) | SMS, push, chat platforms          | Verification codes, alerts, notifications |

### AI Providers

Connect to multiple AI/LLM services with one interface:

| Provider             | Best For               | Features                          |
| -------------------- | ---------------------- | --------------------------------- |
| **Azure OpenAI**     | Enterprise, compliance | GPT-4o, embeddings, SLA           |
| **OpenAI**           | Latest models          | GPT-4o, o1, latest features       |
| **Anthropic Claude** | Long context, analysis | 200K context, reasoning           |
| **Google Gemini**    | Multimodal             | Text, images, competitive pricing |
| **Ollama**           | Local/offline          | Privacy, no API costs             |

```csharp
// Works with ANY AI provider
public class ChatService
{
    private readonly IFlexAIProvider _aiProvider;  // Could be OpenAI, Claude, Ollama, etc.
    
    public async Task<string> AskAsync(string question)
    {
        return await _aiProvider.ChatAsync(question);
    }
}
```

### Email Providers

Send emails through multiple services:

| Provider             | Best For         | Features                       |
| -------------------- | ---------------- | ------------------------------ |
| **Console**          | Development      | No real emails, console output |
| **SMTP**             | Standard servers | Office 365, Gmail, custom      |
| **SMTP + Templates** | Branded emails   | Built-in templates, variables  |
| **SendGrid**         | Transactional    | Delivery tracking, analytics   |

```csharp
// Works with ANY email provider
public class NotificationService
{
    private readonly IFlexEmailProvider _emailProvider;
    
    public async Task SendWelcomeAsync(string email, string name)
    {
        await _emailProvider.SendTemplatedAsync(
            to: email,
            templateId: "welcome",
            templateData: new Dictionary<string, object>
            {
                ["userName"] = name,
                ["loginUrl"] = "https://app.example.com"
            }
        );
    }
}
```

### Message Providers

Send messages across multiple channels:

| Channel         | Use Cases                  | Providers         |
| --------------- | -------------------------- | ----------------- |
| **SMS**         | Verification codes, alerts | Twilio, AWS SNS   |
| **Push**        | Mobile notifications       | Firebase, AWS SNS |
| **WhatsApp**    | Customer support           | Twilio            |
| **Slack/Teams** | Internal alerts            | Native APIs       |
| **Console**     | Development                | Testing           |

```csharp
// Multi-channel messaging
public class AlertService
{
    private readonly IFlexTextMessageProvider _messageProvider;

	public AlertService(IFlexTextMessageProvider messageProvider)
		=> _messageProvider = messageProvider;
    
    public async Task SendAlertAsync(User user, string message)
    {
        // SMS
        if (!string.IsNullOrEmpty(user.PhoneNumber))
        {
            await _messageProvider.SendSmsAsync(user.PhoneNumber, message);
        }
        
        // Push notification
        if (!string.IsNullOrEmpty(user.DeviceToken))
        {
            await _messageProvider.SendPushAsync(
                user.DeviceToken,
                "Alert",
                message
            );
        }
    }
}
```

## Common Patterns

### Automatic Setup via Flex Studio

Providers are automatically added to your application through **Flex Studio**. When you add a provider:

1. **Provider files are created** in `Infrastructure/Providers/{YourApplication}.DataStoreProviders/{Category}/{Provider}/`
2. **NuGet package is referenced** automatically
3. **Default configuration** is added to `Application/EndPoints/{YourApplication}.EndPoint.CommonConfigs/AppSettings/{Category}/{Provider}.json`
4. **README documentation** is included in the provider folder

You can find all provider files, configuration examples, and documentation in the generated infrastructure folder.

### Configuration

Providers use the IOptions pattern. Configuration files are automatically created when you add providers via Flex Studio:

```json
{
    "FlexBase": {
      "AI": {
        "OpenAI": {
          "ApiKey": "<store-in-secrets>",
          "DefaultChatModel": "gpt-4o"
        }
      },
      "Providers": {
        "Email": {
          "Smtp": {
            "Host": "smtp.office365.com",
            "Port": 587,
            "Username": "user@company.com",
            "Password": "<store-in-secrets>"
          }
        },
        "Message": {
          "Console": {
            "DefaultChannel": "Sms"
          }
        }
      }
    }
}
```

Configuration files are located at:

* `Application/EndPoints/{YourApplication}.EndPoint.CommonConfigs/AppSettings/AI/{Provider}.json`
* `Application/EndPoints/{YourApplication}.EndPoint.CommonConfigs/AppSettings/Email/{Provider}.json`
* `Application/EndPoints/{YourApplication}.EndPoint.CommonConfigs/AppSettings/Message/{Provider}.json`

### Dependency Injection

After adding providers via Flex Studio, register only the provider in `Program.cs` (the generated queries/handlers/plugins are auto-wired by Flex):

```csharp
// AI provider
builder.Services.AddFlexOpenAI(builder.Configuration);

// Email provider
builder.Services.AddFlexSmtpEmailProvider(builder.Configuration);

// Message provider
builder.Services.AddFlexConsoleMessageProvider(builder.Configuration);
```

### Multiple Providers

Use keyed services (.NET 8+) for multiple providers:

```csharp
// Register multiple AI providers
builder.Services.AddKeyedSingleton<IFlexAIProvider>("openai", (sp, _) =>
    new FlexOpenAIProvider(Configuration["OpenAI:ApiKey"]!));

builder.Services.AddKeyedSingleton<IFlexAIProvider>("local", (sp, _) =>
    new OllamaProvider());

// Use in service
public class AIService
{
    private readonly IFlexAIProvider _cloud;
    private readonly IFlexAIProvider _local;

    public AIService(
        [FromKeyedServices("openai")] IFlexAIProvider cloud,
        [FromKeyedServices("local")] IFlexAIProvider local)
    {
        _cloud = cloud;
        _local = local;
    }

    public async Task<string> ProcessAsync(string input, bool useLocal = false)
    {
        var provider = useLocal ? _local : _cloud;
        return await provider.ChatAsync(input);
    }
}
```

## Provider-Agnostic Benefits

### 1. Easy Testing

Use console/mock providers during development:

```csharp
// Development
builder.Services.AddFlexConsoleEmailProvider();
builder.Services.AddFlexConsoleMessageProvider();

// Production
builder.Services.AddFlexSmtpEmailProvider();
builder.Services.AddTwilioMessageProvider();
```

### 2. Cost Optimization

Switch providers based on cost or features:

```csharp
public class CostOptimizedService
{
    private readonly IFlexAIProvider _cloudProvider;   // GPT-4o for complex
    private readonly IFlexAIProvider _localProvider;   // Ollama for simple

    public async Task<string> ProcessAsync(string input)
    {
        if (IsComplexQuery(input))
        {
            return await _cloudProvider.ChatAsync(input);
        }
        else
        {
            return await _localProvider.ChatAsync(input);  // Free!
        }
    }
}
```

### 3. Vendor Independence

Avoid vendor lock-in - switch providers with configuration:

```csharp
// Application code stays the same
public class MyService
{
    private readonly IFlexAIProvider _ai;
    private readonly IFlexEmailProvider _email;
    
    // Works with ANY provider implementation
}
```

## Error Handling

All providers follow consistent error patterns:

```csharp
public async Task<bool> SendWithErrorHandlingAsync()
{
    try
    {
        var result = await _provider.SendAsync(message);
        
        if (!result.IsSuccess)
        {
            _logger.LogError("Operation failed: {Error}", result.ErrorMessage);
            
            // Handle specific error codes
            switch (result.ErrorCode)
            {
                case "RATE_LIMITED":
                    await Task.Delay(TimeSpan.FromSeconds(5));
                    return await SendWithErrorHandlingAsync();  // Retry
                
                case "INVALID_INPUT":
                    return false;  // Don't retry
                
                default:
                    throw new Exception(result.ErrorMessage);
            }
        }
        
        return true;
    }
    catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized)
    {
        _logger.LogError("Invalid credentials");
        throw;
    }
}
```

## Best Practices

### 1. Use Console Providers in Development

```csharp
if (builder.Environment.IsDevelopment())
{
    builder.Services.AddFlexConsoleEmailProvider();
    builder.Services.AddFlexConsoleMessageProvider();
    builder.Services.AddSingleton<IFlexAIProvider>(new OllamaProvider());
}
else
{
    builder.Services.AddFlexSmtpEmailProvider(/* production config */);
    builder.Services.AddTwilioMessageProvider(/* production config */);
    builder.Services.AddSingleton<IFlexAIProvider>(new FlexOpenAIProvider(/* production config */));
}
```

### 2. Validate Configuration on Startup

```csharp
// In Program.cs after building
using var scope = app.Services.CreateScope();

var aiProvider = scope.ServiceProvider.GetRequiredService<IFlexAIProvider>();
if (!await aiProvider.TestConnectionAsync())
{
    throw new InvalidOperationException("AI provider not configured correctly");
}

var emailProvider = scope.ServiceProvider.GetRequiredService<IFlexEmailProvider>();
if (!await emailProvider.TestConnectionAsync())
{
    throw new InvalidOperationException("Email provider not configured correctly");
}
```

### 3. Implement Retry Logic

```csharp
public async Task<T> ExecuteWithRetryAsync<T>(
    Func<Task<T>> operation,
    int maxRetries = 3)
{
    for (int attempt = 1; attempt <= maxRetries; attempt++)
    {
        try
        {
            return await operation();
        }
        catch (Exception ex) when (attempt < maxRetries)
        {
            _logger.LogWarning(
                "Attempt {Attempt}/{Max} failed: {Error}",
                attempt, maxRetries, ex.Message
            );
            
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
        }
    }
    
    throw new InvalidOperationException("All retry attempts failed");
}
```

### 4. Monitor and Log

```csharp
public async Task<string> MonitoredChatAsync(string message)
{
    var stopwatch = Stopwatch.StartNew();
    
    try
    {
        var response = await _aiProvider.ChatAsync(message);
        
        _logger.LogInformation(
            "AI chat completed in {ElapsedMs}ms. Provider: {Provider}, Tokens: {Tokens}",
            stopwatch.ElapsedMilliseconds,
            _aiProvider.Provider,
            response.Usage?.TotalTokens
        );
        
        return response.Message.Content;
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "AI chat failed after {ElapsedMs}ms", stopwatch.ElapsedMilliseconds);
        throw;
    }
}
```

## Integration Examples

### AI + Vector Store (RAG)

```csharp
public class RAGService
{
    private readonly IFlexAIProvider _aiProvider;
    private readonly IFlexVectorStore _vectorStore;

    public async Task<string> AskAsync(string question)
    {
        // 1. Generate embedding
        var queryEmbedding = await _aiProvider.EmbedAsync(question);

        // 2. Search vector store
        var results = await _vectorStore.SearchAsync(queryEmbedding, topK: 5);

        // 3. Build context
        var context = string.Join("\n\n", results.Select(r => r.Content));

        // 4. Get AI response
        return await _aiProvider.ChatAsync($"Context: {context}\n\nQuestion: {question}");
    }
}
```

### Email + Message (Multi-Channel Notifications)

```csharp
public class NotificationService
{
    private readonly IFlexEmailProvider _emailProvider;
    private readonly IFlexTextMessageProvider _messageProvider;

    public NotificationService(IFlexEmailProvider emailProvider, IFlexTextMessageProvider messageProvider)
    {
        _emailProvider = emailProvider;
        _messageProvider = messageProvider;
    }

    public async Task NotifyUserAsync(User user, string message)
    {
        var tasks = new List<Task>();

        // Email
        if (!string.IsNullOrEmpty(user.Email))
        {
            tasks.Add(_emailProvider.SendAsync(user.Email, "Notification", message));
        }

        // SMS
        if (!string.IsNullOrEmpty(user.PhoneNumber))
        {
            tasks.Add(_messageProvider.SendSmsAsync(user.PhoneNumber, message));
        }

        // Push
        if (!string.IsNullOrEmpty(user.DeviceToken))
        {
            tasks.Add(_messageProvider.SendPushAsync(user.DeviceToken, "Notification", message));
        }

        await Task.WhenAll(tasks);
    }
}
```

## Advanced Usage Examples

### AI Providers

AI providers enable seamless integration with various LLM services. Below is an example of using an AI provider for generating responses:

```csharp
public class AIResponseService
{
    private readonly IFlexAIProvider _aiProvider;

    public AIResponseService(IFlexAIProvider aiProvider)
    {
        _aiProvider = aiProvider;
    }

    public async Task<string> GenerateResponseAsync(string prompt)
    {
        return await _aiProvider.ChatAsync(prompt);
    }
}
```

### Email Providers

Email providers support sending templated and transactional emails. Below is an example:

```csharp
public class EmailNotificationService
{
    private readonly IFlexEmailProvider _emailProvider;

    public EmailNotificationService(IFlexEmailProvider emailProvider)
    {
        _emailProvider = emailProvider;
    }

    public async Task SendPasswordResetAsync(string email, string resetLink)
    {
        await _emailProvider.SendTemplatedAsync(
            to: email,
            templateId: "password_reset",
            templateData: new Dictionary<string, object>
            {
                ["resetLink"] = resetLink
            }
        );
    }
}
```

### Message Providers

Message providers allow sending SMS, push notifications, and more. Below is an example:

```csharp
public class SmsService
{
    private readonly IFlexTextMessageProvider _messageProvider;

    public SmsService(IFlexTextMessageProvider messageProvider)
    {
        _messageProvider = messageProvider;
    }

    public async Task SendVerificationCodeAsync(string phoneNumber, string code)
    {
        await _messageProvider.SendAsync(new FlexTextMessage
        {
            Channel = FlexMessageChannel.Sms,
			Recipients = new List<string> { phoneNumber },
            Content = $"Your verification code is {code}."
        });
    }
}
```

## See Also

* [Data Stores](/data-and-providers/data-stores.md) - Vector, search, document stores
* [Relational Databases](/data-and-providers/relational-db.md) - EF Core and Dapper
* [AI Providers Details](/data-and-providers/providers/ai-providers.md) - Complete AI provider documentation
* [Email Providers Details](/data-and-providers/providers/e-mail.md) - Complete email provider documentation
* [Message Providers Details](/data-and-providers/providers/text-message.md) - Complete message provider documentation


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.flexbase.in/data-and-providers/providers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
