Azure 网站

从云进行教学

James 分庭

下载代码示例

这是一个激动人心的时刻,是 Web 开发人员。 创建一个项目并将它部署到一个面向公众的端点的端到端任务真正是一项挑战,曾是令人望而生畏,甚至可能让人望而却步。 然而今天站立的计算的一个"解决"的挑战。

很少的资源,您可以下载一个免费的 IDE 和源代码控制工具。 你可以开始一个项目并将其部署到一个丰富的基础设施,为您维护而无需访问或硬件的知识。 你可以有你无代价要开始主持的项目。

我们要与工作的构造块是比以往任何时候更全面 — — 是否 PHP、 Java 或 Microsoft.NET 框架。 我们现在可以专注于用户体验而不是项目管理、 网络、 存储、 部署程序或可扩展性。

FrontClass,在这篇文章,涵盖的应用程序是工作的几十年前就已经几周,如果不长的东西。 已经是很难得到的所有环境中工作。 部署会是一场噩梦。 而且,最有可能,就不能够解决可伸缩性在那段时间一直。 今天,我可以生成项目和把它部署在几个小时,作好准备,规模。 可下载的解决方案包含完整的工作的源代码你可以部署而不必修改您自己微软 Azure 的帐户。

而志愿者在当地的初中高中,教学到编程 10 至 14 岁的孩子,我开始 FrontClass。 我想要与学生的一种方式可以控制比赛节奏,而让他们返回到前一步骤上需求分享的内容。 有的应用程序的帮助教师进行一类的三个功能区域:作文课,课堂教学及学生参与。 我将会打破上述每个领域,但是,当然,有一些重叠。

项目基础知识

若要生成应用程序,我将使用 Visual Studio 2013 更新 2。 创建解决方案和 ASP.NET MVC 模板时,我还将使用 ASP.NET Web 应用程序。 催生了从模板的项目将使用流行引导前端框架的造型和一些 UI 功能。

若要启用实时功能,我会添加那么 SignalR 软件包并使用模具现在知名到 Visual Studio。 我还将在客户端页面上使用的必要 jQuery 库。 我将把配置实体框架 (EF) 默认情况下,在发展中使用 LocalDb­发展的环境,但当我部署到 Azure 的 Web 站点时,我将使用 SQL Azure 数据库作为数据存储区。 我开始整个项目,然而,在 Azure 门户网站 (portal.azure.com),在那里我可以配置我的部署目标。

创建 Azure 网站 在左下角的门户,单击新和选择的网站 + SQL 模板,如中所示的 图 1。 Azure 将创建一组链接的资源。 选择一个适当的名称为此组和应用程序的名称。 我可以选择创建一个新的数据库服务器或选择一个现有我要为我的网站创建数据库的帐户上。 它建议在同一区域,减少网络流量时间有数据库和 Web 站点。

Create a New Azure Web Site with Linked Database
图 1 创建一个新的 Azure 网站与链接的数据库

对我而言,我被称为资源组 ELearning,FrontClass_DB,数据库和网站 FrontClass。 你需要选择一个唯一的站点名称。 完成设置后,我得到 frontclass.azurewebsites。 净的主机名和我的部署目标是准备好要举办我的网站。

尽管不可思议的事件的出现,那里真的不是应该在这里让你大吃一惊。 我创建一个 DNS 条目,映射主机名到 IP 地址,并作出一些配置选项,如默认文档和连接字符串。 这些是本质上你会在幕后,让您的网站运行在 IIS 中做的事情。 所以,再一次,它不是神奇的但它是相当方便。 也有一些基础设施类型工具像源控制和部署脚本可用来帮助您入门。

创建解决方案下一步,我到 Visual Studio 头和选择上述的 ASP.NET Web 应用程序作为一个基地为我的解决方案。 当我选择要创建的项目类型 — — 使用 ASP.NET MVC 模板 — — 我也得到选项,以在 Azure 上创建的相关的资源。 我已经创建的网站和数据库通过门户网站,所以我清除该复选框,并着手创建网站。

撰写课程模块

由于这个项目的范围,我能够维持一个相当简单的数据模型。 我使用 EF6 创建的模型通过代码第一,为道路使用者的数据迁移下来的修改敞开了大门。 最终的结果,所示图 2,是一套简单的代表的课程、 模块和步结构类。

The Basic Application Data Model
图 2 基本的应用程序数据模型

