using Azure.Core; using Azure.Identity; using Kusto.Data; using Kusto.Data.Common; using Kusto.Data.Net.Client; using Microsoft.Extensions.Options; using System.Data; namespace Tango.Portal.Chat.Web.Services { public sealed class KustoQueryService { private readonly ICslQueryProvider _query; private readonly string _database; public KustoQueryService(IOptions opts) { var options = opts.Value; _database = options.Database; // Use DefaultAzureCredential: works locally (Azure CLI / Visual Studio), and in Azure (Managed Identity) var cred = new ClientSecretCredential( opts.Value.TenantId, opts.Value.ClientId, opts.Value.ClientSecret); var kcsb = new KustoConnectionStringBuilder(options.ClusterUri) .WithAadAzureTokenCredentialsAuthentication(cred); _query = KustoClientFactory.CreateCslQueryProvider(kcsb); } public async Task QueryAsync(string kql, IDictionary parameters, CancellationToken ct = default) { var props = new ClientRequestProperties { ClientRequestId = $"chat_{Guid.NewGuid()}" }; foreach (var kvp in parameters) { // Pass all as strings; let KQL cast via e.g., datetime({from}) if declared props.SetParameter(kvp.Key, kvp.Value); } props.SetOption("servertimeout", "00:00:12"); using var reader = await _query.ExecuteQueryAsync(_database, kql, props); var table = new DataTable(); table.Load(reader); return table; } } }