2

I have a unit test project in Visual Studio 2012 where I am storing the AdventureWorks MDF file for SQL Server 2012 (the file is named AdventureWorks2012_Data.mdf). In the Visual Studio Server Explorer, I am able to add the MDF in the Data Connections and browse the database. Right clicking on $/Data Connections/AsventureWorks2012_Data.mdf and selecting properties gives me access to the connection string as follows:

Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Projects\Common\Source\Framework\Framework.Data.Tests\AdventureWorks2012_Data.mdf;Integrated Security=True;Connect Timeout=30

I copied this into my Entity Framework connection string in the app.config file as follows:

<!-- Works :-) -->
<connectionStrings>
  <add name="AdventureWorksEntities" 
       connectionString="metadata=res://*/Repository2Tests.AdventureWorks.csdl|res://*/Repository2Tests.AdventureWorks.ssdl|res://*/Repository2Tests.AdventureWorks.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Projects\Common\Source\Framework\Framework.Data.Tests\AdventureWorks2012_Data.mdf;Integrated Security=True;Connect Timeout=30App=EntityFramework&quot;" 
       providerName="System.Data.EntityClient" />
</connectionStrings>

Note that the AttachDbFilename contains the full path of the MDF file as: C:\Projects\Common\Source\Framework\Framework.Data.Tests\AdventureWorks2012_Data.mdf

When I run the unit tests, everything is fine as expected.

I changed AttachDbFilename to |DataDirectory|\AdventureWorks2012_Data.mdf as described in "ADO.NET Entity Framework Connection Strings" and I set the DataDirectory as described in "ADO.NET |DataDirectory| where is this documented?" so that my connection string now is as follows:

<!-- Doesn't work :-( -->
<connectionStrings>
  <add name="AdventureWorksEntities" 
       connectionString="metadata=res://*/Repository2Tests.AdventureWorks.csdl|res://*/Repository2Tests.AdventureWorks.ssdl|res://*/Repository2Tests.AdventureWorks.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\AdventureWorks2012_Data.mdf;Integrated Security=True;Connect Timeout=30;App=EntityFramework&quot;" 
       providerName="System.Data.EntityClient" />
</connectionStrings>

The change to using |DataDirectory| resulted in the following runtime error:

System.Data.EntityException: The underlying provider failed on ConnectionString. ---> System.ArgumentException: URI formats are not supported.
HResult: -2147024809
at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength)
at System.IO.Path.GetFullPath(String path)
at System.Data.Common.ADP.GetFullPath(String filename)
at System.Data.Common.DbConnectionOptions.ExpandDataDirectory(String keyword, String value, String& datadir)
at System.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
at System.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
at System.Data.SqlClient.SqlConnection.ConnectionString_Set(DbConnectionPoolKey key)
at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
at System.Data.EntityClient.EntityConnection.ChangeConnectionString(String newConnectionString)
--- End of inner exception stack trace ---
HResult: -2146233087
at System.Data.EntityClient.EntityConnection.ChangeConnectionString(String newConnectionString)
at System.Data.Entity.Internal.LazyInternalConnection.TryInitializeFromAppConfig(String name, ConnectionStringSettingsCollection connectionStrings)
at System.Data.Entity.Internal.LazyInternalConnection.Initialize()
at System.Data.Entity.Internal.LazyInternalConnection.get_ConnectionHasModel()
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Internal.Linq.InternalSet`1.Create()

I have researched this for a couple days now and tried countless variations without success. I even debugged into Microsoft code but with compiler optimizations I am unable to see any debugging information on the stack.

Has anyone run across this specific problem?

Community
  • 1
  • 1
Philippe
  • 4,088
  • 4
  • 44
  • 49

1 Answers1

3

I finally solved the problem when I set out to submit a bug report to Microsoft and worked on reproduction steps.

To make a long story short, the problem was in the code that set the DataDirectory:

AppDomain.CurrentDomain.SetData("DataDirectory", dataDirectory);

The issue was that my dataDirectory variable was getting initialized as file://C:/myfolder/etc/ instead of C:\myfolder\etc\. I corrected the code responsible for that and the problem is resolved. Incidentally, the code I used is:

// in the test assembly initializer
String dataDirectory = AppDomain.CurrentDomain.GetApplicationPath();
AppDomain.CurrentDomain.SetData("DataDirectory", dataDirectory);

// GetApplicationPath calls into the following extension method
/// <summary>
/// Defines a set of extension methods on <see cref="AppDomain"/> objects.
/// </summary>
public static class AppDomainExtensions
{
    /// <summary>
    /// Gets the application path (works for both ASP.NET and unit tests).
    /// </summary>
    /// <returns></returns>
    public static string GetApplicationPath(this AppDomain appDomain)
    {
        string binPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        return binPath.Substring(0, binPath.LastIndexOf("bin", StringComparison.InvariantCultureIgnoreCase));
    }
}
Philippe
  • 4,088
  • 4
  • 44
  • 49
  • 1
    A small note that this may fail if the project's output directory is for instance "Build" instead of "bin". Nonetheless, a good solution! – Dr1Ku Oct 10 '13 at 10:19
  • 1
    I had the same issue in a project of mine, where original programmer had used GetExecutingAssembly().GetName().Codebase. Switching over to GetExecutingAssembly().Location fixed the issue as provided here. – Tanveer Badar Aug 25 '14 at 07:48