那里是仪式的有点来遍历得到所有接线在哪里我想要它。 即,我想要使用一个单一的数据库,我想要能够以控制迁移时的生成和我想要我的应用程序来自动执行任何杰出的迁移在应用程序启动。

这让我显式控制显示在每个迁移的变化。 它还可以让我的应用程序更新本身无需干预。 我还将设置一种手段来预填充该数据库的管理员角色与教师角色 (第一次和只有行政用户) 通过对配置类的种子重写。

指定的连接字符串实体框架让我使用相同的数据库与不同的上下文和一个单一的连接字符串内的迁移。 通过调用基类构造函数和传递在名称中,框架将会看起来第一次在应用程序或 Web 配置,看看是否按相同的名称定义的连接字符串。 如果是这样,它将使用它来建立连接。

迁移历史记录为每个上下文由测该命名空间作为更新过程的一部分进行维护。 这将有助于我彼此独立地执行迁移。 进行此设置,我添加一个默认构造函数到我的上下文类,如下所示:

public FrontClassContext()
  : base("DefaultConnection") { }

如果你看看作为坐落在 IdentityModels.cs 文件中的项目模板的一部分创建的上下文,你会看到那里是目前类似的默认构造函数。 它略有修改,以反映性质的 IdentityDbContext 的基类,但仍然从 Web.Config 文件中使用 DefaultConnection 的连接字符串。

启用迁移我生成的配置类的由从 Visual Studio 中的软件包管理器控制台执行以下命令创建的实体:

Enable-Migrations -ContextTypeName FrontClass.DAL.FrontClassContext

这点亮我的课程-迁移­相关实体。 我想要为 ApplicationDbContext,以及做的一样。 与换出的类名,我可以再次运行这个命令。 然而,当我启用配置、 迁移和播种在存储帐户的上下文中,我不想覆盖以前搭建的配置类。 相反,我指定迁移、 备用目录,如下所示,与迁移­目录参数传递到该命令:

 

Enable-Migrations -ContextTypeName FrontClass.Models.ApplicationDbContext -MigrationsDirectory:"Models\AccountMigrations"

第一次迁移中添加的下一步是要简单地脚手架实体框架将执行的类。 我使用了下面的命令两次,一次为我要为其创建迁移每个 DbContext:

Add-Migration Initial-Model -ConfigurationTypeName FrontClass.Migrations.Configuration
Add-Migration Initial-Model -ConfigurationTypeName FrontClass.Models.AccountMigrations.Configuration

再次,与多个上下文中工作增加复杂一点的因为您必须指定 ConfigurationTypeName 参数。 否则,这是一个简单的操作。

设置数据库初始化策略要配置 EF 自动执行我的迁移,需要告诉它之前执行任何数据库访问,使用什么策略。 如果不这样做,我就会收到异常消息在运行时,以表明我的模型是与数据库不同步。 每个到我的课的更改会影响我的数据模型,在数据库中跟踪的计算哈希值。

在我 Global.asax 我添加以下两行代码就可以使用 MigrateDatabaseToLatestVersion 初始值设定项:

Database.SetInitializer<ApplicationDbContext>(
  new MigrateDatabaseToLatestVersion
    <ApplicationDbContext, 
     FrontClass.Models.AccountMigrations.Configuration>());
Database.SetInitializer<FrontClassContext>(
  new MigrateDatabaseToLatestVersion
    <FrontClassContext, FrontClass.Migrations.Configuration>());

请注意我要求接受我想要配置的上下文的泛型 SetInitializer 方法。 对我而言,我的配置类像-命名所以我已经指定的充分使用命名空间的类名称。

种子表第一运行,我想要能够提供一种体验,可以让别人"只需登录",开始使用的应用程序。 我可以创建类似于你会发现在流行的博客应用程序运行一次控制器。 另一个选择是在我的配置类中使用的种子的方法。 种子方法被通过在适当的上下文,从中我可以操作的表的一个实例。

与 ASP.NET 2.0 的身份,我也得到了一套丰富的 EF 意识到的类。 这让我的角色和用户有条件地注入数据库中,就像我图 3

图 3 播种的第一个角色和管理用户

