Umbrazure: Umbraco on Azure 上的无限网站






4.64/5 (9投票s)
Umbrazure 简化了在 Azure 上托管 ASP.NET 网站(基于 Umbraco 6)的开发和托管流程。
引言
想建立一个云架构,让您每天只需花费一杯苏打水的成本就能运行成千上万个 ASP.NET 网站吗?继续阅读,并准备好减少蛀牙,绽放更灿烂的笑容(甚至可能减重!)。
动机
我没有制作一个碰巧托管在“云端”的简单演示网站,而是想为本文制作一些真正有用的东西。我不想演示某些云功能,而是想开发一个蓝图,可以与其他 Web 开发人员共享,以便他们能够对他们正在处理的网站进行一些令人印象深刻的工作。我决定要做的是将我每天使用的工具,Umbraco CMS(内容管理系统),部署到 Azure 上。我将这个蓝图称为“Umbrazure”(“Umbraco”和“Azure”的组合词)。此外,我还想让不熟悉 Umbraco 的其他开发人员更容易上手,并且可以轻松地管理内容,同时又不牺牲我们 Visual Studio 开发人员已经习惯的软件开发便捷性。我很高兴地报告,我实现了这些目标,本文将一步一步地引导您完成整个过程,以便您可以开始使用一个快速、可扩展、易于管理、可扩展且高可用的网站 CMS。
目标
为了演示如何最好地使用 Umbraco,我可以采取几种途径,但我认为对大多数开发人员最有用的方法是如何通过使用高度可扩展的 Umbraco 环境来托管几乎无限数量的网站来降低成本。到本文结束时,您应该有足够的技术知识来以每月不到 30 美元的价格(一个小型 Web 角色、一个 SQL Azure 数据库、一些文件空间和一些网络流量的成本)运行,比如说,500 个网站(每个网站都有自己的自定义域名)。如果您的某些网站变得非常受欢迎并获得大量访问者,您只需花费一点额外的钱来增加 Web 角色的规模和/或数量,这只需单击按钮即可完成。
吸引力
我还要提一点,CMS 已经存在一段时间了,有很多方法可以错误地设置它们,使访问者、用户和程序员的生活变得困难。我将要演示的方法的绝妙之处在于,它具有最低限度的侵入性(与某些其他 CMS 不同……*咳嗽* SharePoint *咳嗽*),这意味着您仍然可以按自己想要的方式自定义内容,而不会被 CMS 强制要求按特定方式行事。构建过程不会有太大变化(F5 仍然有效),在 Visual Studio 中调试就像您没有使用 CMS 一样有效,而且您的访问者将不知道您托管在 Azure 上或正在使用 CMS(除非他们检查您的 HTTP 标头)。我希望,到本文结束时,我将使您作为软件开发人员的生活变得更轻松,而不是更艰难,并且您将获得一套真正有用的技能,可以立即投入使用。
目录
- 概述
- 必备组件
- Azure 设置
- Visual Studio 云解决方案
- 域名
- Umbraco 集成
- Umbraco 安装
- 通过多个 Web 角色实例进行扩展
- 多环境配置
- Twitter Bootstrap 示例站点
- 陷阱/修复
- 结论
- 附录:关于源代码下载
- 词汇表
- 资源
概述
正如我在引言中已经解释过的,本文将处理 Umbraco CMS,以及将其顺利部署到 Azure。但是,在您决定阅读全文之前,我想给您一个关于将要涵盖的具体主题的高层概述。
首先,我们将让您在 Azure 上开始工作。我们将循序渐进,以免您被大量新概念所淹没。即使您以前从未使用过 Azure,您也能跟上。一旦我们为您设置好一些 Azure 基础知识,我们将使用 Visual Studio 和域名进行一些必要的连接,以使它们与 Azure 协同工作。这些事情在没有复杂部分干扰的情况下更容易实现。
一旦您熟悉了 Azure、Visual Studio 和域名,我们就可以开始讨论本文的真正重点,即 Umbraco 的整合。同样,循序渐进……我们将涵盖您需要触及的每一个文件。由于每个 CMS 的工作方式略有不同,我现在将为您提供 Umbraco 工作方式的概述。Umbraco 允许非技术用户管理网站,并且站点上的每个页面在 Umbraco 中都表示为分层树中的一个节点,如下所示
Umbraco 的功能远不止于此,但大多数非技术用户会这样看待它。他们将在 Umbraco 中创建的每个节点将在网站上显示为一个页面(由 Web Forms 或 MVC 提供支持,因为 Umbraco 允许您混合搭配)。节点还可以用于存储用户输入的数据,但大多数节点将具有对应的网页。
一旦您将 Umbraco 集成到 Visual Studio 中,安装到数据库中,并在 Azure 上运行,我们就可以开始自定义它了。其中一些自定义内容只是您通常会在网站中看到的,例如重写规则以创建美观的国际 URL。但是,在进行典型的自定义之后,我们将深入研究使 Umbraco 能够随着网站扩展(即多个 Web 角色实例)而运行的功能。其中一部分将演示 Umbraco 内置的一些功能,例如创建页面和向其添加数据。
如果您一直读到文章的这里,您将能够创建基本的 Umbraco 网站并部署到 Azure。但是,当您继续阅读时,我们将介绍一些使开发更容易的方法,例如创建 XML 转换以根据您是正在调试还是部署到云端来修改配置文件。
文章的其余大部分将是一个示例网站,演示您可能想要使用 Umbrazure 来创建的内容。如果您一直读到文章的这里,您将得到类似这样的结果
本文的其余部分将主要是参考信息。我将包含一些您需要注意的陷阱,一些您可能需要采用的修复方法,以及一个术语表以供快速参考(以防您的同事试图就您将要向他们解释的这个疯狂的 Umbrazure 概念对您进行测验)。
必备组件
要完成此挑战 2 文章,您将需要
- Visual Studio 2012(附带更新 2)
- Azure SDK 和工具(在您创建第一个云项目时安装)
- Windows Azure 订阅(提供免费试用)
Azure 设置
在进入激动人心的编码之前,我们将首先完成尽可能多的 Azure 设置。在这些部分的每一个部分中,图片将帮助您完成整个过程。您的第一步是导航到 www.windowsazure.com,然后单击屏幕右上角的“Portal”按钮。如果您还没有 Windows Azure 订阅,现在是时候创建一个了(使用页面顶部的“Free trial”链接,如下面的图片所示)。
接下来,您需要登录。如果您还没有账户,请返回上一页,然后单击“Free trial”创建一个账户。
登录到门户后,您可以在“Settings”→“Affinity Groups”下创建一个亲和组。当您在同一个亲和组中创建 Web 角色和其他服务时,它们将在同一个物理数据中心创建。这意味着它们在相互通信时不会产生网络流量费用,因为它们使用的是内部网络而不是互联网带宽。
在这里,您可以看到屏幕底部的一个小状态弹出窗口,表明我刚刚创建的一个亲和组正在设置中。由于它在美国东部,我将其命名为“Eastern”。我将从现在开始使用这个亲和组。
“Cloud Services”部分是您创建 Web 角色的地方。Web 角色是运行网站的地方。您可以将其视为 Web 服务器,但它们带有一些 Azure 的便利功能。Azure 可以使用 Web 角色很好地扩展,因为您可以选择垂直扩展(更快的计算机)或水平扩展(更多的计算机)。当您水平扩展(即增加 Web 角色数量)时,Azure 会在您的 Web 角色之间负载均衡所有 Web 请求。据我所知,负载均衡不保证是“粘性的”,这意味着如果用户按下按钮执行回发,他们可能会将该请求发送到与他们最初收到第一个请求不同的 Web 角色。这会产生一些问题,其中一个问题是会话状态在 Web 角色之间将不相同,除非您设置自定义会话提供程序。但是,如果您可以避免会话,那就更好了。
您可以看到,我已经创建了一些现有的 Web 角色,“U6”和“U6CMS”。您可以忽略它们,因为我只是在撰写本文之前进行了一些测试而创建它们。创建 Web 角色的方法是单击页面左下角的“New”按钮。然后,单击“Cloud Service”,然后单击“Custom Create”。
在本文的范围内,我将创建两个 Web 角色,“keanu”和“jodie”。可以通过访问 URL keanu.cloudapp.net 和 jodie.cloudapp.net 来访问它们。由于我已经创建了它们,您必须自己想出一些名字。如果您在为工作制作东西,您可能想根据其他标准而不是您最喜欢的演员和女演员来选择名字,但我将把这个留给您。
您的角色创建完成后,您会在底部看到一个通知。
Azure 可以显示多个通知,因此您可以随时离开去吃零食;您不会错过任何东西。
如果您尝试访问您刚刚创建的 Web 角色的 URL,您将看不到任何有用的信息。这是因为您还没有上传包给它。我们稍后会处理。
大多数网站还需要一个数据库,Azure 有一个叫做 SQL Azure 的数据库。它与 SQL Server 非常相似。您可以在“SQL Databases”部分通过单击“New”→“SQL Database”→“Custom Create”来创建数据库。
您需要为数据库命名,并指明它可以增长到的最大大小。一旦达到该大小,它将进入只读模式,并且无法再插入更多数据。这样做是为了防止您产生任何意外费用。但是,您只为您在数据库中实际使用的空间付费。如果您选择 10GB 作为限制,但您只使用了 5KB,那么您只为这 5KB 付费。
如果您在新服务器上创建数据库(如果是您的第一个数据库,您将会这样做),系统会要求您创建一个数据库用户。请记住该密码,否则之后您需要重置它(可以从 Azure 门户进行)。
在数据库创建完成之前,您将无法使用它,如下所示。
上面的“matrix”数据库是我将用于生产环境的。对于我的开发环境,我将创建一个名为“simulacrum”的数据库。您可以随意命名您的生产/开发数据库。
现在您有两个数据库可供使用。请记住,只要它们存在,您就会为它们付费。忽略我创建的其他两个数据库,因为它们是为了测试目的而创建的。
要管理数据库,请单击此列表中的链接。在这里,我们将单击链接以进入 matrix 数据库管理页面。
这是管理数据库时的着陆页。
单击“Dashboard”(仪表板)(顶部)后,您将看到此页面。单击“Manage allowed IP addresses”链接。
您将输入一个防火墙规则,允许所有外部流量访问您的数据库。输入 0.0.0.0 到 255.255.255.255 的范围(忽略截图以 1.1.1.1 开头的事实……我太蠢了)。通常,您不需要这样做,因为您的大部分流量是内部的,但这样做将使您更容易开发 Azure。
Visual Studio 云解决方案
您暂时完成了 Azure 的工作。现在打开 Visual Studio(记住以管理员身份运行)。
如果您已安装更新 2(如您所愿),您将看到此内容。
首先创建一个新项目。实际上,项目是“Blank Solution”(空白解决方案),它实际上不包含任何项目。我喜欢从头开始。
这是您将在其中进行所有编码的新解决方案。我将其命名为“Umbrazure”,但您可以按自己喜欢的名称命名。
向您的解决方案添加一个新项目。
它将是一个云项目。我命名我的云项目时,只需在解决方案名称后添加“.cloud”后缀。请注意,我使用的是 .Net Framework 4.5。
云项目向导允许您选择要添加的云服务。创建一个 MVC 4 Web 角色。我将其命名为“Umbrazure.Web”。
接下来,选择您的 MVC 4 Web 角色的选项。您将使用 Razor 视图引擎从空模板创建它。
这是您刚刚创建的两个项目。一个云项目(负责所有 Azure 打包)和一个 MVC 4 项目(您的主要 Web 角色项目)。
向您的解决方案添加另一个项目。这次是一个空的 ASP.NET Web 应用程序。它将作为您的默认 Web 应用程序,当您没有更酷的 Web 应用程序(如您的 MVC 4 项目)可显示时,它将显示出来。
这是您的所有三个项目。
我们将开始处理您的 MVC 4 项目。在“Models”文件夹中添加一个名为“Message”的类,并按照下图中的方式填充它。这是最基本的模型。
namespace Umbrazure.Web.Models
{
public class Message
{
public string Text { get; set; }
}
}
接下来,添加一个控制器。
将您的控制器命名为“MessageController”。
按照下图中的方式填充您的控制器。
构建您的解决方案。在添加强类型视图之前(否则您的模型将不会出现在下拉列表中),您应该始终执行此操作。
在“Views”→“Message”(您也需要创建该文件夹)下添加一个视图。
将您的视图命名为“Index”。按下图中的方式设置。
按照下图中的方式填充您的视图。它将仅呈现一个基本的 HTML 页面,向用户显示一条消息。
@model Umbrazure.Web.Models.Message
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Umbrazure Message!</title>
</head>
<body>
<fieldset>
<legend>Message</legend>
<div>
@Html.DisplayFor(model => model.Text)
</div>
</fieldset>
</body>
</html>
接下来,修改 RouteConfig 类中的 RegisterRoutes 函数,以便您有一种方法可以将流量路由到控制器上的操作方法。
namespace Umbrazure.Web
{
using System.Web.Mvc;
using System.Web.Routing;
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
name: "Umbrazure Message",
url: "{controller}/{action}",
defaults: new { },
constraints: new { controller = "^Message$", action = "^Index$" }
);
}
}
}
右键单击您的云项目并开始调试。
启动模拟器需要一些时间。
您会在系统托盘中看到一些消息,因为模拟器正在启动。您还可以使用这些图标查看模拟器(例如,查看任何跟踪消息)。
您看到此错误消息是因为您没有默认路由。另外,请注意端口 81 正在被使用。Azure 自动将您发送到这里,但请记住,在修改 URL 时始终保留 81。
访问您之前设置的路由。这将向您显示从 Message 控制器上的 Index 操作返回的 Index 视图。
双击您的角色配置,并将 VM 大小设置为 extra small。这是最便宜的尺寸。便宜是好事,对吧?
要将项目部署到 Azure,请右键单击云项目并选择“Package”。
您很可能始终选择云配置和发布构建配置。
当 Visual Studio 完成所有打包工作后,它将在 Windows Explorer 中打开您需要的文件夹。
访问 Azure 门户,转到“Cloud Services”,找到您的“keanu”Web 角色(或您命名的任何名称)。单击“Upload”按钮。
填写您想要的部署名称,然后从 Visual Studio 为您打开的 Windows Explorer 文件夹中选择您的包和配置文件。按所示方式设置其他选项,然后单击复选标记按钮。
您可以看到包上传到 Web 角色的进度。
包上传完成后,Web 角色 VM 需要大约 10 分钟才能“预热”。您可以在此处查看状态。
看起来已完成,这意味着您可以开始使用您的 Web 角色了。
就像在 Visual Studio 中运行它一样,如果您尝试访问“主页”,您会看到一个错误。
相反,转到您通过路由设置的路径。恭喜您,您已成为 Azure Web 开发者!
域名
在 Visual Studio 中调试云应用程序时,而不是输入 IP 地址,您可以看到域名。您可以通过在 hosts 文件中输入一个条目来完成此操作(路径如下所示)。127.0.0.1 是您的本地计算机,您可以选择任何您想要的域名。
如果您希望其他人以美观的域名看到您的站点,hosts 文件将不起作用。您需要向注册商注册域名。在此,您可以看到我通过注册商 GoDaddy 注册了 umbrazure.com。它们有点垃圾,但如果您购买大量域名,它们很便宜,就像我一样。
当人们访问您新注册的域名时,他们不会看到太多内容,除非您添加一个 CNAME 记录将其指向 Azure。在这里,我将 www.umbrazure.com 指向 jodie.cloudapp.net。每当有人访问 www.umbrazure.com 时,他们的请求都会被发送到 jodie.cloudapp.net,并且他们会获得一个响应,就好像他们访问了该域名一样。
我创建了另一个 CNAME 记录,以便 umbraco.umbrazure.com 指向我的另一个 Web 角色 keanu.cloudapp.net。这是我将用于与 Umbraco 交互的子域名。
如果有人在没有子域名的情况下访问 umbrazure.com,他们不会看到太多内容。要解决此问题,您可以创建一个域名转发,以便他们自动重定向到某个子域名。在这种情况下,我将重定向到 www.umbrazure.com(网站最常见的子域名)。
您的每个项目都可以设置为响应不同域名的请求。因此,如果用户输入“www.umbrazure.com”,他们将看到一个网站;如果他们输入“umbraco.umbrazure.com”,他们可能会看到另一个网站。您还可以让多个域名指向同一个项目,从而提供相同的网站。在这里,我们正在修改 ServiceDefinition 文件,以便所有已知我们正在处理的域名都由 MVC 4 Web 角色提供服务。任何其他遇到的域名将由“default”Web 应用程序提供服务。
(旁注:Code Project 文本编辑器在粘贴时不会对该 XML 代码片段进行 HTML 编码,因此请从下载文件中获取。)
默认站点目前很无聊,所以我们将添加一个名为“Default.aspx”的 Web Forms 页面。按照下图中的方式填充。
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="Umbrazure.Default.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Default</title>
</head>
<body>
<form id="frmMain" runat="server">
<h1>Default Site</h1>
<p>You have reached the default site.
To see one of the other sites, modify the ServiceDefinition.csdef file
in the cloud project to create a binding for it with this domain name,
like this:</p>
<div>
<asp:TextBox runat="server" ID="txtExample" TextMode="MultiLine"
ReadOnly="true" Rows="16" Columns="120" />
</div>
</form>
</body>
</html>
转到您的默认项目的属性,单击“Settings”选项卡,然后单击创建设置文件的链接。
添加一个名为 ServiceDefinitionTemplate 的字符串设置,其值为下图所示。
(旁注:同样,Code Project 文章编辑器无法处理 XML 代码片段,因此请转到下载文件。)
修改您的 Default 页面的代码隐藏,使其与下图所示的代码匹配。
namespace Umbrazure.Default
{
using System;
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
txtExample.Text = string.Format(
Properties.Settings.Default.ServiceDefinitionTemplate,
Request.Url.Host);
}
}
}
回到您在 Azure 中的 keanu Web 角色,但这次单击“New staging deployment”(新建暂存部署)。暂存部署具有随机分配的 URL。这样,您就可以在将代码移到生产环境之前对其进行测试。
像以前一样打包您的云项目,并使用下图中的详细信息上传暂存部署。
项目上传后,您将在(下图右下角)看到暂存 URL。单击它。
您的暂存 URL 将在新选项卡中打开。由于 URL 刚刚生成,我们看到的是我们的默认站点。但是,我们之前设置的默认站点显示了我们需要添加的绑定,以便 MVC 4 站点能够显示出来。
从上面的绑定中复制,并将其放入您的 ServiceDefinition 文件中,如下所示。您可能需要修改名称(我称之为“Staging”)。
再次打包您的云项目(现在它包含了暂存 URL 绑定),并更新您的暂存部署。
嘿,现在暂存站点显示了与 MVC 4 站点相同的错误。怎么回事?
如果我们导航到我们设置的路由,我们可以看到我们的 Index 视图。通过创建暂存部署,使用临时 URL 创建新绑定,并更新暂存部署,我们能够指示我们希望在此暂存部署上看到 MVC4 站点。真棒!
如果您等待几个小时让 DNS 解析您的 CNAME 条目,并将您的包上传到 jodie Web 角色,您将能够在真实的实时域(而不是那个怪异的 cloudapp.net 域)上看到您的站点。请记住,此域名可以是您想注册的任何域名(只要可用)。您还可以将多个站点指向同一个 Web 角色(我只是使用不同的子域名,因为那样更便宜……CNAME 记录不花费任何费用)。
接下来,开始调试您的云项目。
您将看到默认项目,因为您通过 IP 地址访问站点。
但是,由于您之前添加了 hosts 条目,您还可以通过开发域名访问您正在调试的站点。看,它奏效了!由于您为此开发域名设置了绑定,因此模拟器正在为您的 MVC 4 项目提供流量。
Umbraco 集成
现在您已经熟悉了 Azure 的一般用法,接下来是棘手的部分。Umbraco 集成。您可以从 umbraco.codeplex.com/releases 下载 Umbraco。您想要“recommended download”(推荐下载)下的 ZIP 文件。好吧,除非……
我喜欢生活在刀尖浪尖上,所以我选择下载 Umbraco 的 nightly build(夜间构建)。您可以在 nightly.umbraco.org 找到它们。我下载了版本 6.1.0 的构建 90。如果您想完全按照本文的步骤进行,我建议您下载那个版本。但是,将来,您可能想下载最新最好的版本。但是,如果您那样做,您可能会遇到一些 bug,我可能无法为您解决。
一旦 ZIP 文件下载完成,请单击链接以打开下载它的文件夹。
它可能看起来不像,但这一步可能非常重要。右键单击 ZIP 文件以访问其属性。在解压缩之前,请确保取消阻止 ZIP 文件,否则您可能会遇到奇怪的权限问题。
将 ZIP 文件解压缩到一个文件夹。
这是您解压缩到的文件夹中的文件。这就是 Umbraco。
您将把 Umbraco 集成到您的 MVC 4 项目中。首先复制所有新文件和文件夹到您的项目文件夹(“新”是指尚未存在于项目文件夹中的文件)。我在下图中标出了它们。
接下来,通过右键单击文件和文件夹并选择“Include”(包含)来在 Visual Studio 中“包含”它们。如果您一开始看不到它们,请单击“Refresh”(刷新)按钮(那个有两个箭头在一个圆圈中追逐的图标)。
Umbraco 的 App_Data 文件夹是空的,所以您可以删除它(但是,请保留 MVC 4 项目中的那个)。
在 Windows Explorer 中打开目标 bin 文件夹。
删除其中的所有文件。这将使下一步更容易。
将 Umbraco bin 文件夹中的所有文件移动到您的 MVC 4 项目 bin 文件夹。
在 Visual Studio 中刷新,然后将 bin 文件中的所有内容包含到项目中。
您可以花很多时间尝试合并 web.config 文件,但如果用 Umbraco 版本覆盖 MVC 4 的 web.config,似乎也能正常工作。
Views 文件夹有自己的 web.config。同样,用 Umbraco 在 Views 文件夹中的 web.config 覆盖 MVC 4 项目的版本。忽略 web.config.transform 文件……它只是 Umbraco 构建过程中遗留下来的,他们还没有清理。
您可以忽略其余的 Umbraco 文件/文件夹……您的 MVC 4 项目中已经包含了您需要的内容。
为了使用 Umbraco API,我们需要添加一些引用。
您将为 bin 文件夹中的这 5 个文件中的每一个添加引用。它们都是 Umbraco DLL。
这是您应该添加的 5 个引用。
为了使您的 Global.asax.cs 文件对 Umbraco 友好,请按下图中的方式修改它。我们稍后将扩展此功能。
namespace Umbrazure.Web
{
using System;
public class MvcApplication : Umbraco.Web.UmbracoApplication
{
protected override void OnApplicationStarting(object sender, EventArgs e)
{
base.OnApplicationStarting(sender, e);
}
}
}
为了获得美观的国际 URL,请按照下图中的方式修改您的 UrlRewriting.config 文件。这将使您可以将语言和地区指定在 URL 的开头,而不是作为查询字符串。
(抱歉,无法再次粘贴。)
为了使 ASP.NET Web Forms 回发正常工作,您需要按照下图中的方式修改您的 Form.browser 文件。
(我将不再提及 Code Project 编辑器的任何问题;它们太频繁了。)
上面的文件显示了一个尚不存在的类,所以我们将创建它。首先创建一个“Control_Adapters”文件夹。
在该文件夹中,创建一个名为 UmbrazureFormRewriter 的类。
按照下图中的方式填充该类。这使得任何 form 标签都将其 action 属性设置为用户看到的预期 URL,而不是 URL 重写规则应用后服务器看到的重写 URL。
namespace Umbrazure.Web.Control_Adapters
{
using System;
public class UmbrazureFormRewriter : System.Web.UI.Adapters.ControlAdapter
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{ base.Render(new UmbrazureFormHtmlWriter(writer)); }
private class UmbrazureFormHtmlWriter : System.Web.UI.HtmlTextWriter
{
private const string STR_ACTION_ALREADY_WRITTEN = "ActionAlreadyWritten";
private const string STR_ACTION = "action";
public UmbrazureFormHtmlWriter(System.Web.UI.HtmlTextWriter writer)
: base(writer)
{ this.InnerWriter = writer.InnerWriter; }
public UmbrazureFormHtmlWriter(System.IO.TextWriter writer)
: base(writer)
{ this.InnerWriter = writer; }
public override void WriteAttribute(string name, string value, bool fEncode)
{
if (string.Equals(name, STR_ACTION, StringComparison.InvariantCultureIgnoreCase))
{
System.Web.HttpContext context = System.Web.HttpContext.Current;
if (context.Items[STR_ACTION_ALREADY_WRITTEN] == null)
{
value = context.Request.RawUrl;
context.Items[STR_ACTION_ALREADY_WRITTEN] = true;
}
}
base.WriteAttribute(name, value, fEncode);
}
}
}
}
我们终于准备好看到我们劳动的成果了。构建解决方案。云项目很奇怪……在运行云项目之前,您应该始终构建解决方案。我不确定现在是否仍然如此,但以前如果您不这样做,您可能会让您的云项目运行旧版本。
继续启用调试(Umbraco 的 web.config 已禁用它)。
Umbraco 安装
当网页使用 IP 地址加载时,请将其修改为您的开发域名。
进展!这是 Umbraco 安装页面。单击按钮继续。
我相信您会逐字阅读此页面。完成后,继续到下一页。
最烦人的安装步骤;填写数据库信息。不过,Azure 使这变得容易……
在 Azure 门户中您的 Umbraco 页面的管理页面,您可以单击底部的链接查看连接字符串。
您可以在 Umbraco 安装程序中找到填写表单所需的大部分信息。
继续填写连接字符串中的详细信息。希望您还记得创建数据库时创建的密码。
此安装步骤可能需要一两分钟。
难得一见……第一次就成功了!
Umbraco 希望您创建一个用户,您将使用该用户登录 Umbraco CMS 页面。输入您想要的任何凭据并创建您的用户。
您可以让 Umbraco 为您创建一个站点,但我们不打算这样做,因为我们想要一切都自定义。通过不安装入门套件来从头开始。
就这样,您已经设置了 Umbraco。单击按钮以查看 Umbraco UI。
这就是 Umbraco 的样子。这被称为“Content section”(内容部分)。您可以通过单击页面左下角的图标来访问不同的部分。
您还可以单击“Hide”(隐藏)按钮来隐藏那些奇怪的小部件。
这是“Settings”(设置)部分。这是开发人员花费大量时间的地方。
您将创建一个 Umbraco 称为“Document Type”(文档类型)(简称“DocType”)的东西。您可以将其视为一个类。它定义了数据的结构。数据是您在“Content”部分输入的内容,“Document Type”则指明了您可以作为内容输入的内容的类型。
将此文档类型命名为“Home”。确保取消选中创建匹配模板的复选框。
这是您的“Home”文档类型。
转到“Structure”(结构)选项卡。选中“allow at root”(允许在根节点创建)复选框,然后单击页面顶部(选项卡下方)的保存图标。通过这样做,您允许使用“Home”文档类型创建的任何内容节点都可以在最高级别创建。
接下来,创建一个模板。模板是 Umbraco 用来引用两个不同的 ASP.NET 概念:masterpages 和 views。Umbraco 中的一项新功能是模板可以是其中任何一个,但默认情况下它会创建一个 masterpage。
将您的模板命名为“Home Template”。
这是默认提供的模板(也称为 masterpage)。我认为它有点空。
用下面的标记填充您的模板。这是一个向用户提供服务器信息的页面。
完成后,单击“Save”(保存)图标。每次保存时,Umbraco 都会显示一个小的气球通知,告知操作已完成。
返回到您的“Home”文档类型,并选择“Home Template”作为允许的模板。这意味着当您从此文档类型创建内容节点时,您可以选择使用“Home Template”masterpage 来呈现它。
请记住保存;如果您导航到其他地方,系统不会警告您,您的更改将丢失。
现在您已经创建了文档类型和模板,您终于可以创建内容了,这是任何 CMS 的核心。
将您的内容节点命名为任何您想要的名称。这将作为您的主页。
内容可以“保存”或“发布”。如果您保存它,该内容将被存储到 Umbraco 数据库中,但不会显示在站点上。如果您发布它,内容将在站点上可见。继续发布。
您的通知让您知道内容已发布。请注意节点颜色也变了。
如果您单击上面的“link to document”(文档链接),您将看到主页在新选项卡中打开。巧妙之处在于,这是一个 ASP.NET Web Forms masterpage,运行在 MVC 4 项目中。Umbraco 可以混合搭配 MVC 和 Web Forms。
我们不是白费力气设置 URL 重写规则。如果您愿意,我们可以访问法裔加拿大版本的网站。请注意,服务器将语言和地区视为查询字符串值,尽管我们将其作为路径的一部分输入。
如果您单击其中一个按钮,时间将会更新。另外,URL 不会改变……这要归功于我们之前设置的 Form.browser 文件。如果我们没有这样做,我们现在会在地址栏中看到 URL 的查询字符串版本。
返回 Umbraco UI,右键单击您的主页节点并选择“Culture and Hostnames”(文化和主机名)。
在这里,我们将设置该主页应为之提供内容的所有域名。如果您想为不同的域名显示不同的内容集,您将创建另一个内容节点并将其设置为使用该域名。这是 Umbraco 管理多个域名的方法。其优点是所有内容都在同一个应用程序池中运行,因此在 Umbraco 中管理多个站点不会有额外的内存开销。
在设置完所有域名后,如果我们单击主页节点刷新它,我们将看到一个链接列表……每个域名都有一个链接。
现在我们已经看到了 Umbraco 的功能,让我们停止调试(在 Visual Studio 中单击红色方块)。
由于您在 Umbraco 中创建了一个模板(也称为 masterpage),您需要确保将其包含在 Visual Studio 项目中。否则,它将不会包含在您发送到 Azure 的任何包中。
如果您不希望安装文件夹在 Azure 上运行时运行,您可以将其从项目中排除。它不应该运行超过一次,但以前有一个 Umbraco bug,如果与 SQL 的连接丢失,Umbraco 会再次显示安装。我认为小心起见总比后悔好;排除它是为了安全起见。
看起来 Umbraco 为我们创建了另外两个文件夹……也请将它们包含到项目中,以防 Umbraco 需要它们。
仅供您参考,Umbraco 在安装过程中修改了您的 web.config。它删除了一个应用程序设置,设置了另一个应用程序设置的值,并为数据库设置了一个连接字符串。如果您正在使用源控件,了解此文件已更改以便您可以签入它会很有帮助。
现在我们已经在本地运行了安装程序,打包云项目并更新您在 Azure 上的 keanu 部署。
同样,使用相同的包更新您的 jodie 部署。
大约 10 分钟后,访问您的真实实时主页,您将看到您在 Visual Studio 中运行时看到的内容。看起来一切顺利。
处理 Umbraco 时,请记住使用 Umbraco 子域名。现在这似乎不重要,但将来您创建更多 Web 角色实例时会很重要。
为了将 MVC 视图创建为模板,请修改 umbracoSettings.config 文件中的此设置。
接下来,像往常一样调试云项目。然后,进入 Umbraco 并创建一个新模板。
您将此模板命名为“Mvc Home”。
masterpage 模板的名称大多不重要,但 MVC 视图模板的名称非常重要。原因是别名(下图所示,在名称下方)是从名称派生的。它基本上是名称的无空格版本。当您创建 MVC 控制器时,Umbraco 的路由设置是这样的:模板的名称决定了调用哪个操作方法。控制器是从文档类型的别名确定的。因此,如果我们有一个“Home”文档类型和一个“MvcHome”模板,那么该内容节点的路由将转到“Home”控制器的“MvcHome”操作方法。
用下图中的标记填充模板。请注意,我们的视图中有两个按钮。我们需要进行进一步的编码才能使其按预期工作。另外,请注意我们在 BeginForm 调用中为操作和控制器指定了虚拟值。这是因为它们仅用于构建 action 属性的值。但是,我们手动指定它,以便将其设置为请求的原始 URL(用户输入的 URL)。这是 MVC 中允许 URL 重写与回发一起工作的(如果您还记得,Web Forms 的方法是修改 Form.browser 文件)。
如果没有允许,您就无法将新模板与“Home”文档类型一起使用,所以现在就去做吧。
停止调试并返回 Visual Studio。将视图包含到项目中,以便它是下一个 Azure 包的一部分。
创建一个模型以供“Home”控制器(您很快就会添加)使用。
namespace Umbrazure.Web.Models
{
public class Home
{
public string Text { get; set; }
}
}
为了允许在 MVC 视图中的同一个 form 标签中使用多个按钮来启动不同的操作方法,您必须创建一个操作选择器,如下所示。
namespace Umbrazure.Web.Action_Selectors
{
using System;
using System.Web.Mvc;
public class AcceptParameterAttribute : ActionMethodSelectorAttribute
{
public string Name { get; set; }
public string Value { get; set; }
public override bool IsValidForRequest(
ControllerContext controllerContext,
System.Reflection.MethodInfo methodInfo)
{
var req = controllerContext.RequestContext.HttpContext.Request;
bool valid;
if (string.IsNullOrEmpty(this.Value))
{
valid = !string.IsNullOrEmpty(req.Form[this.Name]);
}
else
{
valid = string.Equals(req.Form[this.Name], this.Value,
StringComparison.InvariantCultureIgnoreCase);
}
return valid;
}
}
}
最后,创建您的主页控制器。
按照下图中的方式填充主页控制器。请注意,我们正在使用我们刚刚创建的操作选择器。第一个和第二个按钮都将调用它们自己的操作方法,因此它们可以以不同的输出来响应。
namespace Umbrazure.Web.Controllers
{
using System.Web.Mvc;
using Umbrazure.Web.Action_Selectors;
public class HomeController : Umbraco.Web.Mvc.RenderMvcController
{
[HttpGet]
public ActionResult MvcHome()
{
return CurrentTemplate(new Models.Home {
Text = "This text came from the default action method." });
}
[HttpPost]
[ActionName("MvcHome")]
[AcceptParameter(Name = "btnUpdate1")]
public ActionResult MvcHome_1(Models.Home model)
{
ModelState.Clear();
model.Text = "This text came from the first action method.";
return CurrentTemplate(model);
}
[HttpPost]
[ActionName("MvcHome")]
[AcceptParameter(Name = "btnUpdate2")]
public ActionResult MvcHome_2(Models.Home model)
{
ModelState.Clear();
model.Text = "This text came from the second action method.";
return CurrentTemplate(model);
}
}
}
再次从 Visual Studio 开始调试,并访问 Umbraco。将“Template”(模板)下拉列表设置为“Mvc Home”并发布。
如您所见,您现在正在使用 MVC 视图而不是 Web Forms masterpage 来构建主页。在 Web Forms 和 MVC 之间切换就是这么简单……只需通过下拉列表切换并单击发布。
停止调试,打包您的云项目,并将其上传到 Azure。您现在可以在实时域上看到您的 Umbraco MVC 页面正常工作了。相当不错!
通过多个 Web 角色实例进行扩展
是时候创建一个新的文档类型了。由于文档类型仅存在于数据库中,因此您可以从您的实时生产环境中创建它们。
将这个命名为“Settings”。
允许它作为根节点。
转到“Tabs”(选项卡)选项卡,并创建一个名为“Automatic”的新选项卡。自动选项卡是我们存储代码自动生成值的设置的地方。
转到“Generic Properties”(通用属性)选项卡,并创建一个名为“Refresh Token”(刷新令牌)的新属性,如下所示。
记住保存。
现在,使用您的 Settings 文档类型创建一个“Settings”节点。
这是它。现在就发布该节点,否则您以后可能会遇到问题(我犯了没有立即发布而导致一些问题的错误)。
回到 Visual Studio 环境,添加一个名为“Helpers”的新文件夹,并在其下创建一个名为“Azure”的类。按照下图中的方式填充。
另外创建一个名为 CacheRefresher 的第二个辅助类,如下所示。我知道,这几乎是代码格式的最差格式化了,但这就是它能将代码塞进单个截图所需的一切。
namespace Umbrazure.Web.Helpers
{
using System;
using UDoc = umbraco.cms.businesslogic.web.Document;
using UNode = umbraco.NodeFactory.Node;
public class CacheRefresher
{
private const int RefreshInterval = 5;
public static string LastRefreshToken { get; private set; }
private static DateTime LastRefreshCheck { get; set; }
private static Object RefreshLock = new object();
static CacheRefresher()
{ LastRefreshCheck = DateTime.Now.AddDays(-1); LastRefreshToken = "Unknown"; }
public static void EnsureFreshCache()
{
lock (RefreshLock)
{
if (DateTime.Now.Subtract(LastRefreshCheck).TotalSeconds > RefreshInterval)
{
try
{
UDoc settingsDoc = GetSettingsDoc();
if (settingsDoc != null)
{
string newToken = settingsDoc.getProperty("refreshToken")
.Value.ToString();
if (LastRefreshToken != newToken)
{
LastRefreshToken = newToken;
umbraco.library.RefreshContent();
}
}
}
catch { /* I know, bad me, I swallowed the exception. */ }
LastRefreshCheck = DateTime.Now;
}
}
}
public static void NotifyOfChange()
{
UDoc settingsDoc = GetSettingsDoc();
if (settingsDoc != null)
{
settingsDoc.getProperty("refreshToken").Value = Guid.NewGuid().ToString();
settingsDoc.Save();
}
}
private static UDoc GetSettingsDoc()
{
UDoc settingsDoc = null; UNode node = new UNode(-1);
foreach (UNode child in node.Children)
{
if (string.Equals(child.Name, "Settings",
StringComparison.InvariantCultureIgnoreCase))
{
settingsDoc = new UDoc(child.Id); break;
}
}
return settingsDoc;
}
}
}
回到您的 Global.asax.cs 文件,进行修改以匹配下图所示的代码。这将监听 Umbraco 内容发布事件。任何时候节点被发布或删除,缓存刷新器都会知晓,以便其他 Web 角色实例知道它们需要从数据库中的更改更新本地缓存。
namespace Umbrazure.Web
{
using System;
using UDoc = umbraco.cms.businesslogic.web.Document;
public class MvcApplication : Umbraco.Web.UmbracoApplication
{
protected override void OnApplicationStarting(object sender, EventArgs e)
{
base.OnApplicationStarting(sender, e);
UDoc.AfterPublish += Document_AfterPublish;
UDoc.AfterDelete += Document_AfterDelete;
}
void Document_AfterDelete(UDoc sender, umbraco.cms.businesslogic.DeleteEventArgs e)
{
Helpers.CacheRefresher.NotifyOfChange();
}
void Document_AfterPublish(UDoc sender, umbraco.cms.businesslogic.PublishEventArgs e)
{
Helpers.CacheRefresher.NotifyOfChange();
}
void Application_BeginRequest(object sender, EventArgs e)
{
try
{
Helpers.CacheRefresher.EnsureFreshCache();
}
catch { /* We don't want our requests to stop here. */ }
}
}
}
将下面截图中的高亮行添加到您的 MvcHome 视图中。它们将告诉您您所在的 Web 角色实例以及一些缓存信息。
为了确保缓存正在更新到每个 Web 角色实例,我们将向网站访问者显示一些来自 Umbraco 的数据。修改 HomeController,如下所示。
namespace Umbrazure.Web.Controllers
{
using System.Web.Mvc;
using Umbrazure.Web.Action_Selectors;
using UNode = umbraco.NodeFactory.Node;
using UProp = umbraco.interfaces.IProperty;
public class HomeController : Umbraco.Web.Mvc.RenderMvcController
{
private string GetCurrentText()
{
UProp info = UNode.GetCurrent().GetProperty("info");
return (info == null) ? string.Empty : info.Value.ToString();
}
[HttpGet]
public ActionResult MvcHome()
{
return CurrentTemplate(new Models.Home {
Text = "Default action says: " + GetCurrentText() });
}
[HttpPost]
[ActionName("MvcHome")]
[AcceptParameter(Name = "btnUpdate1")]
public ActionResult MvcHome_1(Models.Home model)
{
ModelState.Clear();
model.Text = "First action says: " + GetCurrentText();
return CurrentTemplate(model);
}
[HttpPost]
[ActionName("MvcHome")]
[AcceptParameter(Name = "btnUpdate2")]
public ActionResult MvcHome_2(Models.Home model)
{
ModelState.Clear();
model.Text = "Second action says: " + GetCurrentText();
return CurrentTemplate(model);
}
}
}
打包您的云项目并将其部署到 Azure 上的 keanu 和 jodie。然后,将 jodie 扩展到两个实例而不是一个。这将花费一些时间(大约 10 分钟)。
回到 Umbraco,为您的 Home 文档类型添加一个新选项卡。
然后在“Page”(页面)选项卡中添加一个“Info”(信息)属性。
记住保存。
如果您还没有保存 Settings 节点,请立即保存。
在主页节点上,“Info”文本框中输入您能想到的最有趣的一句话。我非常无聊,所以我选择了一个问候语。发布。
当您发布时,一个新的“刷新令牌”应该已经被生成并存储到 Umbraco 数据库中。您可以通过单击“Settings”节点并查看刷新令牌的值来确认这一点。它应该是一个 GUID。如果一个 Web 角色实例注意到它的 GUID 与 Umbraco 数据库中的 GUID 不匹配,它将刷新其缓存(及其 GUID)。
还记得我告诉您我没有立即发布“Settings”节点,这导致了我的一些问题吗?如果您犯了同样的错误,您可以通过重新映像每个 Web 角色实例来解决这些问题。
当我用 Chrome 打开主页时,我得到了第二个 Web 角色实例(它们使用零基索引),如您所见。
然后当我用 Firefox 打开主页时,我使用的是第一个 Web 角色实例。看起来负载均衡正在工作!
多环境配置
为了创建一个开发数据库,我们将不得不再次运行 Umbraco 安装程序。但是,在此之前,我们需要清理一些东西,以免安装程序感到困惑。我们将首先从项目中排除模板并将它们暂时重命名。
撤销安装程序上次运行时对 web.config 所做的更改。如果您正在使用源控件,这很容易。否则,将您当前的 web.config 文件保存到某个地方,然后用 Umbraco ZIP 下载文件中的 web.config 覆盖它。
在 Visual Studio 中开始调试,并运行整个安装过程。但是,这次,使用 simulacrum 数据库而不是 matrix 数据库。
重新创建所有模板和文档类型。不用担心填充视图的内容。但是,要使文档类型与您在生产环境中看到的匹配。请注意,您将必须切换 umbracoSettings.config 文件并重新启动调试以在创建 masterpages 和 views 之间切换(我知道,这很烦人……我希望他们将来会添加该选项到右键单击上下文菜单)。
同样重新创建内容节点。请注意顺序很重要。不要先创建 Settings 节点,否则您将花费数小时来修复它。
别忘了为主页节点设置域名。由于您将仅从 Visual Studio 运行开发站点,因此您只需要添加开发域名。实际上,如果您愿意,可以只使用其中一个。
停止 Visual Studio 调试,删除您刚刚创建的模板,用之前临时重命名的模板替换它们。然后,重新将它们包含到项目中。您应该始终在 Umbraco 中创建模板,因为它将模板信息存储在其数据库中。但是,您需要将模板作为包的一部分进行部署,因为在部署它们之前,模板可能不存在于每个 Web 角色实例的文件系统中。
接下来,您将添加三个 XML 文件(尽管它们将具有“.config”扩展名)。
这些文件是 UrlRewriting.Template.config、UrlRewriting.Debug.config 和 UrlRewriting.Release.config。按照下图中的方式填充它们,并修改主要的 UrlRewriting.config 文件。通常,XML 构建转换仅应用于 web.config 文件,但我们将做一些额外的工作来将转换应用于我们的 UrlRewriting.config 文件。这样,我们就可以在开发环境中拥有与生产环境中不同的 URL。
接下来,我们将手动修改项目文件。开始卸载项目。
然后,在文本编辑器中打开项目文件。
找到我们刚刚修改的指向 UrlRewriting 文件的行,并将它们更改为如下所示。这将使转换文件嵌套在主文件下。它还将将转换文件标记为非内容,因此它们不会部署到生产环境。
在文件的最底部,添加下图中所选的行。这些行将导致 XML 转换文件根据当前构建配置(例如,release 或 debug)转换主要的 UrlRewriting.config 文件。
现在您已完成手动更改,重新加载项目。
看起来嵌套正在工作。
您应该已经有一个 Web.Release.config 文件。修改它,使其看起来如下所示。只是,不要使用我的连接字符串,而是使用您的生产连接字符串。记住输入适当的密码。
现在,如果您从 Visual Studio 运行站点,您将看到特定于开发环境的内容。继续修改主页节点上的信息,以便清楚该信息来自 Umbraco 的开发版本。发布。
如果您访问开发环境,您可以看到开发内容。请注意,XML 转换修改了 URL 重写规则,因此您无需在语言和地区之间的 URL 中输入连字符。我知道您开发者有多讨厌输入额外的字符!
当您将开发环境与生产环境并排放置时,内容是不同的。这是因为它们使用的是不同的数据库。即使您打包您当前正在处理的项目并将其部署到生产环境,您仍然会看到不同的内容。这要归功于我们为不同构建配置添加的 XML 转换。
Twitter Bootstrap 示例网站
Twitter Bootstrap 需要 jQuery,所以先下载它。
接下来,访问自定义页面以下载完整的 Twitter Bootstrap 包。
将您刚刚下载(并已取消阻止和解压缩)的所有文件添加到您的项目中,遵循以下文件夹结构。
添加一个名为 SimplePage 的模型。您将来可以在许多地方使用它,但我们只会将其用于几个页面。
namespace Umbrazure.Web.Models
{
public class SimplePage
{
public string PageLanguage { get; set; }
public string PageDescription { get; set; }
public string PageAuthor { get; set; }
public string PageTitle { get; set; }
public string PageHeader { get; set; }
public string PageBody { get; set; }
public int CopyrightYear { get; set; }
}
}
添加一个名为“SimplePageController”的控制器。
namespace Umbrazure.Web.Controllers
{
using System;
using System.Web.Mvc;
using UNode = umbraco.NodeFactory.Node;
using UProp = umbraco.interfaces.IProperty;
public class SimplePageController : Umbraco.Web.Mvc.RenderMvcController
{
[HttpGet]
public ActionResult SimplePage()
{
return CurrentTemplate(PopulateModel());
}
private Models.SimplePage PopulateModel(Models.SimplePage model = null)
{
if (model == null) model = new Models.SimplePage();
model.CopyrightYear = DateTime.Now.Year;
model.PageLanguage = Request.QueryString["language"];
model.PageAuthor = GetUProp("pageAuthor");
model.PageBody = GetUProp("pageBody");
model.PageDescription = GetUProp("pageDescription");
model.PageHeader = GetUProp("pageHeader");
model.PageTitle = GetUProp("pageTitle");
if (string.IsNullOrEmpty(model.PageLanguage)) model.PageLanguage = "en";
return model;
}
private string GetUProp(string alias)
{
UProp info = UNode.GetCurrent().GetProperty(alias);
return (info == null) ? string.Empty : info.Value.ToString();
}
}
}
开始调试,并创建“Simple Page”模板(一个 MVC 视图)和一个“Simple Page”文档类型。请记住,您必须先在 Umbraco 中创建模板,因为它会将模板信息存储到数据库中。确保文档类型允许该模板。
允许文档类型在内容树的根节点创建,并允许它成为自身的子节点(Umbraco 允许祖父悖论)。
添加一个名为“Page”的选项卡,并在此选项卡中添加如下所示的属性。
创建一个新的顶级内容节点,使用您的“Simple Page”文档类型,根据您的喜好填写“Page”属性,并发布它。另外,将其排序到“Settings”节点上方。
编辑主机名,如下所示。我遇到了一些查看站点的困难,我认为这是因为模拟器将地址栏中通常看到的端口 81 转换为端口 82,直到它到达 Umbraco。为了安全起见,添加带有端口 82 的域名。
修改您的 hosts 文件以添加新的开发域名。
在您的实时域名处创建一个新的 CNAME 记录。同样,您可以使用您一直在使用的域名,或者您可以创建一个全新的域名。
添加绑定,以便 Azure 知道在进行 HTTP 请求时应该提供哪个项目(如下图高亮显示)。
在项目中包含您在 Umbraco 中创建的视图(也称为模板),并修改它以匹配下图中的标记。
@inherits Umbraco.Web.Mvc.UmbracoViewPage<Umbrazure.Web.Models.SimplePage>
@{
Layout = null;
}<!DOCTYPE html>
<html lang="@(Model.PageLanguage)">
<head>
<meta charset="utf-8">
<title>@(Model.PageTitle)</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="@(Model.PageDescription)">
<meta name="author" content="@(Model.PageAuthor)">
<link href="bootstrap/css/bootstrap.css" rel="stylesheet">
<style type="text/css">
body {
padding-top: 60px;
padding-bottom: 40px;
}
</style>
</head>
<body>
<!-- Navigation menu. -->
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="https://codeproject.org.cn/">Umbrazure</a>
<div class="nav-collapse collapse">
<ul class="nav">
<li><a href="https://codeproject.org.cn/About">About</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Pages<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="https://codeproject.org.cn/Article">Article</a></li>
<li><a href="https://codeproject.org.cn/Contest">Contest</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- Content. -->
<div class="container">
<h1>@(Model.PageHeader)</h1>
@(Html.Raw(Model.PageBody))
<footer>
<p>© Umbrazure @(Model.CopyrightYear.ToString())</p>
</footer>
</div>
<!-- JavaScript -->
<script src="bootstrap/js/jquery-1.9.1.js"></script>
<script src="bootstrap/js/bootstrap.js"></script>
</body>
</html>
开始调试您的云项目,并访问您的开发域名,您应该会看到您的新站点正在运行。原来的网站仍然在其自己的域名上运行。
在将包部署到 Azure 之前,请确保先在那里创建模板。现在也是创建文档类型的好时机(确保它与您在本地创建的匹配)。另外,目前在 Azure 上的模板中无需放入任何内容……它将在您部署包时被替换。
在您的生产环境中创建内容节点,确保通过 Umbraco 提供的 UI 管理主机名(如下所示)。并确保节点位于 Settings 上方,就像您在本地所做的一样。
最后,创建您的包并将其部署到 Azure。您现在应该能够看到您的两个网站。
接下来,您将创建一些根节点下的子页面。
这些是您将创建的子页面节点。用您想要的任何信息填充它们,并全部发布。
您完成了!这是您刚刚创建的所有子页面。
陷阱/修复
以下是我在撰写本文或过去遇到的一些您应该注意的事情。
- 内容节点顺序。 确保内容节点顺序正确(没有域名关联的节点放在底部)。这给我带来了一些问题。但是,这可能仅仅是因为我没有使用端口 82(Azure 模拟器会做一些奇怪的事情)。
- 端口。 Azure 模拟器在您从 Visual Studio 运行网站时,会以奇怪的方式处理端口。请务必考虑到您可能需要在地址栏中使用端口 81,而您的服务器代码可能会遇到端口 82。典型的端口(虽然看不见)是端口 80。
- 模板创建。 模板是 masterpages 和 views。如果您在 Umbraco 中创建了一个已存在于文件系统中的模板,您将收到一个错误,而且其副作用谁也无法预料。始终先在 Umbraco 中创建。
- 缓存问题。 我遇到了一些缓存未更新的问题。这与从我的旧代码到新代码的转换有关。如果您遇到问题,只需重新映像您的实例(或删除它们并重新上传包)。
- XML 转换混合配置。 我向您展示的用于 UrlRewriting.config 的转换与用于 web.config 的转换工作方式略有不同。对于 web.config,您总是在 Visual Studio 中使用主文件进行调试。也就是说,转换仅在您打包或发布时应用。但是,对于 UrlRewriting.config 转换,它们在每次构建时都会应用,并覆盖主文件。这就是为什么您将主内容存储在 UrlRewriting.Template.config 文件中的原因。请记住这一点,因为它可能导致您遇到混合配置。
- Session。 除非绝对必要,否则避免使用服务器端 session。如果您确实需要它,您将不得不创建一个自定义 session 提供程序并跨 Web 角色实例共享 session(例如,存储在数据库中)。如果您处理不当,可能会减慢您的网站速度。
- Machine Key。 我在哪里读到 Azure 会自动将 machine key 插入到您的 Web 角色 web.config 文件中。那很好,但如果它没有,并且您在 Azure 上使用 ASP.NET Web Forms,您可能需要自己来做。我还没有在 Azure 上做任何视图状态方面的工作,所以我还不确定。
- SQL Server Management Studio 限制。 SSMS 可以连接到您的 SQL Azure 数据库,但功能非常有限(例如,没有设计器)。Visual Studio 包含一些稍好用的 SQL 工具,但处理 SQL Azure 时,您仍然会遇到有限的 GUI。它不像处理 SQL Server 那样好。
- 以管理员身份运行。 如果您的计算机上的权限受限,请始终以管理员身份运行 Visual Studio。否则您会遇到问题。编辑 hosts 文件时,对于 Notepad++ 也是如此。
- Umbraco 喜欢 Chrome。 我过去在处理 Umbraco 时,除了 Chrome 之外,使用任何其他浏览器都遇到了奇怪的问题。处理 Umbraco 时,为了安全起见,请尽可能使用 Chrome。
- 公司代理/防火墙。 唉。公司代理/防火墙是我存在的祸根。它们可能导致无数问题。首先,您可能需要打开端口 1433 才能连接到 SQL Azure。此外,Visual Studio 中的 Server Explorer 需要一些特殊的变通方法才能连接到 blob 存储。而且,除非我拔掉网线,否则 hosts 文件中的条目似乎不起作用。如果您在工作场所这样做,请准备好抓狂。
- 不要清理解决方案。 如果您在 Visual Studio 中执行“Clean Solution”(清理解决方案),您可能会丢失 bin 文件夹中的 Umbraco DLL。只要您能恢复它们(例如通过源控件),那就可以了,但请牢记这一点。您可能还想考虑将它们保存在另一个文件夹中,并在构建时将它们复制到 bin。我还没有自己尝试过这种方法,但我认为它应该可行。
- 版本冲突。 我在 Visual Studio 中看到了一些与引用不同 DLL 版本相关的警告。我认为这是因为我创建的项目以 .Net 4.5 为目标,但 Umbraco 的 web.config 期望 .Net 4.0。这似乎没有引起任何问题,但如果您遇到任何问题,可以考虑使用 .Net 4.0 项目或对 web.config 进行一些调整。
- 创建用户双击。 在 Umbraco 安装过程中,请勿双击“Create User”(创建用户)按钮。看起来它什么也没做,但如果您点击第二次,它可能会损坏您的数据库,您将不得不重新开始。
- Umbraco 最佳实践。 Umbraco 中的一些东西在您学习时似乎是个好主意(例如,宏),但后来会成为障碍。发展您自己的最佳实践,并做对您有效的事情。它允许您这样做是 Umbraco 最大的优点之一。
结论
如果您一直读到文章的最后,我感到很钦佩。但是,您没有浪费时间。让 CMS 上线对于 Web 开发人员来说是一项非常有价值的技能。尤其是在 Azure 上上线 CMS,更是如此,因为这似乎是未来的发展方向。公司正逐渐放弃他们那种花费大量金钱用于人员和额外服务器(用于峰值负载)来维护其 Web 形象的旧模式。事实是,即使是最大的公司也容易遭受非常高的负载情况,而他们的基础设施无法处理(例如,在成功的超级碗广告后产生大量网络流量)。
借助 Azure 等云技术,他们不再需要持续为他们可能永远无法负担的最坏情况付费。他们可以根据需要动态扩展。有了 Umbrazure 这样的蓝图,您就有了一个真正的方法来帮助解决他们的问题。您可以为任何需要多个网站的公司工作,并且这些公司会定期更新其内容以证明 CMS 的价值。通过 Azure 集成,您可以确保您的实现对于未来的任何情况都坚如磐石。很可能,您现在正在处理这样的项目是您阅读本文的原因。无论是什么情况,我都希望本文对您有所帮助。如果您确实使用了一些您在这里学到的技术,请在文章底部留下评论;我很想听听!如果您遇到任何问题,我也会尽力提供帮助。
附录:关于源代码下载
目前有两个下载文件用于挑战二,都列在文章顶部。一个是文章中的完整代码,另一个是除了几个较大的文件之外的其他内容。我建议您下载完整版本而不是部分版本。由于 Code Project 的限制,我无法将较大的文件直接上传到他们的服务器,因此我将其存储在其他地方,并上传了部分文件,以便您可以使用 Code Project 的源代码浏览器功能在不离开文章或下载任何内容的情况下查看文件。
另外请注意,出于必要,我从下载文件中删除了其他一些项目。例如,我删除了我的源控件绑定、我的用户文件和连接字符串。源代码实际上更多是作为参考,因为您需要完成几个步骤才能使其与您的 Azure 设置一起运行。
还有一件事。代码中有一个彩蛋。在代码中搜索“easter egg”,您应该可以找到它,如果您想删除它的话。我不会透露它是什么;我不想破坏惊喜!
词汇表
以下是文章中提到的一些术语,在此解释以供您参考。
- CMS。 内容管理系统。它是一种方式,让构建网站的人员无需了解太多 Web 开发知识,就可以通过干净的 UI 输入内容。他们只需键入一些文本并单击一个按钮,就可以在网页上看到他们的更改。这使得构建大型网站更快、更容易。
- Umbraco(发音)。 Umbraco 是一个开源的 ASP.NET 内容管理系统。以下是一些 Umbraco 相关术语:
- Content Node。 要显示在网站上的数据块。通常,内容节点定义了特定页面的所有数据。但是,内容节点不必对应于一个页面(它们可以仅作为数据容器)。
- Document Type / Doctype。 文档类型(简称 doctype)是一种定义内容节点上输入数据的结构的方式。对于给定的文档类型,您可以创建许多节点,每个节点根据文档类型规定的结构指定其自己的值。
- Template。 这是 Umbraco 对两个概念(masterpages 和 views)的术语。由于 Umbraco 可以与 ASP.NET Web Forms 和 ASP.NET MVC 一起使用,因此您可以选择要使用的模板类型。当您创建内容节点时,您可以选择要用于显示该内容节点上数据的模板。
- Property。 属性是您添加到文档类型的键/值对。在文档类型中,您指定属性的名称,当从该文档类型创建内容节点时,创建者将根据每个属性填写值。属性上的值随后由模板显示。
- Azure(发音)。 微软的云产品。它允许您创建大量的 Web 服务器、数据库和文件服务器作为服务,而不是自己付费购买硬件。一些相关术语:
- Web Role。 Azure 版的 Web 服务器。具有一些额外功能。由于 Azure 默认进行负载均衡,因此您可以创建多个 Web 角色实例以允许更多的网站流量。
- Umbrazure(发音)。 “Umbraco”和“Azure”两个词的混合词。本文的重点就是这个。一种在Azure云上部署和使用Umbraco的方法。这个词是我自己创造的,但请随意使用它,就像它存在于字典里一样。
- Twitter Bootstrap。 一组客户端组件,可以使您的页面看起来美观且功能良好。例如,常用元素的样式以及用于常用功能的 JavaScript,如下拉菜单。它由Twitter的开发人员创建。
- 主机名 / 域名。 我交替使用这两个术语。基本上,URL的主要部分,不包含路径。
资源
以下是一些可供您进一步了解Umbraco、Azure以及本文其他概念的资源。
- Umbraco
- Umbraco TV。我学习Umbraco的方式。有些视频是免费的,或者您可以每月支付约20美元以访问所有视频。非常值得。
- Umbraco论坛。许多Google搜索的结果都会导向这里。或者,您也可以自己提问。我在这里得到了很好的解答。
- Umbraco文档。阅读手册。有时它会过时,但通常会引导您走向正确的方向。
- Umbraco路线图。看看Umbraco的计划很有趣。
- Umbraco博客。他们经常发布博客,内容也很重要,比如他们曾停用Umbraco 5(不是开玩笑)。
- Umbraco问题。如果您遇到问题,可以在这里报告。对于重大的破坏性更改,他们会非常迅速地处理。
- CodePlex。您可以在这里下载Umbraco,查看源代码的最新更改,或提交您自己的更改。
- 每日构建。如果您想要Umbraco的最新版本。
- Azure
- Windows Azure 文档
- Azure门户。门户本身包含一些不错的文档。只需点击屏幕右下角的问号,您就可以获得关于该特定屏幕的帮助。
- 其他
- Twitter Bootstrap
- jQuery
- 亚马逊。购买Azure书籍的好地方。只需寻找评分最高且近期的书籍。您也可以考虑查看MSBuild。