The type Database cannot be constructed. You must configure the container to supply this value.

Topics: Enterprise Library Core
Oct 24, 2012 at 11:20 AM
Edited Oct 24, 2012 at 11:21 AM
I am getting the following error after I upgraded our Enterprise Library from version 4.1 to 5. 

Errors:

The type Database cannot be constructed. You must configure the container to supply this value.

ResolutionFailedException: Resolution of the dependency failed, type = "Microsoft.Practices.EnterpriseLibrary.Data.Database", name = "ApplicationCoreLibraryDB". Exception occurred while: while resolving. Exception is:
InvalidOperationException - The type Database cannot be constructed. You must configure the container to supply this value.
----------------------------------------------- At the time of the exception, the container was:    Resolving Microsoft.Practices.EnterpriseLibrary.Data.Database,ApplicationCoreLibraryDB ]   
Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides) +440   
Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, String name, IEnumerable`1 resolverOverrides) +45   
Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides) +43   
Microsoft.Practices.Unity.UnityServiceLocator.DoGetInstance(Type serviceType, String key) +134   
Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance(Type serviceType, String key) in c:\Home\Chris\Projects\CommonServiceLocator\main\Microsoft.Practices.ServiceLocation\ServiceLocatorImplBase.cs:49 
[ActivationException: Activation error occured while trying to get instance of type Database, key "ApplicationCoreLibraryDB"]   
Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance(Type serviceType, String key) in c:\Home\Chris\Projects\CommonServiceLocator\main\Microsoft.Practices.ServiceLocation\ServiceLocatorImplBase.cs:53   
Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance(String key) in c:\Home\Chris\Projects\CommonServiceLocator\main\Microsoft.Practices.ServiceLocation\ServiceLocatorImplBase.cs:103   
Microsoft.Practices.EnterpriseLibrary.Data.DatabaseFactory.InnerCreateDatabase(String name) in c:\EntLib\Entlib\Source\Blocks.Desktop\Data\Src\Data\DatabaseFactory.cs:82   
Microsoft.Practices.EnterpriseLibrary.Data.DatabaseFactory.CreateDatabase(String name) in c:\EntLib\Entlib\Source\Blocks.Desktop\Data\Src\Data\DatabaseFactory.cs:68   
ApplicationCoreLibrary.Data.SystemSettingData.GetDetailByName(String systemSettingName) in C:\development\ApplicationShell\ApplicationCoreLibrary\Data\SystemSettingData.cs:81   
ApplicationCoreLibrary.Manager.SystemSettingManager.GetDetailByName(String systemSettingName) in C:\development\ApplicationShell\ApplicationCoreLibrary\Manager\SystemSettingManager.cs:63   
ApplicationCoreLibrary.Helper.GlobalsManager.LoadGlobalSettings() in C:\development\ApplicationShell\ApplicationCoreLibrary\Helper\GlobalsManager.cs:136   
ApplicationCoreLibrary.Helper.GlobalsManager..ctor() in C:\development\ApplicationShell\ApplicationCoreLibrary\Helper\GlobalsManager.cs:72   
ApplicationCoreLibrary.Helper.GlobalsManager..cctor() in C:\development\ApplicationShell\ApplicationCoreLibrary\Helper\GlobalsManager.cs:17 
[TypeInitializationException: The type initializer for 'ApplicationCoreLibrary.Helper.GlobalsManager' threw an exception.]   
ApplicationCoreLibrary.Helper.GlobalsManager.get_DbConnectionString() in C:\development\ApplicationShell\ApplicationCoreLibrary\Helper\GlobalsManager.cs:26   
GlobalsManager.SetGlobalTransactionLevel() in C:\development\ApplicationShell\ApplicationShell\ApplicationCore\Helper\GlobalsManager.cs:509   
GlobalsManager.Application_PreRequestHandlerExecute(Object source, EventArgs e) in C:\development\ApplicationShell\ApplicationShell\ApplicationCore\Helper\GlobalsManager.cs:247   
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +148    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

Web.config:
  <configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging" requirePermission="true" />
    <section name="cachingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Caching.Configuration.CacheManagerSettings, Microsoft.Practices.EnterpriseLibrary.Caching" requirePermission="true" />
 <
section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />    </configSections>

 <connectionStrings>     <add name="ApplicationCoreLibraryDB" connectionString="Data Source=;Initial Catalog=;Persist Security Info=True;User ID=;Password="       providerName="SQLDataAccess" />   </connectionStrings>

Code:
 var db = DatabaseFactory.CreateDatabase(GlobalsManager.DbConnectionString) as SQLDataAccess;


Oct 24, 2012 at 6:02 PM

You don't need to pass the connection string to the CreateDatabase method just the database name (i.e. connectionString name).  E.g.:

var db = DatabaseFactory.CreateDatabase("ApplicationCoreLibraryDB");

Just curious if SQLDataAccess is your own Database and Database Provider?  Usually for SQL Server the config would look like:

    <add name="ApplicationCoreLibraryDB" connectionString="Data Source=;Initial Catalog=;Persist Security Info=True;User ID=;Password=&quot;"
      providerName="System.Data.SqlClient" />

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Oct 25, 2012 at 9:10 AM
Edited Oct 25, 2012 at 9:12 AM

Hi Randy,

Thanks for your response.

Yes, SQLDataAccess is our own Database Provider. It works when the providerName = "System.Data.SqlClient".

The SQLDataAccess Class looks as follows:

namespace DataAccessLibrary.SQL
{
 
    [SqlClientPermission(SecurityAction.Demand)]
    [ConfigurationElementType(typeof(SQLDataAccess))]
    public class SQLDataAccess : SqlDatabase
    {
        public int CommandTimeout { getset; }
 
        public SQLDataAccess(string connectionString)
            : base(connectionString)
        {
            CommandTimeout = 120;
           
        }
    }
}
namespace DataAccessLibrary.SQL
{
    /// <summary>
    /// Represents the process to build an instance of <see cref="SqlDatabase"/> described by configuration information.
    /// </summary>
    public class SQLDataAccessData : SqlDatabaseData
    {
        public SQLDataAccessData(ConnectionStringSettings connectionStringSettings, IConfigurationSource configurationSource)
            : base(connectionStringSettings, configurationSource)
        { 
        }
 
        public override IEnumerable<TypeRegistration> GetRegistrations()
        {
            yield return new TypeRegistration<Database>(
                () => new SQLDataAccess(ConnectionString))
            {
                Name = this.Name,
                Lifetime = TypeRegistrationLifetime.Transient
            }; 
 
        }
    }
}



Oct 26, 2012 at 4:54 AM

You need to create a custom DbProviderFactory (e.g. SQLDataAccess):

    public class SQLDataAccessFactory : DbProviderFactory
    {
        /// <summary>
        /// Singleton instance. Required by the Enterprise Library.
        /// </summary>
        public static SQLDataAccessFactory Instance = new SQLDataAccessFactory();

        private static DbProviderFactory _factory;

        private SQLDataAccessFactory()
            : base()
        {
            _factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        }
    }

And then map it to your custom database:

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    </configSections>
  <dataConfiguration defaultDatabase="ApplicationCoreLibraryDB">
    <providerMappings>
      <add databaseType="DataAccessCustomDbProvider_400588.SQLDataAccess, DataAccessCustomDbProvider_400588, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
        name="SQLDataAccessFactory.SqlClient" />
    </providerMappings>
  </dataConfiguration>
  <connectionStrings>
    <add name="ApplicationCoreLibraryDB" connectionString="data source=.\SQLEXPRESS;Database=Logging;Integrated Security=SSPI;User Instance=false"
      providerName="SQLDataAccessFactory.SqlClient" />
  </connectionStrings>
  <system.data>
    <DbProviderFactories>
      <add name="SQLDataAccessFactory"
           invariant="SQLDataAccessFactory.SqlClient"
           support="FF"
           description="Custom SQLDataAccessFactory.SqlClient .NET Framework Data Provider for SqlServer"
           type="DataAccessCustomDbProvider.SQLDataAccessFactory, DataAccessCustomDbProvider"
      />
    </DbProviderFactories>
  </system.data>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Oct 26, 2012 at 11:48 AM

Hi Randy,

I created a new SQLDataAccessFactory Class and implemented the Code and Settings as you specified above. Now I am getting another error: The type 'DataAccessLibrary.SQL.SQLDataAccess, DataAccessLibrary.SQL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' cannot be resolved. Please verify the spelling is correct or that the full type name is provided.

Not sure what I am doing wrong.

  <dataConfiguration defaultDatabase="ApplicationCoreLibraryDB">
    <providerMappings>
      <add databaseType="DataAccessLibrary.SQL.SQLDataAccess, DataAccessLibrary.SQL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
        name="SQLDataAccessFactory.SqlClient" />
    </providerMappings>
  </dataConfiguration>

  <system.data>
    <DbProviderFactories>
      <add name="SQLDataAccessFactory"
           invariant="SQLDataAccessFactory.SqlClient"
           support="FF"
           description="Custom SQLDataAccessFactory.SqlClient .NET Framework Data Provider for SqlServer"
           type="DataAccessLibrary.SQL.SQLDataAccessFactory, DataAccessLibrary.SQL"/>
    </DbProviderFactories>
  </system.data>
I also have the following Code in the SQLDataAccess Class.
        /// <summary>
        /// Executes the command and returns a System.Data.IDataReader through which the result can be read.
        /// It is the responsibility of the caller to close the connection and reader when finished.
        /// </summary>
        /// <param name="dbCommand"></param>
        /// <returns></returns>
        public new IDataReader ExecuteReader(DbCommand dbCommand)
        {
            IDataReader tempReader = null;
            SQLLog sqlLog = new SQLLog(dbCommand);
 
            if (dbCommand.CommandTimeout < CommandTimeout)
                dbCommand.CommandTimeout = CommandTimeout;
 
            try
            {
                tempReader = base.ExecuteReader(dbCommand);
            }
            catch (Exception ex)
            {
                sqlLog.ErrorMessage = ex.Message;
                sqlLog.WriteLog();
 
                AlertManager.SendEmailOnFailure(ex, dbCommand);
 
                throw ex;
            }
 
            sqlLog.EndExecutionDateTime = DateTime.Now;
            sqlLog.WriteLog();
 
            return tempReader;
        }
 
        /// <summary>
        /// Executes the command and returns the number of rows affected.
        /// </summary>
        /// <param name="dbCommand"></param>
        /// <returns></returns>
        public new int ExecuteNonQuery(DbCommand dbCommand)
        {
            SQLLog sqlLog = new SQLLog(dbCommand);
            int tempInt = 0;
 
            if (dbCommand.CommandTimeout < CommandTimeout)
                dbCommand.CommandTimeout = CommandTimeout;
 
            try
            {
                tempInt = base.ExecuteNonQuery(dbCommand);
            }
            catch (Exception ex)
            {
                sqlLog.ErrorMessage = ex.Message;
                sqlLog.WriteLog();
 
                AlertManager.SendEmailOnFailure(ex, dbCommand);
 
                throw ex;
            }
 
            sqlLog.EndExecutionDateTime = DateTime.Now;
            sqlLog.WriteLog();
 
            return tempInt;
        }
 
        /// <summary>
        /// Executes the command and returns the first column of the first row in the result set returned by the query.
        /// Extra columns or rows are ignored
        /// </summary>
        /// <param name="dbCommand"></param>
        /// <returns></returns>
        public new object ExecuteScalar(DbCommand dbCommand)
        {
            SQLLog sqlLog = new SQLLog(dbCommand);
            object tempObj = new object();
 
            if (dbCommand.CommandTimeout < CommandTimeout)
                dbCommand.CommandTimeout = CommandTimeout;
 
            try
            {
                tempObj = base.ExecuteScalar(dbCommand);
            }
            catch (Exception ex)
            {
                sqlLog.ErrorMessage = ex.Message;
                sqlLog.WriteLog();
 
                AlertManager.SendEmailOnFailure(ex, dbCommand);
 
                throw ex;
            }
 
            sqlLog.EndExecutionDateTime = DateTime.Now;
            sqlLog.WriteLog();
 
            return tempObj;
        }
 
        public new DataSet ExecuteDataSet(DbCommand dbCommand)
        {
            SQLLog sqlLog = new SQLLog(dbCommand);
            DataSet dsTemp = new DataSet();
 
            if (dbCommand.CommandTimeout < CommandTimeout)
                dbCommand.CommandTimeout = CommandTimeout;
 
            try
            {
                dsTemp = base.ExecuteDataSet(dbCommand);
            }
            catch (Exception ex)
            {
                sqlLog.ErrorMessage = ex.Message;
                sqlLog.WriteLog(System.Diagnostics.TraceEventType.Error);
 
                AlertManager.SendEmailOnFailure(ex, dbCommand);
 
                throw ex;
            }
 
            sqlLog.EndExecutionDateTime = DateTime.Now;
            sqlLog.WriteLog();
 
            return dsTemp;
        }
Oct 26, 2012 at 2:46 PM

Hi Randy,

Is it possible that you can send me a working copy of the project.

Kind Regards,

Elana

Oct 26, 2012 at 4:29 PM

You can get a sample project here

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Oct 31, 2012 at 11:38 AM

Hi Randy,

Thanks for the sample project.

Is there a way I can add the following code to the SQLDataAccessFactory Class as this was in the SQLDataAccess Class which inherited SQLDatabaseData:

        /// <summary>
        /// Executes the command and returns a System.Data.IDataReader through which the result can be read.
        /// It is the responsibility of the caller to close the connection and reader when finished.
        /// </summary>
        /// <param name="dbCommand"></param>
        /// <returns></returns>
        public new IDataReader ExecuteReader(DbCommand dbCommand)
        {
            IDataReader tempReader = null;
            SQLLog sqlLog = new SQLLog(dbCommand);
 
            if (dbCommand.CommandTimeout < CommandTimeout)
                dbCommand.CommandTimeout = CommandTimeout;
 
            try
            {
                tempReader = base.ExecuteReader(dbCommand);
            }
            catch (Exception ex)
            {
                sqlLog.ErrorMessage = ex.Message;
                sqlLog.WriteLog();
 
                AlertManager.SendEmailOnFailure(ex, dbCommand);
 
                throw ex;
            }
 
            sqlLog.EndExecutionDateTime = DateTime.Now;
            sqlLog.WriteLog();
 
            return tempReader;
        }
 
        /// <summary>
        /// Executes the command and returns the number of rows affected.
        /// </summary>
        /// <param name="dbCommand"></param>
        /// <returns></returns>
        public new int ExecuteNonQuery(DbCommand dbCommand)
        {
            SQLLog sqlLog = new SQLLog(dbCommand);
            int tempInt = 0;
 
            if (dbCommand.CommandTimeout < CommandTimeout)
                dbCommand.CommandTimeout = CommandTimeout;
 
            try
            {
                tempInt = base.ExecuteNonQuery(dbCommand);
            }
            catch (Exception ex)
            {
                sqlLog.ErrorMessage = ex.Message;
                sqlLog.WriteLog();
 
                AlertManager.SendEmailOnFailure(ex, dbCommand);
 
                throw ex;
            }
 
            sqlLog.EndExecutionDateTime = DateTime.Now;
            sqlLog.WriteLog();
 
            return tempInt;
        }
 
        /// <summary>
        /// Executes the command and returns the first column of the first row in the result set returned by the query.
        /// Extra columns or rows are ignored
        /// </summary>
        /// <param name="dbCommand"></param>
        /// <returns></returns>
        public new object ExecuteScalar(DbCommand dbCommand)
        {
            SQLLog sqlLog = new SQLLog(dbCommand);
            object tempObj = new object();
 
            if (dbCommand.CommandTimeout < CommandTimeout)
                dbCommand.CommandTimeout = CommandTimeout;
 
            try
            {
                tempObj = base.ExecuteScalar(dbCommand);
            }
            catch (Exception ex)
            {
                sqlLog.ErrorMessage = ex.Message;
                sqlLog.WriteLog();
 
                AlertManager.SendEmailOnFailure(ex, dbCommand);
 
                throw ex;
            }
 
            sqlLog.EndExecutionDateTime = DateTime.Now;
            sqlLog.WriteLog();
 
            return tempObj;
        }
 
        public new DataSet ExecuteDataSet(DbCommand dbCommand)
        {
            SQLLog sqlLog = new SQLLog(dbCommand);
            DataSet dsTemp = new DataSet();
 
            if (dbCommand.CommandTimeout < CommandTimeout)
                dbCommand.CommandTimeout = CommandTimeout;
 
            try
            {
                dsTemp = base.ExecuteDataSet(dbCommand);
            }
            catch (Exception ex)
            {
                sqlLog.ErrorMessage = ex.Message;
                sqlLog.WriteLog(System.Diagnostics.TraceEventType.Error);
 
                AlertManager.SendEmailOnFailure(ex, dbCommand);
 
                throw ex;
            }
 
            sqlLog.EndExecutionDateTime = DateTime.Now;
            sqlLog.WriteLog();
 
            return dsTemp;
        }
Nov 1, 2012 at 4:42 AM

You should override the ExecuteNonQuery, ExecuteScalar, and ExecuteReader methods in the public class SQLDataAccess : SqlDatabase since the base Database class is where those methods are defined.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com