if (!context.Roles.Any(r => r.Name == 
  FrontClass.MvcApplication.AdministratorRoleName))
{
  var roleStore = new RoleStore<IdentityRole>(context);
  var roleManager = new RoleManager<IdentityRole>(roleStore);
  var identityRole = new IdentityRole 
    {Name = FrontClass.MvcApplication.AdministratorRoleName};
  roleManager.Create(identityRole);
}
var instructorName = "instructor@contonso.com";
if (!context.Users.Any(u => u.UserName == instructorName))
{
  var userStore = new UserStore<ApplicationUser>(context);
  var userManager = new UserManager<ApplicationUser>(userStore);
  var applicationUser = 
    new ApplicationUser { UserName = instructorName };
  userManager.Create(applicationUser, "init_2014");
  userManager.AddToRole(applicationUser.Id, 
    FrontClass.MvcApplication.AdministratorRoleName);
}

我也被播种的模块相关的表,用一些示例数据,你可以看到在本文附带的下载。 当应用程序启动时,我可以使用密码 init_2014 instructor@contonso.com 用户名登录。 在这一点上,我在的地方有我的数据结构、 应用程序配置了多个上下文中使用相同的数据库和我有一个管理用户 — — 教练帐户 — — 这可以登录。

基本的编辑功能允许实际课程组成是提供创建、 所需的最后一片读取、 更新和删除 (CRUD) 功能。 我创建一个新的区域称为管理我的项目的根目录中,使用内置的脚手架工具来构建用户界面。 最后,我创建管理控制器与一个索引操作和一个视图,提供课程维护、 模块和步骤的链接。

指导课程

作为教师,您可以从同一个管理视图,然后从中选择一个模块选择一门课程。 每个步骤都显示在后续模块页面上,正如你可以看到在图 4。 您可以向任何一个学生在虚拟课堂上的内容的访问讲师预览和发送的任何步骤。

Conduct the Class
图 4 行为类

学生们可以在一次会议,在课堂上与教员,或传播到世界各地。 一个上下文,您可以使用此应用程序将是一个实时、 在线的虚拟教室,有几十个甚至几百个学生。 我想要确保不管如何,您可能需要调整应用程序,你不会失去扩展能力。 所以我要考虑怎么教训有效载荷实际上会给学生。

您可以为纯文本或 html 格式,创建一个课程模块中的步骤,每一步可以是任意长度。 那么 SignalR 做很好的处理谈判运输 (与 Websocket,服务器发送的事件,长轮询或永远帧) 的力学,它抽象需要担心消息序列化。

最终,为了保持可扩展,我需要保持较小的我的邮件。 这是设计的为了尽量减少对服务器资源的需求,降低成本的序列化,让客户端的浏览器利用部分的基础设施,如缓存,那么 SignalR 在中和使用同样的它:为发信号。

要实现这一目标的最佳方式是简单地发送消息到客户端说,"新的内容就在这里,"而不是发送整个课一步。 收到的在这里的 JSON 中的客户端,请考虑下列序列化的消息:

{"H":"ModuleStepHub", "M":"updateStep",
  "A":["\n<h1>Welcome to the course!</h1><p>trimmed for brevity...</p>\n"]}

该消息作为参数负载来为客户端的 updateStep 方法进行 HTML。 那"裁剪为简洁起见"文本是关注的源。 内容可显著增加,根据教练如何创建迈出的一步。 现在,这只是文本。 你可以想象的消息的大小将会如何成长如果您试图发送内容或管道的图像的页面。 将序列化为 JSON 和传递到每个客户端使用的信令的管道资源的文本或图像。 相反,我只是想要发送的信号,特别是浏览器应该加载的新内容 ID。 那小得多的消息看起来更像这样:

{"H":"ModuleStepHub","M":"notifyStepAvailable","A":[7]}

现在,我知道我想用我的消息来完成,我可以在我的应用程序中建立了此功能。

**创建中心:**我将集线器的文件夹添加到我的项目,然后从添加新项对话框中添加那么 SignalR 集线器类 (v2)。 集线器是服务器端的一段的那么 SignalR 您创建发布消息和处理客户端调用。 去这条路线,Visual Studio 拉在我的依赖关系和与抽样方法在我中心支架一类。 我删除的抽样方法,并创建一个新的让我发送一条消息,用下面的代码:

public void MakeStepAvailable(int stepId)
{
  Clients.Others.
notifyStepAvailable(stepId);
}

这里的前提是行动的课程的教师将调用某种向学生发送一步。 使用其他客户端上的动态属性对象,我告诉那么 SignalR 一步 ID 向发送所有其他连接的客户端。 那么 SignalR 提供大量的这种过滤的选项,所以我可以更新特定的用户、 一组用户或一些其他片的连接的客户端。 集线器也让教官开始一个新的模块。 学生可以得到由讲师提供的步骤的列表。

