Microsoft.Practices.ServiceLocation.ActivationException

Topics: Building and extending application blocks, Data Access Application Block, Enterprise Library Core
Feb 16, 2012 at 5:31 PM

I am trying to use an external config file for the database config using the Enterprise Library Configuration File base configuration source.  This works fine on my desktop but when I deploy it to a Server 2003 web server I get this error:

Exception Type: Microsoft.Practices.ServiceLocation.ActivationException

Message: Activation error occured while trying to get instance of type Database, key ""

Data: System.Collections.ListDictionaryInternal

TargetSite: System.Object GetInstance(System.Type, System.String)

HelpLink: NULL

Source: Microsoft.Practices.ServiceLocation

 

StackTrace Information

*********************************************

   at Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance(Type serviceType, String key) in c:\Home\Chris\Projects\CommonServiceLocator\main\Microsoft.Practices.ServiceLocation\ServiceLocatorImplBase.cs:line 53

   at Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance[TService](String key) in c:\Home\Chris\Projects\CommonServiceLocator\main\Microsoft.Practices.ServiceLocation\ServiceLocatorImplBase.cs:line 103

   at Microsoft.Practices.EnterpriseLibrary.Data.DatabaseFactory.InnerCreateDatabase(String name) in c:\EntLib\Entlib\Source\Blocks.Desktop\Data\Src\Data\DatabaseFactory.cs:line 82

   at Microsoft.Practices.EnterpriseLibrary.Data.DatabaseFactory.CreateDatabase() in c:\EntLib\Entlib\Source\Blocks.Desktop\Data\Src\Data\DatabaseFactory.cs:line 40

   at VendorClaimManagement.DataAccess.FetchClaims(Int32 vendorId) in C:\TFS\CHS\1-Development\Intranet\Main\VendorClaimManagement\DAL\DataAccess.vb:line 12

I have also tried it on Server 2008 with the same result. 

If I create the database directly like this it works: 

Dim dataSource As New FileConfigurationSource("C:\datalinkfiles\Security\AZManConnectionStrings.config")

 

Dim OracleConfig As System.Configuration.ConnectionStringsSection = CType(dataSource.GetSection("connectionStrings"), System.Configuration.ConnectionStringsSection)  

Dim element As System.Configuration.ConnectionStringSettingsCollection = OracleConfig.ConnectionStrings

Try

m_db = New EntLib.Oracle.OracleDatabase(element.Item("Security Connection String").ConnectionString)

Catch ex As Exception

Throw New InvalidOperationException(message.ToString, ex)

End Try

I also can use Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationSourceFactory.Create as the configuration source and it works.

So why can't the ServiceLocation find the external config?

 

Feb 17, 2012 at 3:05 PM

As you mention this is usually a configuration issue -- it sounds like the configuration file is not being loaded.  

You say it works fine on your desktop machine -- are you using IIS on your desktop?

Can you post code/config where you load the configuration?

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

Feb 17, 2012 at 5:48 PM

I use ASP .NET Development Server by default but I did try running it through IIS on my desktop (IIS5) and it worked.  I only load the configuration as a workaround.

Here is test code that works on my desktop and fails on the server:

Imports Microsoft.VisualBasic
Imports System.Data
Imports EntLib = Microsoft.Practices.EnterpriseLibrary.Data

Namespace Test
    Public NotInheritable Class Data

        Public Shared Function GetData() As DataSet
            Dim ds As System.Data.DataSet
            Dim m_db As EntLib.Database = EntLib.DatabaseFactory.CreateDatabase()
            Dim dbCommand As System.Data.Common.DbCommand = m_db.GetStoredProcCommand("Ncs.Temp.Blah")

            m_db.DiscoverParameters(dbCommand)

            ds = m_db.ExecuteDataSet(dbCommand)

            Return ds

        End Function

    End Class

End Namespace

It breaks in CreateDatabase().

This is the relevant parts of my config:


<configuration>
  <configSections>
    <section name="enterpriseLibrary.ConfigurationSource" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationSourceSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true"/>
  </configSections>
  <enterpriseLibrary.ConfigurationSource selectedSource="File-based Configuration Source">
    <sources>
      <add name="System Configuration Source" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.SystemConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add name="File-based Configuration Source" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.FileConfigurationSource, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
           filePath="external.config"/>
    </sources>
    <redirectSections>
      <add sourceName="File-based Configuration Source" name="dataConfiguration"/>
    </redirectSections>
  </enterpriseLibrary.ConfigurationSource>
