Skip to content

GridLab Elasticsearch Client Provider - Skills Guide

Skill Type: Framework Integration
Technology Stack: .NET, ABP Framework, Elasticsearch
Complexity Level: Intermediate
Last Updated: 2024


📋 Overview

The GridLab Elasticsearch Client Provider is an enterprise-grade module that enables search and analytics capabilities with enhanced security, SSL certificate validation, and configuration management for ABP Framework applications.

Key Capabilities

  • ✅ Enterprise search and analytics integration
  • ✅ Secure SSL/TLS certificate validation
  • ✅ Multiple authentication methods (Basic, API Key)
  • ✅ Data stream support for logging
  • ✅ Serilog integration
  • ✅ Distributed caching support
  • ✅ Index management

Prerequisites

  • .NET 9.0 or higher
  • Elasticsearch cluster (8.x or higher)
  • NuGet package manager

🚀 Quick Start

Step 1: Install NuGet Package

Install the GridLab.Abp.Elasticsearch package from NuGet:

Install-Package GridLab.Abp.Elasticsearch

Package Information:

Step 2: Add Module Dependency

Add the AbpGridLabElasticsearchModule to your ABP module's dependency list:

[DependsOn(
    //...other dependencies
    typeof(AbpGridLabElasticsearchModule)
)]
public class YourModule : AbpModule
{
}

Step 3: Configure Settings

Locate appsettings.json in your project and add Elasticsearch configuration:

{
  "Elasticsearch": {
    "Enabled": true,
    "Configuration": {
      "ConnectionString": "https://localhost:9200",
      "DataStreamType": "logs",
      "DataStreamDataset": "application", 
      "DataStreamNamespace": "production"
    },
    "Authentication": {
      "Type": "Basic",
      "Username": "elastic",
      "Password": "your_password"
    },
    "Ssl": {
      "Enabled": true,
      "CertificateFingerprint": "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD",
      "CertPath": "certificates/elasticsearch.pfx",
      "CertPassphrase": "certificate_password"
    },
    "Connection": {
      "TimeoutSeconds": 30,
      "MaxRetries": 3,
      "EnableDebugMode": false
    }
  }
}

⚙️ Configuration Reference

Configuration Options

Elasticsearch Section

Property Description Default
Enabled Enable/disable Elasticsearch integration false

Configuration Section

Property Description Default
ConnectionString Elasticsearch cluster endpoint https://localhost:9200
DataStreamType Data stream type for logging logs
DataStreamDataset Data stream dataset name generic
DataStreamNamespace Data stream namespace default

Authentication Section

Property Description Values
Type Authentication method Basic, ApiKey, None
Username Username for Basic auth -
Password Password for Basic auth -
ApiKey API key for ApiKey auth -

SSL Section

Property Description Default
Enabled Enable SSL certificate validation true
CertificateFingerprint Expected certificate fingerprint -
CertPath Path to client certificate (PKCS#12) -
CertPassphrase Certificate passphrase -

Connection Section

Property Description Default
TimeoutSeconds Request timeout in seconds 30
MaxRetries Maximum retry attempts 3
EnableDebugMode Enable debug logging false

Configure Cache

To use Elasticsearch as part of distributed cache

Add ConfigureDistributedCache to Abp Module:

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();
        var env = context.Services.GetHostingEnvironment();

        // Other configurations
        ConfigureDistributedCache(configuration);
        ConfigureDataProtection(context, configuration);
        ConfigureDistributedLock(context, configuration);
    }
private void ConfigureDistributedCache(IConfiguration configuration)
{
    Configure<AbpDistributedCacheOptions>(options =>
    {
        options.KeyPrefix = configuration["AbpDistributedCache:KeyPrefix"] ?? "";
    });
}
private void ConfigureDataProtection(ServiceConfigurationContext context, IConfiguration configuration)
{
    var dataProtectionBuilder = context.Services.AddDataProtection().SetApplicationName(configuration["DataProtection:ApplicationName"]!);

    var certificateProvider = context.Services.GetCertificateProvider();
    var certificateValidator = context.Services.GetCertificateValidator();

    var options = configuration
        .GetSection(AbpGridLabValkeyOptions.ServiceName)
        .Get<AbpGridLabValkeyOptions>() ?? new AbpGridLabValkeyOptions();

    var configurationOptions = AbpValkeyConfigurationHelper.CreateConfigurationOptions(
        serviceOptions: options,
        certificateProvider: certificateProvider,
        certificateValidator: certificateValidator
    );

    var redis = ConnectionMultiplexer.Connect(configurationOptions);
    dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, configuration["DataProtection:Keys"]);
}
private void ConfigureDistributedLock(ServiceConfigurationContext context, IConfiguration configuration)
{
    context.Services.AddSingleton<IDistributedLockProvider>(sp =>
    {
        var certificateProvider = context.Services.GetCertificateProvider();
        var certificateValidator = context.Services.GetCertificateValidator();

        var options = configuration
            .GetSection(AbpGridLabValkeyOptions.ServiceName)
            .Get<AbpGridLabValkeyOptions>() ?? new AbpGridLabValkeyOptions();

        var configurationOptions = AbpValkeyConfigurationHelper.CreateConfigurationOptions(
            serviceOptions: options,
            certificateProvider: certificateProvider,
            certificateValidator: certificateValidator
        );

        var connection = ConnectionMultiplexer.Connect(configurationOptions);
        return new RedisDistributedSynchronizationProvider(connection.GetDatabase());
    });
}

