|数据目录|的位置如何在连接字符串解决?

How is location of |Data Directory| in connection strings resolved?

如果我创建一个 asp.net 项目并使用 entity framework 创建一个数据库,类似这样的内容会自动添加到 web.config:

中的连接字符串中
<add name="DefaultConnection" connectionString="data source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\WebAppName.mdf;initial catalog=WebAppName;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />

请注意,它使用 |Data Directory| 而不是完全限定的文件路径,在本例中,它指向“App_Data”文件夹。 Here's 一些文档如何解释它:

The presence of User Instance=true and AttachDBFilename=|DataDirectory| cause SqlConnectionHelper to conclude that the connection string targets SQL Server Express and triggers the database's creation. (The presence of data source=.\SQLEXPRESS in the connection string does not factor into the decision, because SqlConnectionHelper supports non-default as well as default instances of SQL Server Express.) The |DataDirectory| portion of the connection string specifies that the MDF file is located inthe App_Data directory. SqlConnectionHelper derives the database name from the MDF file name. It also creates an App_Data folder to hold the MDF if the folder doesn't already exist.

除非,如果我在控制台应用程序中使用 Entity Framework,那么 none 是正确的——您只会得到一个异常,说明在指定路径中没有文件,它将忽略您创建的任何 App_Data 个文件夹,并且如果有 none 个文件夹则无法创建。如果您完全删除 AttachDBFilename 部分,它将起作用,但会在 .exe 文件所在的本地输出箱中创建数据库。 Google tells me 您可以使用 AppDomain.SetData 手动设置 |Data Directory| 但显然对于控制台应用程序来说仍然不正确(得到编译错误说 "An object reference is required")。

所以我的问题是,|Data Directory| 的位置究竟是如何解析的?据我所知,控制台应用程序和 Asp.net 应用程序之间的差异意味着解决方案不能仅在 SQL Server Express 中发生,因为两者都使用相同的安装。那么它是否发生在 asp.net 服务器中?或者是否有在 asp.net 个项目中创建的隐藏设置文件?

这是指定 |DataDirectory|

位置的代码

GetDataDirectory

[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
internal static string GetDataDirectory() {
    if (HostingEnvironment.IsHosted)
        return Path.Combine(HttpRuntime.AppDomainAppPath, HttpRuntime.DataDirectoryName);

    string dataDir = AppDomain.CurrentDomain.GetData(s_strDataDir) as string;
    if (string.IsNullOrEmpty(dataDir)) {
        string appPath = null;

#if !FEATURE_PAL // FEATURE_PAL does not support ProcessModule
        Process p = Process.GetCurrentProcess();
        ProcessModule pm = (p != null ? p.MainModule : null);
        string exeName = (pm != null ? pm.FileName : null);

        if (!string.IsNullOrEmpty(exeName))
            appPath = Path.GetDirectoryName(exeName);
#endif // !FEATURE_PAL

        if (string.IsNullOrEmpty(appPath))
            appPath = Environment.CurrentDirectory;

        dataDir = Path.Combine(appPath, HttpRuntime.DataDirectoryName);
        AppDomain.CurrentDomain.SetData(s_strDataDir, dataDir, new FileIOPermission(FileIOPermissionAccess.PathDiscovery, dataDir));
    }

    return dataDir;
}