</configuration>
And this is the external.config:
<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="Database Connection String">
        <providerMappings>
            <add databaseType="NYSIF.EnterpriseLibrary.Data.Oracle.OracleDatabase, NYSIF.EnterpriseLibrary.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=4a65549a54109ede"
                name="Oracle.DataAccess.Client" />
        </providerMappings>
    </dataConfiguration>
    <connectionStrings>
        <add name="Database Connection String" connectionString="Data Source=DEVRAC;Persist Security Info=True;User ID=USER;Password=PWD"
            providerName="Oracle.DataAccess.Client" />
    </connectionStrings>
</configuration>
Feb 17, 2012 at 7:03 PM
Edited Apr 2, 2012 at 8:43 PM

Thanks for the info.  I was able to replicate the behavior.  I don't have Oracle installed but if I change the default database to be SqlServer then the database can be resolved.  

So it looks like the issue is with the provider name not being able to be resolved.  When this happens the database instance does not get added to the container so the resolve of the database fails.

I would verify that the Oracle provider is installed and can be located by the .NET runtime.

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

Feb 17, 2012 at 8:19 PM

SqlServer shows up in the collection of connection strings even when there are no connection strings in the config.  I tried putting the database config in the web.config but it still does not work on the server.  If I use this code instead of the DatabaseFactory the connectionStringSettings are found and the database is created using the Oracle provider.

        Public Shared Function GetData2() As DataSet
            Dim ds As System.Data.DataSet
            Dim m_db As NYSIF.EnterpriseLibrary.Data.Oracle.OracleDatabase

            ' Get the connection string using EnterpriseLibrary methods
            Dim config As IConfigurationSource = Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationSourceFactory.Create
            Dim OracleConfig As System.Configuration.ConnectionStringsSection = CType(config.GetSection("connectionStrings"), System.Configuration.ConnectionStringsSection)
            Dim connectionStringsCollection As System.Configuration.ConnectionStringSettingsCollection = OracleConfig.ConnectionStrings
            Dim connectionString As String = connectionStringsCollection.Item("Database Connection String").ConnectionString

            'Instantiate the database object with the connection string

            m_db = New NYSIF.EnterpriseLibrary.Data.Oracle.OracleDatabase(connectionString)

            Dim dbCommand As System.Data.Common.DbCommand = m_db.GetStoredProcCommand("Ncs.Temp.Blah")

            m_db.DiscoverParameters(dbCommand)

            ds = m_db.ExecuteDataSet(dbCommand)

            Return ds

        End Function

Feb 17, 2012 at 8:56 PM

Okay, I changed the config to use System.Data.OracleClient even though my custom Database uses the Oracle provider and now it works on the server!  I checked on the server and the Oracle provider is in the GAC so I don't understand why the Enterprise Library cannot find or instantiate it on the server but I can live with this workaround.

<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="Database Connection String">
        <providerMappings>
            <add databaseType="NYSIF.EnterpriseLibrary.Data.Oracle.OracleDatabase, NYSIF.EnterpriseLibrary.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=4a65549a54109ede"
                name="System.Data.OracleClient" />
        </providerMappings>
    </dataConfiguration>
    <connectionStrings>
        <add name="Database Connection String" connectionString="Data Source=DEVRAC;Persist Security Info=True;User ID=NCS;Password=NCS"
            providerName="System.Data.OracleClient" />
    </connectionStrings>
</configuration>
Feb 17, 2012 at 9:01 PM
Edited Feb 17, 2012 at 9:27 PM

Connection String information is also pulled from machine.config which is where those "rogue" SqlServer connections usually appear from.

I wonder if the ODP.NET provider is registered as a DBProviderFactory in machine config?

E.g.:

 

<system.data>
  <DbProviderFactories>
    <add name="Oracle Data Provider for .NET" invariant="Oracle.DataAccess.Client"
        description="Oracle Data Provider for .NET" 
type="Oracle.DataAccess.Client.OracleClientFactory, Oracle.DataAccess, Version=, Culture=neutral, PublicKeyToken=89b483f429c47342" /> </DbProviderFactories> </system.data>

You could also compare machine.config files between the two servers (both 32 and 64 bit).

You could also write a small program to verify that OracleClientFactory is in the DbProviderFactory list:

 

            DataTable table = DbProviderFactories.GetFactoryClasses();

            foreach (DataRow row in table.Rows)
            {
                Console.WriteLine("Factory Found:");
foreach (DataColumn column in table.Columns) { Console.WriteLine("\t" + row[column]); } }

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

 

Feb 17, 2012 at 9:11 PM

I dropped that <system.data> section into my web.config, switched back to the Oracle.DataAccess.Client in the database settings and that worked.  Now I'll just have to talk to the Server Admins about adding it to the machine.config.

Thanks for all your help, I never would have figured this out on my own.