We are trying to implement a cloud database solution using nhibernate. We are using Azure SQL Database and we are in troubles at the time of set the connection. As the Authentication keyword is not allowed on the connection string, the only way to create a connection is to provide an Access Token. This property is not available on nhibernate. We were advised to create our own connection provider in order to achieve this. Our connection provides is:
using Project.dataaccessobjects;
using Project.security;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using NHibernate.Connection;
using System;
using System.Data.Common;
using System.Data.SqlClient;
using System.Threading.Tasks;
namespace Project.connection
{
public partial class AzureSQLDatabase : DriverConnectionProvider
{
private string strSQLServer{ get; set; }
private string strDatabase { get; set; }
private string strTenantId { get; set; }
private string strClientId { get; set; }
private string strPassword { get; set; }
public AzureSQLDatabase() : base()
{
strSQLServer = AzureKeyVaultDAO.getInstance().get("SQLServer");
strDatabase = AzureKeyVaultDAO.getInstance().get("Database");
strTenantId = AzureKeyVaultDAO.getInstance().get("TenantId");
strClientId = AzureKeyVaultDAO.getInstance().get("ClientId");
strPassword = AzureKeyVaultDAO.getInstance().get("Password");
}
private string accessToken()
{
const string ResourceUrl = "https://database.windows.net/";
string AuthorityUrl = $"https://login.microsoftonline.com/{strTenantId}";
AuthenticationContext objAuthenticationContext;
Task<AuthenticationResult> objAuthenticationResult;
ClientCredential objCredentials;
objCredentials = new ClientCredential(strClientId, SecureText.getInstance().decrypt(strPassword));
objAuthenticationContext = new AuthenticationContext(AuthorityUrl);
objAuthenticationResult = objAuthenticationContext.AcquireTokenAsync(ResourceUrl, objCredentials);
return objAuthenticationResult.Result.AccessToken;
}
public override DbConnection GetConnection(string connectionString)
{
DbConnection objConnection = new SqlConnection();
try
{
objConnection.ConnectionString = connectionString;
((SqlConnection) objConnection).AccessToken = accessToken();
objConnection.Open();
}
catch (Exception)
{
objConnection.Dispose();
throw;
}
return objConnection;
}
}
}
Next is our HibernateUtil class
using Project.dataaccessobjects;
using Project.entities;
using NHibernate;
using NHibernate.Cfg;
using System.Collections.Generic;
namespace Project.hibernate
{
public class HibernateUtil
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
Configuration objConfiguration = new Configuration();
objConfiguration.SetProperties(properties());
objConfiguration.AddAssembly(typeof(Entity/Beam/Domain).Assembly);
_sessionFactory = objConfiguration.BuildSessionFactory();
}
return _sessionFactory;
}
}
private static Dictionary<string, string> properties()
{
Dictionary<string, string> obj = new Dictionary<string, string>();
obj.Add("connection.provider", "Project.connection.AzureSQLDatabase");
obj.Add("connection.connection_string", $"Server = tcp:{AzureKeyVaultDAO.getInstance().get("SQLServer")},1433; Initial Catalog = {AzureKeyVaultDAO.getInstance().get("Database")}; Persist Security Info = False; MultipleActiveResultSets = False; Encrypt = True; TrustServerCertificate = False");
obj.Add("dialect", "NHibernate.Dialect.MsSqlAzure2008Dialect");
obj.Add("show_sql", "true");
return obj;
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
}
At objConfiguration.BuildSessionFactory() we get the following exception:
NHibernate.HibernateException: 'Could not instantiate connection provider: Project.connection.AzureSQLDatabase' TypeLoadException: Could not load type Project.connection.AzureSQLDatabase. Possible cause: no assembly name specified.
Do you know what are we missing/skipping?
I found a better solution. Setting the property Environment.Hbm2ddlKeyWords, "none"
allowed me to execute the BuildSessionFactory
and open set the connection at SessionFactory.OpenSession()
.
namespace ExceptionsDB.hibernate
{
public class HibernateUtil
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
Configuration objConfiguration = new Configuration();
objConfiguration.SetProperties(properties());
//Add all Entities
objConfiguration.AddAssembly(typeof(Entity/Bean/Domain).Assembly);
_sessionFactory = objConfiguration.BuildSessionFactory();
}
return _sessionFactory;
}
}
private static Dictionary<string, string> properties()
{
Dictionary<string, string> obj = new Dictionary<string, string>();
obj.Add("dialect", "NHibernate.Dialect.MsSqlAzure2008Dialect");
obj.Add(Environment.Hbm2ddlKeyWords, "none");
obj.Add("show_sql", "true");
return obj;
}
public static ISession OpenSession()
{
//return SessionFactory.OpenSession(ADO.NET Connection); obsolete
return SessionFactory.WithOptions().Connection(ADO.NET Connection).OpenSession();
}
}
}