Исключение "форматы URI не поддерживаются" при использовании |DataDirectory| в строке подключения Entity Framework
У меня есть проект модульного теста в Visual Studio 2012, где я храню файл AdventureWorks MDF для SQL Server 2012 (файл называется AdventureWorks2012_Data.mdf). В Visual Studio Server Explorer я могу добавить MDF в Data Connections и просмотреть базу данных. Щелкните правой кнопкой мыши на $/Data Connections/AsventureWorks2012_Data.mdf и выберите свойства, чтобы получить доступ к строке подключения следующим образом:
Источник данных =(LocalDB)\v11.0;AttachDbFilename=C:\Projects\Common\Source\Framework\Framework.Data.Tests\AdventureWorks2012_Data.mdf; Интегрированная безопасность =True; Время ожидания подключения =30
Я скопировал это в мою строку подключения Entity Framework в файле app.config следующим образом:
<!-- 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="Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Projects\Common\Source\Framework\Framework.Data.Tests\AdventureWorks2012_Data.mdf;Integrated Security=True;Connect Timeout=30App=EntityFramework""
providerName="System.Data.EntityClient" />
</connectionStrings>
Обратите внимание, что AttachDbFilename содержит полный путь к файлу MDF: C:\Projects\Common\Source\Framework\Framework.Data.Tests\AdventureWorks2012_Data.mdf
Когда я запускаю юнит-тесты, все нормально, как и ожидалось.
Я изменил AttachDbFilename на |DataDirectory|\AdventureWorks2012_Data.mdf, как описано в " Строка подключения ADO.NET Entity Framework", и я установил DataDirectory, как описано в " ADO.NET | DataDirectory |, где это задокументировано?", Так что теперь моя строка подключения как следует:
<!-- 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="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\AdventureWorks2012_Data.mdf;Integrated Security=True;Connect Timeout=30;App=EntityFramework""
providerName="System.Data.EntityClient" />
</connectionStrings>
Изменение использования | DataDirectory | привел к следующей ошибке во время выполнения:
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()
Я исследовал это в течение пары дней и попробовал бесчисленные варианты без успеха. Я даже отлаживал в коде Microsoft, но с оптимизацией компилятора я не вижу никакой информации об отладке в стеке.
Кто-нибудь сталкивался с этой конкретной проблемой?
1 ответ
Я наконец решил проблему, когда намеревался отправить отчет об ошибке в Microsoft и поработал над этапами воспроизведения.
Короче говоря, проблема была в коде, который устанавливает DataDirectory:
AppDomain.CurrentDomain.SetData("DataDirectory", dataDirectory);
Проблема заключалась в том, что моя переменная dataDirectory инициализировалась как file://C:/myfolder/etc/
вместо C:\myfolder\etc\
, Я исправил код, отвечающий за это, и проблема решена. Кстати, код, который я использовал:
// 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));
}
}