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:
- Package Name: GridLab.Abp.Elasticsearch
- Repository: GitLab - GridLab ABP Framework
- NuGet: GridLab.Abp.Elasticsearch
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