ASP.NET Core Integration
- Last UpdatedJul 28, 2026
- 4 minute read
- Engineering
- Integration Service 4.1
- Integrators
This section covers integrating the AVEVA Integration Service Data API SDK into ASP.NET Core applications using dependency injection, health checks, Serilog, and middleware.
Setup
Project Dependencies
dotnet add package AVEVA.IntegrationService.DataAPI.SDK
dotnet add package Microsoft.Extensions.Http
dotnet add package Serilog.AspNetCore
Minimum .NET Version
.NET 5.0 or later
Dependency Injection
Register SDK in Program.cs
// Program.cs (.NET 6+)
var builder = WebApplication.CreateBuilder(args);
// Register all DataAPI services via extension method
builder.Services.AddDataApiServices(builder.Configuration);
var app = builder.Build();
app.Run();
Extension Method
// Extensions/DataApiServiceCollectionExtensions.cs
public static class DataApiServiceCollectionExtensions
{
public static IServiceCollection AddDataApiServices(
this IServiceCollection services,
IConfiguration configuration)
{
var host = configuration["DataApi:Host"];
if (string.IsNullOrEmpty(host))
throw new InvalidOperationException("DataApi:Host configuration is required");
services.Configure<DataApiOptions>(configuration.GetSection("DataApi"));
services.AddScoped<IDataApiClientFactory, DataApiClientFactory>();
services.AddScoped<IEngineeringDataService, EngineeringDataService>();
services.AddScoped<IExcelDataService, ExcelDataService>();
services.AddHttpClient();
return services;
}
}
DataApiClientFactory for DI
public interface IDataApiClientFactory
{
EngineeringClient CreateEngineeringClient();
ExcelClient CreateExcelClient();
}
public class DataApiClientFactory : IDataApiClientFactory
{
private readonly DataApiOptions _options;
public DataApiClientFactory(IOptions<DataApiOptions> options)
{
_options = options.Value;
}
public EngineeringClient CreateEngineeringClient()
{
var authType = _options.AuthenticationType == "Connect"
? AuthenticationType.Connect
: AuthenticationType.NTLM;
return DataApiClientFactory.CreateDataApiClient<EngineeringClient>(
host: _options.Host,
authType: authType,
token: _options.AccessToken ?? "");
}
public ExcelClient CreateExcelClient()
{
var authType = _options.AuthenticationType == "Connect"
? AuthenticationType.Connect
: AuthenticationType.NTLM;
return DataApiClientFactory.CreateDataApiClient<ExcelClient>(
host: _options.Host,
authType: authType,
token: _options.AccessToken ?? "");
}
}
Configuration Class
public class DataApiOptions
{
public string Host { get; set; }
public string AuthenticationType { get; set; } = "NTLM";
public string AccessToken { get; set; }
public int TimeoutMinutes { get; set; } = 60;
public int RetryAttempts { get; set; } = 3;
}
Configuration
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"AVEVA": "Debug"
}
},
"DataApi": {
"Host": "https://your-ais-server/api/v1/datasources",
"AuthenticationType": "NTLM",
"TimeoutMinutes": 60,
"RetryAttempts": 3
}
}
Environment-Specific
// appsettings.Development.json
{
"DataApi": {
"Host": "https://localhost:44301/api/v1/datasources"
}
}
// appsettings.Production.json
{
"DataApi": {
"Host": "https://ais-prod.empresa.com/api/v1/datasources",
"AuthenticationType": "Connect"
}
}
Secure Token Storage
// Azure Key Vault
builder.Configuration.AddAzureKeyVault(
new Uri($"https://{keyVaultName}.vault.azure.net/"),
new DefaultAzureCredential());
// User Secrets (Development only)
builder.Configuration.AddUserSecrets<Program>();
Service Implementation
Engineering Data Service
public interface IEngineeringDataService
{
Task<IEnumerable<DatasourceDto>> GetDataSourcesAsync();
Task<IEnumerable<Table>> GetTablesAsync(string datasourceName);
Task<IEnumerable<TableData>> GetTableDataAsync(string datasourceName, string tableName);
}
public class EngineeringDataService : IEngineeringDataService
{
private readonly IDataApiClientFactory _clientFactory;
private readonly ILogger<EngineeringDataService> _logger;
public EngineeringDataService(
IDataApiClientFactory clientFactory,
ILogger<EngineeringDataService> logger)
{
_clientFactory = clientFactory;
_logger = logger;
}
public async Task<IEnumerable<DatasourceDto>> GetDataSourcesAsync()
{
try
{
_logger.LogInformation("Retrieving data sources");
var client = _clientFactory.CreateEngineeringClient();
return await client.GetDataSources("");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving data sources");
throw;
}
}
public async Task<IEnumerable<Table>> GetTablesAsync(string datasourceName)
{
try
{
_logger.LogInformation("Retrieving tables for {DatasourceName}", datasourceName);
var client = _clientFactory.CreateEngineeringClient();
return await client.GetTables(datasourceName, "");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving tables for {DatasourceName}", datasourceName);
throw;
}
}
public async Task<IEnumerable<TableData>> GetTableDataAsync(
string datasourceName, string tableName)
{
try
{
_logger.LogInformation("Retrieving data for {DatasourceName}.{TableName}",
datasourceName, tableName);
var client = _clientFactory.CreateEngineeringClient();
return await client.GetTableData(datasourceName, tableName, "");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving data for {DatasourceName}.{TableName}",
datasourceName, tableName);
throw;
}
}
}
Controllers
REST API Controller
[ApiController]
[Route("api/[controller]")]
public class DataSourcesController : ControllerBase
{
private readonly IEngineeringDataService _dataService;
private readonly ILogger<DataSourcesController> _logger;
public DataSourcesController(
IEngineeringDataService dataService,
ILogger<DataSourcesController> logger)
{
_dataService = dataService;
_logger = logger;
}
[HttpGet("datasources")]
public async Task<ActionResult<IEnumerable<DatasourceDto>>> GetDataSources()
{
try
{
var dataSources = await _dataService.GetDataSourcesAsync();
return Ok(dataSources);
}
catch (TimeoutException ex)
{
_logger.LogWarning(ex, "Request timeout");
return StatusCode(StatusCodes.Status504GatewayTimeout,
new { message = "Request timed out" });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving data sources");
return StatusCode(StatusCodes.Status500InternalServerError,
new { message = "An error occurred" });
}
}
[HttpGet("tables/{datasourceName}")]
public async Task<ActionResult<IEnumerable<Table>>> GetTables(string datasourceName)
{
try
{
var tables = await _dataService.GetTablesAsync(datasourceName);
return Ok(tables);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving tables for {DatasourceName}", datasourceName);
return BadRequest(new { message = ex.Message });
}
}
[HttpGet("data/{datasourceName}/{tableName}")]
public async Task<ActionResult<IEnumerable<TableData>>> GetTableData(
string datasourceName, string tableName)
{
try
{
var data = await _dataService.GetTableDataAsync(datasourceName, tableName);
return Ok(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving data");
return BadRequest(new { message = ex.Message });
}
}
}
Health Checks
Register Health Check
// Program.cs
builder.Services
.AddHealthChecks()
.AddCheck<DataApiHealthCheck>("dataapi");
var app = builder.Build();
app.MapHealthChecks("/health");
DataApiHealthCheck Implementation
public class DataApiHealthCheck : IHealthCheck
{
private readonly DataApiOptions _options;
public DataApiHealthCheck(IOptions<DataApiOptions> options)
{
_options = options.Value;
}
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
try
{
var healthClient = HealthCheckClientFactory.CreateHealthCheckClient(new HttpClient());
var status = await healthClient.HealthCheckAPI(_options.Host);
return status == System.Net.HttpStatusCode.OK
? HealthCheckResult.Healthy("DataAPI is healthy")
: HealthCheckResult.Unhealthy($"DataAPI returned {status}");
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy($"DataAPI check failed: {ex.Message}", ex);
}
}
}
Logging
Configure Serilog
// Program.cs
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console()
.WriteTo.File(
"logs/app-.txt",
rollingInterval: RollingInterval.Day,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.Enrich.FromLogContext()
.CreateLogger();
try
{
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
// ...
var app = builder.Build();
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
Structured Logging Examples
_logger.LogInformation(
"Retrieved {Count} data sources from {Host}",
dataSources.Count(), _options.Host);
_logger.LogError(ex,
"Failed to retrieve data from {DatasourceName}", datasourceName);
Error Handling
Global Exception Handler Middleware
public class DataApiExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<DataApiExceptionHandlerMiddleware> _logger;
public DataApiExceptionHandlerMiddleware(
RequestDelegate next,
ILogger<DataApiExceptionHandlerMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "Unhandled exception occurred");
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
var response = new
{
message = exception.Message,
statusCode = context.Response.StatusCode
};
return context.Response.WriteAsJsonAsync(response);
}
}
// Register in Program.cs
app.UseMiddleware<DataApiExceptionHandlerMiddleware>();
Per-Endpoint Error Handling
[HttpGet("data")]
public async Task<ActionResult<DataResponse>> GetData()
{
try
{
var data = await _service.GetDataAsync();
return Ok(data);
}
catch (HubConnectionInitializationException)
{
return StatusCode(StatusCodes.Status503ServiceUnavailable,
new { message = "Data service is temporarily unavailable" });
}
catch (TimeoutException)
{
return StatusCode(StatusCodes.Status504GatewayTimeout,
new { message = "Request timed out" });
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError,
new { message = "An unexpected error occurred" });
}
}
Complete Example: Web API
// Program.cs
using Serilog;
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console()
.WriteTo.File("logs/app-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
builder.Services
.AddControllers();
builder.Services
.AddDataApiServices(builder.Configuration);
builder.Services
.AddHealthChecks()
.AddCheck<DataApiHealthCheck>("dataapi");
builder.Services.AddCors(options =>
options.AddPolicy("AllowAll", b =>
b.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()));
var app = builder.Build();
app.UseHttpsRedirection();
app.UseCors("AllowAll");
app.MapControllers();
app.MapHealthChecks("/health");
app.Run();