使用 Visual Studio 或 Visual Web Developer 通过SQL Server Compact部署 ASP.NET Web 应用程序:部署SQL Server Compact数据库 - 第 2 个,共 12 个

作者 :Tom Dykstra

下载初学者项目

本系列教程介绍如何使用 Visual Studio 2012 RC 或 Visual Studio Express 2012 RC for Web 部署 (发布) 包含 SQL Server Compact 数据库的 ASP.NET Web 应用程序项目。 如果安装 Web 发布更新,也可以使用 Visual Studio 2010。 有关该系列的简介,请参阅 该系列中的第一个教程

有关演示 Visual Studio 2012 RC 版本后引入的部署功能的教程,演示如何部署除 SQL Server Compact 以外的SQL Server版本,以及如何部署到 Azure 应用服务 Web 应用,请参阅使用 Visual Studio ASP.NET Web 部署

概述

本教程介绍如何设置两个SQL Server Compact数据库和用于部署的数据库引擎。

对于数据库访问,Contoso University 应用程序需要以下软件,这些软件必须随应用程序一起部署,因为它不包含在.NET Framework中:

此外,还必须部署应用程序两个数据库中的数据的所有) 的数据库结构和某些 (。 通常,在开发应用程序时,将测试数据输入到不希望部署到实时站点的数据库中。 但是,还可以输入一些想要部署的生产数据。 在本教程中,你将配置 Contoso University 项目,以便在部署时包括所需的软件和正确的数据。

提醒:如果在完成本教程时收到错误消息或某些内容不起作用,请务必检查故障排除页面

SQL Server Compact与SQL Server Express

示例应用程序使用 SQL Server Compact 4.0。 对于网站来说,此数据库引擎是一个相对较新的选项;早期版本的 SQL Server Compact 在 Web 托管环境中不起作用。 与使用SQL Server Express进行开发和部署到完整SQL Server更常见的方案相比,SQL Server Compact具有一些优势。 根据所选的托管提供程序,SQL Server Compact部署可能更便宜,因为某些提供商会收取额外的费用以支持完整的SQL Server数据库。 SQL Server Compact无需额外付费,因为可以将数据库引擎本身部署为 Web 应用程序的一部分。

但是,还应注意其限制。 SQL Server Compact不支持存储过程、触发器、视图或复制。 (有关SQL Server Compact不支持的SQL Server功能的完整列表,请参阅 SQL Server Compact 与 SQL Server 之间的差异。) 此外,还有一些可用于在 中操作架构和数据的工具SQL Server Express和SQL Server数据库不适用于SQL Server Compact。 例如,不能在 Visual Studio 中将 SQL Server Management Studio 或 SQL Server Data Tools 用于 SQL Server Compact 数据库。 可以使用其他选项来使用SQL Server Compact数据库:

  • 可以在 Visual Studio 中使用服务器资源管理器,它为SQL Server Compact提供有限的数据库操作功能。
  • 可以使用 WebMatrix 的数据库操作功能,该功能比服务器资源管理器更多。
  • 可以使用功能相对完整的第三方或开放源代码工具,例如SQL Server Compact工具箱SQL Compact 数据和架构脚本实用工具
  • 可以编写和运行自己的 DDL (数据定义语言) 脚本来操作数据库架构。

可以从SQL Server Compact开始,然后随着需求的发展而升级。 本系列后面的教程介绍如何从SQL Server Compact迁移到SQL Server Express和SQL Server。 但是,如果要创建新应用程序,并且预计在不久的将来需要SQL Server,则最好从SQL Server或SQL Server Express开始。

为部署配置 SQL Server Compact 数据库引擎

通过安装以下 NuGet 包,添加了 Contoso University 应用程序中访问数据所需的软件:

这些链接指向这些包的当前版本,这些包可能比为本教程下载的初学者项目中安装的版本更新。 若要部署到托管提供程序,请确保使用 Entity Framework 5.0 或更高版本。 早期版本的 Code First 迁移 需要完全信任,并且在许多托管提供程序中,应用程序将在中等信任中运行。 有关中等信任的详细信息,请参阅 部署到 IIS 作为测试环境 教程。

NuGet 包安装通常会处理与应用程序一起部署此软件所需的一切。 在某些情况下,这涉及到更改Web.config文件和添加 PowerShell 脚本等任务,这些脚本在生成解决方案时运行。 如果要在不使用 NuGet 的情况下添加对这些功能 ((如 SQL Server Compact 和 Entity Framework) )的支持,请确保知道 NuGet 包安装的功能,以便可以手动执行相同的工作。

有一个例外,即 NuGet 不会处理为确保成功部署而必须执行的所有操作。 SqlServerCompact NuGet 包向项目添加生成后脚本,该脚本将本机程序集复制到项目 bin 文件夹下的 x86amd64 子文件夹中,但脚本不包含项目中的这些文件夹。 因此,除非手动将其包含在项目中,否则 Web 部署不会将它们复制到目标网站。 (此行为来自默认部署配置;本教程中不会使用的另一个选项是更改控制此行为的设置。可以更改的设置是,在“项目属性”窗口的“包/发布 Web”选项卡上的“要部署的项”下运行应用程序所需的文件。通常不建议更改此设置,因为这可能会导致将比生产环境所需的文件部署更多的文件。有关替代项的详细信息,请参阅配置项目属性教程。)

生成项目,然后在解决方案资源管理器单击“显示所有文件”(如果尚未这样做)。 可能还必须单击“ 刷新”。

Solution_Explorer_Show_All_Files

展开 bin 文件夹以查看 amd64x86 文件夹,然后选择这些文件夹,右键单击,然后选择“ 包括在项目中”。

amd64_and_x86_in_Solution_Explorer.png

文件夹图标会更改,以显示文件夹已包含在项目中。

Solution_Explorer_amd64_included.png

为应用程序数据库部署配置Code First 迁移

部署应用程序数据库时,通常不会简单地将包含所有数据的开发数据库部署到生产环境,因为其中的大部分数据可能仅用于测试目的。 例如,测试数据库中的学生姓名是虚构的。 另一方面,通常不能只部署没有任何数据的数据库结构。 测试数据库中的某些数据可能是真实数据,当用户开始使用应用程序时必须存在。 例如,数据库可能有一个包含有效成绩值或真实部门名称的表。

为了模拟此常见方案,你将配置一个 Code First 迁移 Seed 方法,该方法仅插入生产环境中所需的数据。 此 Seed 方法不会插入测试数据,因为它将在 Code First 在生产中创建数据库后在生产环境中运行。

在发布迁移之前的 Code First 早期版本中,种子方法也经常插入测试数据,因为在开发过程中每次模型更改时,都必须从头开始完全删除并重新创建数据库。 使用 Code First 迁移,数据库更改后将保留测试数据,因此不需要在 Seed 方法中包含测试数据。 下载的项目使用预迁移方法,在初始值设定项类的 Seed 方法中包含所有数据。 在本教程中,你将禁用初始值设定项类并启用迁移。 然后,你将更新 Migrations 配置类中的 Seed 方法,以便它仅插入要在生产环境中插入的数据。

下图演示了应用程序数据库的架构:

School_database_diagram

对于这些教程,你将假定 首次部署站点时, StudentEnrollment 表应为空。 其他表包含必须在应用程序上线时预加载的数据。

由于将使用 Code First 迁移,因此不再需要使用 DropCreateDatabaseIfModelChanges Code First 初始值设定项。 此初始值设定项的代码位于 ContosoUniversity.DAL 项目的 SchoolInitializer.cs 文件中。 Web.config 文件的 appSettings 元素中的设置会导致每当应用程序首次尝试访问数据库时运行此初始值设定项:

<appSettings>
  <add key="Environment" value="Dev" />
  <add key="DatabaseInitializerForType ContosoUniversity.DAL.SchoolContext, ContosoUniversity.DAL" value="ContosoUniversity.DAL.SchoolInitializer, ContosoUniversity.DAL" />
</appSettings>

打开应用程序Web.config文件,并从 appSettings 元素中删除指定 Code First 初始值设定项类的 元素。 appSettings 元素现在如下所示:

<appSettings>
  <add key="Environment" value="Dev" />
</appSettings>

注意

指定初始值设定项类的另一种方法是在 Global.asax 文件的 方法中Application_Start调用 Database.SetInitializer 。 如果要在使用该方法指定初始值设定项的项目中启用迁移,请删除该代码行。

接下来,启用Code First 迁移。

第一步是确保将 ContosoUniversity 项目设置为启动项目。 在“解决方案资源管理器”中,右键单击“ContosoUniversity”项目,然后选择“设置为启动项目”。 Code First 迁移将在启动项目中查找数据库连接字符串。

在“工具”菜单中,单击“NuGet 包管理器”,然后单击“包管理器控制台”

Selecting_Package_Manager_Console

“包管理器控制台” 窗口的顶部,选择“ContosoUniversity.DAL”作为默认项目,然后在提示符处 PM> 输入“enable-migrations”。

enable-migrations_command

此命令在 ContosoUniversity.DAL 项目的新 Migrations 文件夹中创建 Configuration.cs 文件。

Migrations_folder_in_Solution_Explorer

之所以选择 DAL 项目,是因为必须在包含 Code First 上下文类的项目中执行“enable-migrations”命令。 当类位于类库项目中时,Code First 迁移在解决方案的启动项目中查找数据库连接字符串。 在 ContosoUniversity 解决方案中,Web 项目已设置为启动项目。 (如果不想将具有连接字符串的项目指定为 Visual Studio 中的启动项目,可以在 PowerShell 命令中指定启动项目。若要查看 enable-migrations 命令的命令语法,可以输入命令“get-help enable-migrations”。)

打开 Configuration.cs 文件,将 方法中的 Seed 注释替换为以下代码:

var instructors = new List<Instructor>
{   
    new Instructor { FirstMidName = "Kim",     LastName = "Abercrombie", HireDate = DateTime.Parse("1995-03-11"), OfficeAssignment = new OfficeAssignment { Location = "Smith 17" } },
    new Instructor { FirstMidName = "Fadi",    LastName = "Fakhouri",    HireDate = DateTime.Parse("2002-07-06"), OfficeAssignment = new OfficeAssignment { Location = "Gowan 27" } },
    new Instructor { FirstMidName = "Roger",   LastName = "Harui",       HireDate = DateTime.Parse("1998-07-01"), OfficeAssignment = new OfficeAssignment { Location = "Thompson 304" } },
    new Instructor { FirstMidName = "Candace", LastName = "Kapoor",      HireDate = DateTime.Parse("2001-01-15") },
    new Instructor { FirstMidName = "Roger",   LastName = "Zheng",       HireDate = DateTime.Parse("2004-02-12") }
};
instructors.ForEach(s => context.Instructors.AddOrUpdate(i => i.LastName, s));
context.SaveChanges();

var departments = new List<Department>
{
    new Department { Name = "English",     Budget = 350000, StartDate = DateTime.Parse("2007-09-01"), PersonID = 1 },
    new Department { Name = "Mathematics", Budget = 100000, StartDate = DateTime.Parse("2007-09-01"), PersonID = 2 },
    new Department { Name = "Engineering", Budget = 350000, StartDate = DateTime.Parse("2007-09-01"), PersonID = 3 },
    new Department { Name = "Economics",   Budget = 100000, StartDate = DateTime.Parse("2007-09-01"), PersonID = 4 }
};
departments.ForEach(s => context.Departments.AddOrUpdate(d => d.Name, s));
context.SaveChanges();

var courses = new List<Course>
{
    new Course { CourseID = 1050, Title = "Chemistry",      Credits = 3, DepartmentID = 3, Instructors = new List<Instructor>() },
    new Course { CourseID = 4022, Title = "Microeconomics", Credits = 3, DepartmentID = 4, Instructors = new List<Instructor>() },
    new Course { CourseID = 4041, Title = "Macroeconomics", Credits = 3, DepartmentID = 4, Instructors = new List<Instructor>() },
    new Course { CourseID = 1045, Title = "Calculus",       Credits = 4, DepartmentID = 2, Instructors = new List<Instructor>() },
    new Course { CourseID = 3141, Title = "Trigonometry",   Credits = 4, DepartmentID = 2, Instructors = new List<Instructor>() },
    new Course { CourseID = 2021, Title = "Composition",    Credits = 3, DepartmentID = 1, Instructors = new List<Instructor>() },
    new Course { CourseID = 2042, Title = "Literature",     Credits = 4, DepartmentID = 1, Instructors = new List<Instructor>() }
};
courses.ForEach(s => context.Courses.AddOrUpdate(s));
context.SaveChanges();

courses[0].Instructors.Add(instructors[0]);
courses[0].Instructors.Add(instructors[1]);
courses[1].Instructors.Add(instructors[2]);
courses[2].Instructors.Add(instructors[2]);
courses[3].Instructors.Add(instructors[3]);
courses[4].Instructors.Add(instructors[3]);
courses[5].Instructors.Add(instructors[3]);
courses[6].Instructors.Add(instructors[3]);
context.SaveChanges();

对 的引用 List 下有红色波浪线,因为尚未为其命名空间提供 using 语句。 右键单击 的实例之 List 一,单击“ 解析”,然后单击“ 使用 System.Collections.Generic”。

使用 using 语句解析

此菜单选择将以下代码添加到 using 文件顶部附近的 语句。

using System.Collections.Generic;

注意

向 方法添加代码 Seed 是可将固定数据插入数据库的许多方法之一。 另一种方法是将代码添加到 Up 每个迁移类的 和 Down 方法。 UpDown 方法包含实现数据库更改的代码。 你将在 部署数据库更新 教程中看到它们的示例。

还可以使用 Sql 方法编写执行 SQL 语句的代码。 例如,如果要向“部门”表添加“预算”列,并且想要将所有部门预算初始化为 $1,000.00 作为迁移的一部分,则可以将以下代码行添加到 Up 该迁移的方法:

Sql("UPDATE Department SET Budget = 1000");

本教程所示的此示例使用 AddOrUpdate Code First 迁移 Configuration 类的 方法中的 Seed 方法。 Code First 迁移每次迁移后都会调用 Seed 方法,此方法会更新已插入的行,或者插入它们(如果尚不存在)。 方法 AddOrUpdate 可能不是方案的最佳选择。 有关详细信息,请参阅 Julie Lerman 博客上的 小心使用 EF 4.3 AddOrUpdate 方法

按 Ctrl-SHIFT-B 生成项目。

下一步是为初始迁移创建 DbMigration 类。 希望此迁移创建新数据库,因此必须删除已存在的数据库。 SQL Server Compact数据库包含在 App_Data 文件夹中的 .sdf 文件中。 在 解决方案资源管理器 中,展开 ContosoUniversity 项目中的App_Data,查看由 .sdf 文件表示的两个SQL Server Compact数据库。

右键单击 School.sdf 文件,然后单击“ 删除”。

sdf_files_in_Solution_Explorer

“包管理器控制台” 窗口中,输入命令“add-migration Initial”以创建初始迁移并将其命名为“Initial”。

add-migration_command

Code First 迁移在 Migrations 文件夹中创建另一个类文件,此类包含用于创建数据库架构的代码。

包管理器控制台中,输入命令“update-database”以创建数据库并运行 Seed 方法。

update-database_command

(如果收到指示表已存在且无法创建的错误,则可能是因为在删除数据库后和执行 之前运行了 update-database应用程序。在这种情况下,请再次删除 School.sdf 文件, update-database 然后重试 command.)

运行应用程序。 现在,“学生”页为空,但“讲师”页面包含讲师。 这是部署应用程序后将在生产环境中获取的内容。

Empty_Students_page

Instructors_page_after_initial_migration

项目现已准备好部署 School 数据库。

创建用于部署的成员资格数据库

Contoso University 应用程序使用 ASP.NET 成员身份系统和表单身份验证对用户进行身份验证和授权。 只有管理员才能访问其中一个页面。 若要查看此页面,请运行应用程序,并从“课程”下的浮出控件菜单中选择“更新额度”。 应用程序将显示 “登录 ”页,因为只有管理员有权使用 “更新额度” 页。

Log_in_page

使用密码“Pas$w0rd”以“管理员”身份登录, (注意数字零代替“w0rd”) 中的字母“o”。 登录后,将显示 “更新额度 ”页。

Update_Credits_page

首次部署站点时,通常会排除为测试而创建的大多数或全部用户帐户。 在这种情况下,你将部署管理员帐户,但不会部署用户帐户。 无需手动删除测试帐户,而是创建一个只有生产环境中所需的一个管理员用户帐户的新成员身份数据库。

注意

成员资格数据库存储帐户密码的哈希。 若要将帐户从一台计算机部署到另一台计算机,必须确保哈希例程不会在目标服务器上生成与源计算机上不同的哈希。 使用 ASP.NET 通用提供程序时,只要不更改默认算法,它们就会生成相同的哈希。 默认算法为 HMACSHA256,在 Web.config 文件中 machineKey 元素的验证属性中指定。

成员资格数据库不是由 Code First 迁移 维护的,并且没有自动初始值设定项,该初始值设定项使用测试帐户 (与 School 数据库) 一样。 因此,若要使测试数据保持可用,需要先创建测试数据库的副本,然后再创建新数据库。

解决方案资源管理器 中,将 App_Data 文件夹中的 aspnet.sdf 文件重命名为 aspnet-Dev.sdf。 (不要创建副本,只需重命名一下即可创建一个新数据库。)

解决方案资源管理器 中,确保已选择 (ContosoUniversity 的 Web 项目,而不是 ContosoUniversity.DAL) 。 然后在“ 项目 ”菜单中,选择“ ASP.NET 配置 ”以运行 网站管理工具 (WAT) 。

选择“安全”选项卡。

WAT_Security_tab

单击“ 创建或管理角色” 并添加 管理员 角色。

WAT_Create_New_Role

导航回 “安全 ”选项卡,单击“ 创建用户”,并将用户“管理员”添加为管理员。 在单击“创建用户”页上的“创建用户”按钮之前,请确保选中“管理员检查”框。 本教程中使用的密码为“Pas$w0rd”,你可以输入任何电子邮件地址。

WAT_Create_User

关闭浏览器。 在“解决方案资源管理器”中,单击“刷新”按钮以查看新的 aspnet.sdf 文件。

New_aspnet.sdf_in_Solution_Explorer

右键单击 aspnet.sdf ,然后选择“ 包含在项目中”。

区分开发与生产数据库

在本部分中,你将重命名数据库,以便开发版本为 School-Dev.sdf 和 aspnet-Dev.sdf,生产版本为 School-Prod.sdf 和 aspnet-Prod.sdf。 这不是必要的,但这样做有助于避免混淆数据库的测试和生产版本。

“解决方案资源管理器”中,单击“刷新”,展开“App_Data”文件夹以查看之前创建的 School 数据库;右键单击该数据库并选择“包含在项目中”。

Including_School.sdf_in_project

aspnet.sdf 重命名为 aspnet-Prod.sdf

School.sdf 重命名为 School-Dev.sdf

在 Visual Studio 中运行应用程序时,不希望使用 数据库文件的 -Prod 版本,而希望使用 -Dev 版本。 因此,必须更改 Web.config 文件中的连接字符串,使其指向数据库的 -Dev 版本。 (你尚未创建 School-Prod.sdf 文件,但没关系,因为 Code First 将在生产环境中创建该数据库,当你第一次在那里运行应用时。)

打开应用程序Web.config文件,并找到连接字符串:

<configuration>
  <!-- Settings -->
  <connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=|DataDirectory|aspnet.sdf" providerName="System.Data.SqlServerCe.4.0" />
    <add name="SchoolContext" connectionString="Data Source=|DataDirectory|School.sdf" providerName="System.Data.SqlServerCe.4.0" />
  </connectionStrings>
  <!-- Settings -->
</configuration>

将“aspnet.sdf”更改为“aspnet-Dev.sdf”,并将“School.sdf”更改为“School-Dev.sdf”:

<configuration>
  <!-- Settings -->
  <connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=|DataDirectory|aspnet-Dev.sdf" providerName="System.Data.SqlServerCe.4.0" />
    <add name="SchoolContext" connectionString="Data Source=|DataDirectory|School-Dev.sdf" providerName="System.Data.SqlServerCe.4.0" />
  </connectionStrings>
  <!-- Settings -->
</configuration>

SQL Server Compact数据库引擎和两个数据库现在都已准备好部署。 在以下教程中,为在开发、测试和生产环境中必须不同的设置设置设置了自动 Web.config 文件转换。 (必须更改的设置包括连接字符串,但稍后在创建发布配置文件时将设置这些更改。)

更多信息

有关 NuGet 的详细信息,请参阅 使用 NuGet 管理项目库NuGet 文档。 如果不想使用 NuGet,则需要了解如何分析 NuGet 包,以确定在安装 NuGet 包时它的作用。 (例如,它可以配置Web.config转换、配置 PowerShell 脚本以在生成时运行等) 若要详细了解 NuGet 的工作原理,请参阅特别是创建和发布包和配置文件以及源代码转换