using CredentialManager.Models;
using CredentialManager.Services;
using CredentialManager.Integration;
using DataConnection.CredentialManagement.Interfaces;
using DataConnection.CredentialManagement.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Data.SqlClient;
using Microsoft.Data.Sqlite;
namespace DataConnection.CredentialManagement.Services;
///
/// Servizio per l'integrazione delle credenziali con DataConnection
///
public class DataConnectionCredentialService : IDataConnectionCredentialService
{
private readonly ICredentialService _credentialService;
private readonly ILogger _logger;
public DataConnectionCredentialService(
ICredentialService credentialService,
ILogger logger)
{
_credentialService = credentialService;
_logger = logger;
}
#region Database Credentials
public async Task GetDatabaseCredentialAsync(string name)
{
return await _credentialService.GetDatabaseCredentialAsync(name);
}
public async Task GetDatabaseCredentialAsync(int id)
{
return await _credentialService.GetDatabaseCredentialAsync(id);
}
public async Task> GetAllDatabaseCredentialsAsync()
{
return await _credentialService.GetAllDatabaseCredentialsAsync();
}
public async Task SaveDatabaseCredentialAsync(DatabaseCredential credential)
{
_logger.LogInformation("Saving database credential: {Name}", credential.Name);
return await _credentialService.SaveDatabaseCredentialAsync(credential);
}
public async Task DeleteDatabaseCredentialAsync(int id)
{
_logger.LogInformation("Deleting database credential with ID: {Id}", id);
return await _credentialService.DeleteCredentialAsync(id);
}
public async Task DeleteDatabaseCredentialAsync(string name)
{
_logger.LogInformation("Deleting database credential: {Name}", name);
return await _credentialService.DeleteCredentialAsync(name);
}
#endregion
#region REST API Credentials
public async Task GetRestApiCredentialAsync(string name)
{
return await _credentialService.GetRestApiCredentialAsync(name);
}
public async Task GetRestApiCredentialAsync(int id)
{
return await _credentialService.GetRestApiCredentialAsync(id);
}
public async Task> GetAllRestApiCredentialsAsync()
{
return await _credentialService.GetAllRestApiCredentialsAsync();
}
public async Task SaveRestApiCredentialAsync(RestApiCredential credential)
{
_logger.LogInformation("Saving REST API credential: {Name}", credential.Name);
return await _credentialService.SaveRestApiCredentialAsync(credential);
}
public async Task DeleteRestApiCredentialAsync(int id)
{
_logger.LogInformation("Deleting REST API credential with ID: {Id}", id);
return await _credentialService.DeleteCredentialAsync(id);
}
public async Task DeleteRestApiCredentialAsync(string name)
{
_logger.LogInformation("Deleting REST API credential: {Name}", name);
return await _credentialService.DeleteCredentialAsync(name);
}
#endregion
#region DataConnection Specific Operations
public async Task GetConnectionStringAsync(string credentialName)
{
var credential = await GetDatabaseCredentialAsync(credentialName);
if (credential == null)
throw new InvalidOperationException($"Database credential '{credentialName}' not found");
return credential.ToConnectionString();
}
public async Task GetConnectionStringAsync(int credentialId)
{
var credential = await GetDatabaseCredentialAsync(credentialId);
if (credential == null)
throw new InvalidOperationException($"Database credential with ID '{credentialId}' not found"); return credential.ToConnectionString();
}
public async Task GetDbManagerOptionsAsync(string credentialName)
{
var credential = await GetDatabaseCredentialAsync(credentialName);
if (credential == null)
throw new InvalidOperationException($"Database credential '{credentialName}' not found");
var options = new DataConnection.EF.DbManagerOptions
{
ServerConnectionString = credential.ToConnectionString(),
DatabaseName = credential.DatabaseName!,
DatabaseType = credential.DatabaseType.ToDataConnectionDatabaseType(),
CommandTimeout = credential.CommandTimeout
};
// Configura automaticamente il servizio di scoperta database
options.ConfigureDatabaseDiscovery(options.DatabaseType);
_logger.LogDebug("Created DbManagerOptions for credential: {Name} ({DatabaseType})",
credentialName, credential.DatabaseType);
return options;
}
public async Task GetDbManagerOptionsAsync(int credentialId)
{
var credential = await GetDatabaseCredentialAsync(credentialId);
if (credential == null)
throw new InvalidOperationException($"Database credential with ID '{credentialId}' not found"); var options = new DataConnection.EF.DbManagerOptions
{
ServerConnectionString = credential.ToConnectionString(),
DatabaseName = credential.DatabaseName!,
DatabaseType = credential.DatabaseType.ToDataConnectionDatabaseType(),
CommandTimeout = credential.CommandTimeout
};
// Configura automaticamente il servizio di scoperta database
options.ConfigureDatabaseDiscovery(options.DatabaseType);
_logger.LogDebug("Created DbManagerOptions for credential ID: {Id} ({DatabaseType})",
credentialId, credential.DatabaseType);
return options;
}
public async Task GetRestServiceOptionsAsync(string credentialName)
{
var credential = await GetRestApiCredentialAsync(credentialName);
if (credential == null)
throw new InvalidOperationException($"REST API credential '{credentialName}' not found");
var options = new DataConnection.REST.Configuration.RestServiceOptions
{
BaseUrl = credential.BaseUrl,
ApiKey = credential.ApiKey,
Username = credential.Username,
Password = credential.Password,
AuthToken = credential.AuthToken,
TimeoutSeconds = credential.TimeoutSeconds,
IgnoreSslErrors = credential.IgnoreSslErrors
};
_logger.LogDebug("Created RestServiceOptions for credential: {Name} ({BaseUrl})",
credentialName, credential.BaseUrl);
return options;
}
public async Task GetRestServiceOptionsAsync(int credentialId)
{
var credential = await GetRestApiCredentialAsync(credentialId);
if (credential == null)
throw new InvalidOperationException($"REST API credential with ID '{credentialId}' not found");
var options = new DataConnection.REST.Configuration.RestServiceOptions
{
BaseUrl = credential.BaseUrl,
ApiKey = credential.ApiKey,
Username = credential.Username,
Password = credential.Password,
AuthToken = credential.AuthToken,
TimeoutSeconds = credential.TimeoutSeconds,
IgnoreSslErrors = credential.IgnoreSslErrors
};
_logger.LogDebug("Created RestServiceOptions for credential ID: {Id} ({BaseUrl})",
credentialId, credential.BaseUrl);
return options;
}
#endregion
#region Connection Testing
public async Task<(bool Success, string Message)> TestDatabaseConnectionAsync(string credentialName)
{
try
{
var credential = await GetDatabaseCredentialAsync(credentialName);
if (credential == null)
return (false, $"Credenziale '{credentialName}' non trovata");
return await TestDatabaseConnectionAsync(credential);
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel test della connessione per credenziale: {Name}", credentialName);
return (false, $"Errore nel test: {ex.Message}");
}
}
public async Task<(bool Success, string Message)> TestDatabaseConnectionAsync(DatabaseCredential credential)
{
try
{
var connectionString = ConnectionStringBuilder.BuildConnectionString(credential);
// Test base della sintassi
if (string.IsNullOrEmpty(connectionString))
return (false, "Connection string vuota o non valida");
_logger.LogInformation("Testing database connection for {Name} ({DatabaseType})",
credential.Name, credential.DatabaseType);
// Test di connessione diretto basato sul tipo di database
try
{
return credential.DatabaseType switch
{
CredentialManager.Models.DatabaseType.SqlServer => await TestSqlServerConnection(connectionString, credential),
CredentialManager.Models.DatabaseType.MySql => await TestMySqlConnection(connectionString, credential),
CredentialManager.Models.DatabaseType.PostgreSql => await TestPostgreSqlConnection(connectionString, credential),
CredentialManager.Models.DatabaseType.Oracle => await TestOracleConnection(connectionString, credential),
CredentialManager.Models.DatabaseType.Sqlite => await TestSqliteConnection(connectionString, credential),
_ => (false, $"Test di connessione non implementato per {credential.DatabaseType}")
};
}
catch (Exception ex)
{
_logger.LogError(ex, "Database connection test failed for {Name}", credential.Name);
return (false, $"Errore di connessione: {ex.Message}");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel test della connessione database");
return (false, $"Errore: {ex.Message}");
}
}
private async Task<(bool Success, string Message)> TestSqlServerConnection(string connectionString, DatabaseCredential credential)
{
try
{
using var connection = new Microsoft.Data.SqlClient.SqlConnection(connectionString);
connection.Open();
var command = connection.CreateCommand();
command.CommandText = "SELECT @@VERSION";
command.CommandTimeout = credential.CommandTimeout;
var version = await command.ExecuteScalarAsync();
return (true, $"Connessione SQL Server riuscita!\n\nDettagli:\n- Host: {credential.Host}:{credential.Port}\n- Database: {credential.DatabaseName ?? "Default"}\n- Versione: {version?.ToString()?.Split('\n')[0]}\n- Timeout: {credential.CommandTimeout}s");
}
catch (Exception ex)
{
return (false, $"Errore SQL Server: {ex.Message}");
}
}
private Task<(bool Success, string Message)> TestMySqlConnection(string connectionString, DatabaseCredential credential)
{
try
{
// Per MySQL, dovremmo usare MySql.Data.MySqlClient o Pomelo.EntityFrameworkCore.MySql
// Per ora returnamo un messaggio che indica che il test non è implementato
return Task.FromResult<(bool Success, string Message)>((false, "Test MySQL non implementato - installare MySql.Data.MySqlClient"));
}
catch (Exception ex)
{
return Task.FromResult<(bool Success, string Message)>((false, $"Errore MySQL: {ex.Message}"));
}
}
private Task<(bool Success, string Message)> TestPostgreSqlConnection(string connectionString, DatabaseCredential credential)
{
try
{
// Per PostgreSQL, dovremmo usare Npgsql
return Task.FromResult<(bool Success, string Message)>((false, "Test PostgreSQL non implementato - installare Npgsql"));
}
catch (Exception ex)
{
return Task.FromResult<(bool Success, string Message)>((false, $"Errore PostgreSQL: {ex.Message}"));
}
}
private Task<(bool Success, string Message)> TestOracleConnection(string connectionString, DatabaseCredential credential)
{
try
{
// Per Oracle, dovremmo usare Oracle.ManagedDataAccess
return Task.FromResult<(bool Success, string Message)>((false, "Test Oracle non implementato - installare Oracle.ManagedDataAccess"));
}
catch (Exception ex)
{
return Task.FromResult<(bool Success, string Message)>((false, $"Errore Oracle: {ex.Message}"));
}
}
private async Task<(bool Success, string Message)> TestSqliteConnection(string connectionString, DatabaseCredential credential)
{
try
{
using var connection = new Microsoft.Data.Sqlite.SqliteConnection(connectionString);
connection.Open();
var command = connection.CreateCommand();
command.CommandText = "SELECT sqlite_version()";
command.CommandTimeout = credential.CommandTimeout;
var version = await command.ExecuteScalarAsync();
return (true, $"Connessione SQLite riuscita!\n\nDettagli:\n- File: {credential.Host ?? connectionString}\n- Versione SQLite: {version}\n- Timeout: {credential.CommandTimeout}s");
}
catch (Exception ex)
{
return (false, $"Errore SQLite: {ex.Message}");
}
}
public async Task<(bool Success, string Message)> TestRestApiConnectionAsync(string credentialName)
{
try
{
_logger.LogInformation("Attempting to test REST API connection for credential: {Name}", credentialName);
var credential = await GetRestApiCredentialAsync(credentialName);
if (credential == null)
{
_logger.LogWarning("REST API credential '{Name}' not found", credentialName);
return (false, $"Credenziale REST API '{credentialName}' non trovata");
}
_logger.LogInformation("Found credential: {Name}, ServiceType: {ServiceType}, BaseUrl: {BaseUrl}",
credential.Name, credential.ServiceType, credential.BaseUrl);
return await TestRestApiConnectionAsync(credential);
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel test della connessione REST API per credenziale: {Name}", credentialName);
return (false, $"Errore nel test: {ex.Message}");
}
}
public async Task<(bool Success, string Message)> TestRestApiConnectionAsync(RestApiCredential credential)
{
try
{
if (string.IsNullOrEmpty(credential.BaseUrl))
return (false, "Base URL non specificata");
// Test base dell'URL
if (!Uri.TryCreate(credential.BaseUrl, UriKind.Absolute, out var uri))
return (false, "Base URL non valida");
// Per i servizi specifici, eseguiamo test di autenticazione reali
switch (credential.ServiceType)
{
case RestServiceType.SapB1ServiceLayer:
return await TestSapB1ServiceLayerAuthentication(credential);
case RestServiceType.Salesforce:
return await TestSalesforceAuthentication(credential);
default:
// Per REST API generiche, facciamo un test di connettività base
return await TestGenericRestApiConnection(credential);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel test della connessione REST API");
return (false, $"Errore: {ex.Message}");
}
}
private async Task<(bool Success, string Message)> TestSapB1ServiceLayerAuthentication(RestApiCredential credential)
{
try
{
_logger.LogInformation("Testing SAP B1 Service Layer authentication for {Name} ({BaseUrl})",
credential.Name, credential.BaseUrl);
using var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromSeconds(credential.TimeoutSeconds);
// Test di login al Service Layer
var loginUrl = credential.BaseUrl.TrimEnd('/') + "/Login";
var loginData = new
{
CompanyDB = credential.CompanyDatabase,
UserName = credential.Username,
Password = credential.Password,
Language = credential.Language ?? "en-US"
};
var loginJson = System.Text.Json.JsonSerializer.Serialize(loginData);
var loginContent = new StringContent(loginJson, System.Text.Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(loginUrl, loginContent);
if (response.IsSuccessStatusCode)
{
return (true, $"Autenticazione SAP B1 Service Layer riuscita!\n\nDettagli:\n- Server: {credential.BaseUrl}\n- Company DB: {credential.CompanyDatabase}\n- Versione: {credential.Version}\n- Lingua: {credential.Language}\n- Timeout: {credential.TimeoutSeconds}s");
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
return (false, $"Autenticazione SAP B1 fallita. Status: {response.StatusCode}\nDettagli: {errorContent}");
}
}
catch (HttpRequestException ex)
{
return (false, $"Errore di rete SAP B1: {ex.Message}");
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException || ex.Message.Contains("timeout"))
{
return (false, $"Timeout della connessione SAP B1 ({credential.TimeoutSeconds}s)");
}
}
private async Task<(bool Success, string Message)> TestSalesforceAuthentication(RestApiCredential credential)
{
try
{
_logger.LogInformation("Testing Salesforce authentication for {Name} ({BaseUrl})",
credential.Name, credential.BaseUrl);
_logger.LogDebug("Salesforce credential details: Username={Username}, HasPassword={HasPassword}, HasSecurityToken={HasSecurityToken}, HasClientId={HasClientId}, HasClientSecret={HasClientSecret}",
credential.Username, !string.IsNullOrEmpty(credential.Password), !string.IsNullOrEmpty(credential.SecurityToken),
!string.IsNullOrEmpty(credential.ClientId), !string.IsNullOrEmpty(credential.ClientSecret));
using var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromSeconds(credential.TimeoutSeconds);
// Test di autenticazione OAuth2
var tokenUrl = credential.BaseUrl.TrimEnd('/') + "/services/oauth2/token";
var tokenData = new List>
{
new("grant_type", "password"),
new("username", credential.Username ?? "")
};
// Aggiungiamo password + security token se disponibile
var password = credential.Password ?? "";
if (!string.IsNullOrEmpty(credential.SecurityToken))
{
password += credential.SecurityToken;
}
tokenData.Add(new("password", password));
// Aggiungiamo client credentials se disponibili
if (!string.IsNullOrEmpty(credential.ClientId))
{
tokenData.Add(new("client_id", credential.ClientId));
}
if (!string.IsNullOrEmpty(credential.ClientSecret))
{
tokenData.Add(new("client_secret", credential.ClientSecret));
}
_logger.LogDebug("Posting to Salesforce token URL: {TokenUrl}", tokenUrl);
var tokenContent = new FormUrlEncodedContent(tokenData);
var response = await httpClient.PostAsync(tokenUrl, tokenContent);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
_logger.LogInformation("Salesforce authentication successful for {Name}", credential.Name);
return (true, $"Autenticazione Salesforce riuscita!\n\nDettagli:\n- Login URL: {credential.BaseUrl}\n- API Version: {credential.ApiVersion}\n- Sandbox: {credential.IsSandbox}\n- Tipo Auth: OAuth2\n- Timeout: {credential.TimeoutSeconds}s");
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogWarning("Salesforce authentication failed for {Name}. Status: {StatusCode}, Response: {Response}",
credential.Name, response.StatusCode, errorContent);
return (false, $"Autenticazione Salesforce fallita. Status: {response.StatusCode}\nDettagli: {errorContent}");
}
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, "Network error during Salesforce authentication for {Name}", credential.Name);
return (false, $"Errore di rete Salesforce: {ex.Message}");
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException || ex.Message.Contains("timeout"))
{
_logger.LogWarning("Timeout during Salesforce authentication for {Name} ({TimeoutSeconds}s)", credential.Name, credential.TimeoutSeconds);
return (false, $"Timeout della connessione Salesforce ({credential.TimeoutSeconds}s)");
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error during Salesforce authentication for {Name}", credential.Name);
return (false, $"Errore imprevisto: {ex.Message}");
}
}
private async Task<(bool Success, string Message)> TestGenericRestApiConnection(RestApiCredential credential)
{
try
{
// Test di connessione reale per REST API generiche
using var httpClient = new HttpClient();
// Configurazione del timeout
httpClient.Timeout = TimeSpan.FromSeconds(credential.TimeoutSeconds);
// Configurazione autenticazione
if (!string.IsNullOrEmpty(credential.ApiKey))
{
httpClient.DefaultRequestHeaders.Add("X-API-Key", credential.ApiKey);
}
else if (!string.IsNullOrEmpty(credential.AuthToken))
{
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {credential.AuthToken}");
}
else if (!string.IsNullOrEmpty(credential.Username) && !string.IsNullOrEmpty(credential.Password))
{
var authValue = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes($"{credential.Username}:{credential.Password}"));
httpClient.DefaultRequestHeaders.Add("Authorization", $"Basic {authValue}");
}
_logger.LogInformation("Testing generic REST API connection for {Name} ({BaseUrl})",
credential.Name, credential.BaseUrl);
// Facciamo una richiesta HEAD o GET semplice per testare la connettività
var testEndpoint = credential.BaseUrl.TrimEnd('/') + "/";
var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, testEndpoint));
// Anche un 404 o 401 indica che il server è raggiungibile
var isReachable = response.StatusCode != System.Net.HttpStatusCode.RequestTimeout &&
!IsNetworkError(response.StatusCode);
if (isReachable)
{
return (true, $"Connessione REST API riuscita!\n\nDettagli:\n- URL: {credential.BaseUrl}\n- Status: {response.StatusCode}\n- Timeout: {credential.TimeoutSeconds}s\n- Auth: {GetAuthType(credential)}");
}
else
{
return (false, $"Connessione fallita. Status: {response.StatusCode}\nVerifica URL e configurazione di rete.");
}
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, "Generic REST API connection test failed for {Name}", credential.Name);
return (false, $"Errore di rete: {ex.Message}");
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException || ex.Message.Contains("timeout"))
{
return (false, $"Timeout della connessione ({credential.TimeoutSeconds}s). Il server potrebbe essere irraggiungibile.");
}
}
private static bool IsNetworkError(System.Net.HttpStatusCode statusCode)
{
return statusCode == System.Net.HttpStatusCode.RequestTimeout ||
statusCode == System.Net.HttpStatusCode.BadGateway ||
statusCode == System.Net.HttpStatusCode.ServiceUnavailable ||
statusCode == System.Net.HttpStatusCode.GatewayTimeout;
}
private static string GetAuthType(RestApiCredential credential)
{
if (!string.IsNullOrEmpty(credential.ApiKey))
return "API Key";
if (!string.IsNullOrEmpty(credential.AuthToken))
return "Auth Token";
if (!string.IsNullOrEmpty(credential.Username))
return "Basic Auth";
return "Nessuna";
}
#endregion
#region SAP B1 Service Layer Credentials
public async Task GetSapB1CredentialAsync(string name)
{
return await _credentialService.GetSapB1CredentialAsync(name);
}
public async Task GetSapB1CredentialAsync(int id)
{
return await _credentialService.GetSapB1CredentialAsync(id);
}
public async Task> GetAllSapB1CredentialsAsync()
{
return await _credentialService.GetAllSapB1CredentialsAsync();
}
public async Task SaveSapB1CredentialAsync(SapB1ServiceLayerCredential credential)
{
_logger.LogInformation("Saving SAP B1 Service Layer credential: {Name}", credential.Name);
return await _credentialService.SaveSapB1CredentialAsync(credential);
}
public async Task DeleteSapB1CredentialAsync(int id)
{
_logger.LogInformation("Deleting SAP B1 Service Layer credential with ID: {Id}", id);
return await _credentialService.DeleteCredentialAsync(id);
}
public async Task DeleteSapB1CredentialAsync(string name)
{
_logger.LogInformation("Deleting SAP B1 Service Layer credential: {Name}", name);
return await _credentialService.DeleteCredentialAsync(name);
}
public async Task<(bool Success, string Message)> TestSapB1ConnectionAsync(string credentialName)
{
try
{
var credential = await GetSapB1CredentialAsync(credentialName);
if (credential == null)
return (false, $"Credenziale SAP B1 '{credentialName}' non trovata");
return await TestSapB1ConnectionAsync(credential);
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel test della connessione SAP B1 per credenziale: {Name}", credentialName);
return (false, $"Errore nel test: {ex.Message}");
}
}
public async Task<(bool Success, string Message)> TestSapB1ConnectionAsync(SapB1ServiceLayerCredential credential)
{
try
{
if (string.IsNullOrEmpty(credential.ServerUrl))
return (false, "Server URL non specificato");
if (!Uri.TryCreate(credential.ServerUrl, UriKind.Absolute, out var uri))
return (false, "Server URL non valido");
_logger.LogInformation("Testing SAP B1 Service Layer connection for {Name} ({ServerUrl})",
credential.Name, credential.ServerUrl);
using var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromSeconds(credential.TimeoutSeconds);
// Test di accesso al Service Layer
var loginUrl = credential.ServerUrl.TrimEnd('/') + "/Login";
var loginData = new
{
CompanyDB = credential.CompanyDatabase,
UserName = credential.Username,
Password = credential.Password,
Language = credential.Language ?? "en-US"
};
var loginJson = System.Text.Json.JsonSerializer.Serialize(loginData);
var loginContent = new StringContent(loginJson, System.Text.Encoding.UTF8, "application/json");
try
{
var response = await httpClient.PostAsync(loginUrl, loginContent);
if (response.IsSuccessStatusCode)
{
return (true, $"Connessione SAP B1 Service Layer riuscita!\n\nDettagli:\n- Server: {credential.ServerUrl}\n- Company DB: {credential.CompanyDatabase}\n- Versione: {credential.Version}\n- Lingua: {credential.Language}\n- Timeout: {credential.TimeoutSeconds}s");
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
return (false, $"Login fallito. Status: {response.StatusCode}\nDettagli: {errorContent}");
}
}
catch (HttpRequestException ex)
{
return (false, $"Errore di rete SAP B1: {ex.Message}");
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException || ex.Message.Contains("timeout"))
{
return (false, $"Timeout della connessione SAP B1 ({credential.TimeoutSeconds}s).");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel test della connessione SAP B1");
return (false, $"Errore: {ex.Message}");
}
}
#endregion
#region Salesforce Credentials
public async Task GetSalesforceCredentialAsync(string name)
{
return await _credentialService.GetSalesforceCredentialAsync(name);
}
public async Task GetSalesforceCredentialAsync(int id)
{
return await _credentialService.GetSalesforceCredentialAsync(id);
}
public async Task> GetAllSalesforceCredentialsAsync()
{
return await _credentialService.GetAllSalesforceCredentialsAsync();
}
public async Task SaveSalesforceCredentialAsync(SalesforceCredential credential)
{
_logger.LogInformation("Saving Salesforce credential: {Name}", credential.Name);
return await _credentialService.SaveSalesforceCredentialAsync(credential);
}
public async Task DeleteSalesforceCredentialAsync(int id)
{
_logger.LogInformation("Deleting Salesforce credential with ID: {Id}", id);
return await _credentialService.DeleteCredentialAsync(id);
}
public async Task DeleteSalesforceCredentialAsync(string name)
{
_logger.LogInformation("Deleting Salesforce credential: {Name}", name);
return await _credentialService.DeleteCredentialAsync(name);
}
public async Task<(bool Success, string Message)> TestSalesforceConnectionAsync(string credentialName)
{
try
{
var credential = await GetSalesforceCredentialAsync(credentialName);
if (credential == null)
return (false, $"Credenziale Salesforce '{credentialName}' non trovata");
return await TestSalesforceConnectionAsync(credential);
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel test della connessione Salesforce per credenziale: {Name}", credentialName);
return (false, $"Errore nel test: {ex.Message}");
}
}
public async Task<(bool Success, string Message)> TestSalesforceConnectionAsync(SalesforceCredential credential)
{
try
{
if (string.IsNullOrEmpty(credential.LoginUrl))
return (false, "Login URL non specificato");
if (!Uri.TryCreate(credential.LoginUrl, UriKind.Absolute, out var uri))
return (false, "Login URL non valido");
_logger.LogInformation("Testing Salesforce connection for {Name} ({LoginUrl})",
credential.Name, credential.LoginUrl);
using var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromSeconds(credential.TimeoutSeconds);
// Test di login SOAP/REST
if (credential.UseSoapApi)
{
return await TestSalesforceSoapLogin(httpClient, credential);
}
else
{
return await TestSalesforceOAuthLogin(httpClient, credential);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nel test della connessione Salesforce");
return (false, $"Errore: {ex.Message}");
}
}
private async Task<(bool Success, string Message)> TestSalesforceOAuthLogin(HttpClient httpClient, SalesforceCredential credential)
{
try
{
var tokenUrl = credential.LoginUrl.TrimEnd('/') + "/services/oauth2/token";
var tokenData = new List>
{
new("grant_type", "password"),
new("username", credential.Username),
new("password", credential.Password + credential.SecurityToken),
new("client_id", credential.ClientId ?? ""),
new("client_secret", credential.ClientSecret ?? "")
};
var tokenContent = new FormUrlEncodedContent(tokenData);
var response = await httpClient.PostAsync(tokenUrl, tokenContent);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
return (true, $"Connessione Salesforce riuscita!\n\nDettagli:\n- Login URL: {credential.LoginUrl}\n- API Version: {credential.ApiVersion}\n- Sandbox: {credential.IsSandbox}\n- Tipo Auth: OAuth2\n- Timeout: {credential.TimeoutSeconds}s");
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
return (false, $"Login OAuth Salesforce fallito. Status: {response.StatusCode}\nDettagli: {errorContent}");
}
}
catch (Exception ex)
{
return (false, $"Errore OAuth Salesforce: {ex.Message}");
}
}
private async Task<(bool Success, string Message)> TestSalesforceSoapLogin(HttpClient httpClient, SalesforceCredential credential)
{
try
{
// Test semplificato per SOAP - verifica solo la raggiungibilità del servizio
var soapUrl = credential.LoginUrl.TrimEnd('/') + "/services/Soap/u/" + credential.ApiVersion;
var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, soapUrl));
if (response.IsSuccessStatusCode || response.StatusCode == System.Net.HttpStatusCode.MethodNotAllowed)
{
return (true, $"Connessione Salesforce SOAP riuscita!\n\nDettagli:\n- SOAP URL: {soapUrl}\n- API Version: {credential.ApiVersion}\n- Sandbox: {credential.IsSandbox}\n- Tipo Auth: SOAP\n- Timeout: {credential.TimeoutSeconds}s");
}
else
{
return (false, $"Servizio SOAP Salesforce non raggiungibile. Status: {response.StatusCode}");
}
}
catch (Exception ex)
{
return (false, $"Errore SOAP Salesforce: {ex.Message}");
}
}
#endregion
}