地图那么 SignalR 集线器暴露在我的中心中创建的功能,需要捅那么 SignalR,作为我的应用程序正在启动。 对 MapSignalR 的调用设置了一个默认终结点,提供了一个 JavaScript 代理。 当包含在客户端,这将调用服务器端方法从客户端,反之亦然。 我的项目的根文件夹包括我打电话要做配置方法中的布线浩然启动类。 这是如何,看起来后我的更改:

public void Configuration(IAppBuilder app)
{
  ConfigureAuth(app);
  app.MapSignalR();
}

它是重要的是在这里第一次调用 ConfigureAuth。 浩然管道将推送消息通过中间件中间件注册的顺序的。 在我们的例子中,我们想要的身份验证和授权在发生之前,调用到达我们的中枢。

启用共享让老师分享的内容,添加,另一个控制器名 InstructController 的应用程序。 这有只索引操作。 我已经装饰的类具有授权的属性,因此只有管理员才可以控制教室。 索引操作接受模块 ID 作为参数,在我的 App_Startup\RouteConfig.cs 类中配置的路由。 方法查找模块从数据库,并返回该记录到视图与查询中包括的步骤集合。

相应的视图 (位于 Views\Instruct\Index.cshtml),只是生成了一个分享按钮的每一步。 我使用的数据 id 属性来存储步骤的 ID。 我包括那么 SignalR 图书馆和集线器代理暴露在前面的步骤,然后编写少量的 JavaScript 来启动代理和处理 click 事件从教练,如中所示图 5

图 5 JavaScript 到启动代理和处理单击事件

<script src="~/Scripts/jquery.signalR-2.0.3.js"></script>
<script src="~/SignalR/Hubs"></script>
<script>
  $(function() {
    var hub = $.connection.moduleStepHub;
    $.connection.hub.start().done(function() {
      $(".share-step").click(function() {
        var stepId = $(this).attr("data-id");
          hub.server.makeStepAvailable(stepId);
      });
    });
  });
</script>

最后,我修改我的行政索引页,包括课程和模块,教师可从中选择的列表。 最后一个界面,作为显示在图 6,让教练跳进一个模块的权利,并开始教学。

The Administrative Interface for FrontClass
图 6 为 FrontClass 的管理接口

使用模块视图从图 4,指导员然后可以发送内容到类。

课堂参与

作为一个学生,这个故事是简单得多。 只是显示 ! 每个学生将需要注册以访问该站点,并接收活动课程模块的说明他们需要输入密码。 注册过程是由照顾我的项目中的默认帐户控制器。 我需要创建承载这一课的页面内容和编写所需的学生参加在类中的代码。 为学生加入教室一类处于活动状态时,他们必须先报名参加该课程。

构建课堂控制器控制器中的项目的根文件夹上右键单击让我添加一个新的控制器并命名为 ClassroomController。 我向此类添加的两个主要方法是的指数,在那里将送达的主要内容和 GetModuleStep,满足一些先决条件后返回请求的步骤。 第三个操作处理情况下那里有没有积极的类模块。 若要访问模块材料,必须登录到该站点并报名参加了活动模块课程学生。

允许课程招生 ClassroomController 是德科­额定与我创建,以确保学生只能访问的课程,他们须由教师设置的输入代码 EnrollmentVerficationFilter。 如果还没有尚未注册用户或教练还没有开始一个模块,然后学生被重定向到索引行动上 EnrollmentController,正如你可以看到在图 7。 学生可以报读的课程用适当的条目的代码。 后成功注册,添加到使用有关 ASP.NET 标识组件的用户帐户的索赔。

The Course Lobby and Enrollment Page
图 7 课程大厅和注册页

我添加通过 UserManager 类,到的访问通过获取我的 ApplicationDbContext 的一个实例并使用,生成 UserStore,然后传递到我的目标类索赔:

var context = new ApplicationDbContext();
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);

一旦我在的地方有必要组件,我通过校长代表他的身份得到用户的 ID,生成一个索赔对象。 然后我将,添加到该用户的帐户:

var userId = User.Identity.GetUserId();
var courseClaim = new Claim(MvcApplication.CourseRegistrationClaimUrn,
  enroll.CourseId.ToString(CultureInfo.InvariantCulture));
userManager.AddClaim(userId, courseClaim);

在地方上的用户帐户的索赔,一个学生可能现在访问教室。