Usage Examples

Basic Client Injection

public class MyService : ITransientDependency
{
    private readonly IElasticsearchClientProvider _clientProvider;

    public MyService(IElasticsearchClientProvider clientProvider)
    {
        _clientProvider = clientProvider;
    }

    public async Task<SearchResponse<MyDocument>> SearchDocumentsAsync()
    {
        var client = _clientProvider.GetClient();

        var response = await client.SearchAsync<MyDocument>(s => s
            .Index("my-index")
            .Query(q => q.MatchAll())
        );

        return response;
    }
}

Advance Search Options

public class DocumentSearchService : ITransientDependency
{
    private readonly IElasticsearchClientProvider _clientProvider;
    private readonly ILogger<DocumentSearchService> _logger;

    public DocumentSearchService(
        IElasticsearchClientProvider clientProvider,
        ILogger<DocumentSearchService> logger)
    {
        _clientProvider = clientProvider;
        _logger = logger;
    }

    public async Task<List<Document>> SearchAsync(string query, int pageSize = 10)
    {
        try
        {
            var client = _clientProvider.GetClient();

            var response = await client.SearchAsync<Document>(s => s
                .Index("documents")
                .Size(pageSize)
                .Query(q => q
                    .MultiMatch(m => m
                        .Fields(f => f.Field(doc => doc.Title).Field(doc => doc.Content))
                        .Query(query)
                    )
                )
                .Highlight(h => h
                    .Fields(f => f.Field(doc => doc.Content))
                )
            );

            if (!response.IsValidResponse)
            {
                _logger.LogError("Elasticsearch search failed: {Error}", response.DebugInformation);
                return new List<Document>();
            }

            return response.Documents.ToList();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error occurred during Elasticsearch search");
            throw;
        }
    }
}

Index Management

public class IndexManagementService : ITransientDependency
{
    private readonly IElasticsearchClientProvider _clientProvider;

    public IndexManagementService(IElasticsearchClientProvider clientProvider)
    {
        _clientProvider = clientProvider;
    }

    public async Task<bool> CreateIndexAsync<T>(string indexName) where T : class
    {
        var client = _clientProvider.GetClient();

        var response = await client.Indices.CreateAsync(indexName, c => c
            .Mappings(m => m.AutoMap<T>())
            .Settings(s => s
                .NumberOfShards(1)
                .NumberOfReplicas(1)
            )
        );

        return response.IsValidResponse;
    }

    public async Task<bool> IndexDocumentAsync<T>(T document, string indexName) where T : class
    {
        var client = _clientProvider.GetClient();

        var response = await client.IndexAsync(document, idx => idx.Index(indexName));

        return response.IsValidResponse;
    }
}

Serilog Integration

To use Elasticsearch as a Serilog sink in your ASP.NET Core application:

Program.cs Configuration

var builder = WebApplication.CreateBuilder(args);

// Configure Serilog with Elasticsearch
builder.Host.UseSerilog((context, services, loggerConfig) =>
{
    loggerConfig
        .ReadFrom.Configuration(context.Configuration)
        .Enrich.FromLogContext()
        .Enrich.WithProperty("Application", "MyApplication")
        .WriteTo.UseElasticsearch(context.Configuration);
});

// Add ABP and GridLab services
await builder.AddApplicationAsync<MyApplicationModule>();

var app = builder.Build();

📚 Best Practices

✅ Do's

  • Use data streams for logging and time-series data
  • Implement proper error handling for search operations
  • Use connection pooling for better performance
  • Enable SSL/TLS in production environments
  • Monitor Elasticsearch cluster health
  • Use appropriate index naming conventions
  • Implement retry logic for failed operations

❌ Don'ts

  • Don't store sensitive data without encryption
  • Don't use wildcard queries on large datasets
  • Don't ignore connection timeout settings
  • Don't skip SSL certificate validation in production
  • Don't use synchronous operations in web requests
  • Don't forget to close connections properly
  • Don't index without considering mapping strategy

🔍 Troubleshooting

Common Issues

Issue: Connection timeout

  • Solution: Check Elasticsearch server is running
  • Solution: Verify connection string is correct
  • Solution: Increase TimeoutSeconds in configuration

Issue: SSL certificate validation fails

  • Solution: Verify certificate fingerprint matches
  • Solution: Ensure certificate is not expired
  • Solution: Check CertPath and CertPassphrase are correct

Issue: Authentication failed

  • Solution: Verify username and password are correct
  • Solution: Check authentication type matches server configuration
  • Solution: Ensure user has required permissions

Issue: Search returns no results

  • Solution: Verify index exists
  • Solution: Check query syntax is correct
  • Solution: Ensure documents are indexed

📖 Additional Resources