检查教室视图 正如你可以看到在 图 8,教室分为两个部分。页面的顶部为当前模块的概述并提供控件以跳转到任何可用的步骤。底部所谓的黑板上,并显示由讲师的共享内容。

The Virtual Chalkboard图 8 虚拟黑板

这页真的仅有几个 DIV 元素作为内容的容器。其余是通过 JavaScript 了有线和通过内容获取基于来自 ClassroomHub 或学生的选择上一步的消息。教练选择新的步骤,ClassroomHub 通知,并将信号发送到所有人都在教室里。这反过来提取数据从 ClassroomController,因此启用缓存。

部署项目

讲师可以创建和管理课程、 模块和步骤。学生可以为网站登记和注册自己的课程。课程都通过招生的要求,保护和虚拟教室的黑板用的内容更新,由授课老师的指导。船的时间啊 !

从生成菜单中,选择要发布我的项目的选项。将显示发布 Web 对话框,然后 Azure 网站作为发布目标。Visual Studio 会提示我输入我的凭据如果我已经没在签署。然后我可以选择我在开始这个项目时创建的现有网站。我发布的配置文件是然后下载,完成与预配置的数据库连接字符串并将我的网站发送到 Azure 所需的所有凭据。

在这个项目的开始,第一次准备好我的网站在 Azure 门户中。因为这个项目使用 DefaultConnection 连接字符串,已经存在于我的发布配置文件,我不需要进行任何更改,当我去生产。生产连接字符串自动点我的应用程序在以前配置 SQL Azure 数据库。

利用 Azure 的 Web 站点

发布一个网站到一个预先配置的终结点中 Azure 网站是一个受欢迎的惊喜。这是实际上很容易。经过多年的幸存的要复杂得多的部署步骤,这必然是一种享受。独自一人,这不是结束游戏为 Azure 网站。有很多工具可用:

  • 添加一个自定义的域:如果你可以注册一个域名,并设置了几个 DNS 记录,只需分钟要添加到您的网站选择的唯一的域。更多关于这在 bit.ly/1sV8R1y
  • 安全的应用程序:基于 SNI 的证书都负担得起­能,和你可以通过仪表板的 Azure Web 站点添加它们。更多关于这在 bit.ly/1mYXndJ
  • 规模的网站:如果您发现您的项目正在增长,您可以选择要扩大规模 (更强大的硬件) 或缩小 (更多实例)。别忘了还配置 Azure 服务总线来处理你那么 SignalR 通信量。了解更多,那么 SignalR bit.ly/1o6B7AC
  • 添加连续部署:即使是最小的项目,我放弃直接部署和使用基于 Git 的源代码管理服务器。Azure 然后创建阶段和自动部署我的网站上检查中。更多关于这在 bit.ly/1o6BACT
  • 添加监视和警报:它是最好的知道什么时候的东西不会完全正确在您的应用程序。你可以监视某些类型的问题并得到通知,因为他们发生,所有已配置的从你的网站的仪表板。

总结

在这篇文章中,我使用 ASP.NET 身份 2.0,现在是默认的 ASP.NET MVC 模板视觉工作室 2013 年的一部分。若要了解有关增强和更改的详细信息,请查阅的.NET Web 开发和工具的博客帖子 bit.ly/PXgQ2d。我还用那么 SignalR,使客户端和服务器之间的实时通信。这会自动生成 JavaScript 代理,并且调用代码在服务器从客户端,反之亦然。更多关于创建您的数据模型与代码第一次使用 EF ASP.NET MVC 5 应用程序中,访问在教程 bit.ly/1pivbmE

丰富的经验,是很容易提供当你不需要去关心底层的基础架构或部署的复杂性。FrontClass 应用程序利用身份验证、 授权、 实时消息的发送和持久性数据存储。作为开发人员,我得到很多这些积木等其他人的努力。我不需要担心其他运动部件,当我移动我的项目投入生产。

James 分 庭 是在 ASP.NET/IIS 和经常在会议和用户组演讲微软 MVP 加拿大各地。他是作者的"Windows Azure 网站"(Wrox,2013年),可通过电子书 (bit.ly/wawsbook),并提出了关于微软虚拟学院 (bit.ly/wawsmva)。他的博客 jameschambers.com 和你能联系到他在 Twitter 上 twitter.com/CanadianJames

衷心感谢以下技术专家对本文的审阅:乍得麦卡勒姆 (独立顾问)