首页 > 学院 > 开发设计 > 正文

利用Powershell自动部署asp.net mvc网站项目 (一)

2019-11-17 01:36:56
字体:
来源:转载
供稿:网友

利用Powershell自动部署asp.net mvc网站项目 (一)

这一篇中我们会写一些关于自动化部署的代码。我们会使用Powershell书写这类代码。

你将发现这篇文章中涉及的东西非常具体,有的要求甚至相当苛刻且可能不具有通用性。这是因为部署从来都是跟环境打交道,部署过程中协作的组建太多,相互之间的交集不可能太大。可能唯一能够通用的是自动化部署的基本原则(只是这篇文章的基本原则):

  • 每一次自动化部署结束之后,应用程序都会有相同的初始状态。
  • 自动化部署的机器非常干净,只有相应的Windows Server系统和.NET Framework。尤其是,不会有 Visual Studio。

我们需要公开一些基本的环境信息:

  • 64-bit Windows Server 2008/2012/2012 R2或者 64-bit Windows 7/8/8.1
  • 我们的工程是使用Microsoft Visual Studio 2013开发的;
  • .NET Framework版本为 4.5
  • ASP.NET MVC的版本为 5.0.0
  • Microsoft Build Tool的版本为 12.0

关于MSBuild这里需要多说几句。在Visual Studio2013 发布之前,MSBuild是随.NET Framework一起发布的。这意味着我们可以不用安装Visual Studio就可以构建 .NET 应用程序。

这是多么美好的世界啊!因此,上一句话是假的。尤其是当你构建ASP.NETWeb 应用程序的时候,你马上就会遇到 “Cannot found … Webapplication.target” 的错误。如果你 StackOverflow 一下就可以知道,我们需要做的是安装Visual Studio或者从另外一台安装了Visual Studio的机器上将相关的文件拷贝出来。这真是——丢人的设计!linux 的拥趸又有了发泄的空间。

于是微软决定正视这个问题。从Visual Studio2013 开始,MSBuild将与Visual Studio而不是.NET Framework一起发布。这引来了一片骂声。我不得不说,大家在生活中不论遇到什么事情都要保持足够的冷静,往往先发脾气的得不到任何的好处。事实是,由于.NET Framework发布的周期是相对较长的,因此微软目前越来越倾向于使用 NuGet 进行类库的发布,这样有助于削减.NET Framework基础类库的大小,并缩短基础类库的发布周期。相应的MSBuildVisual Studio的发布周期也希望进行独立的变化。MSBuild将和Visual Studio保持发布周期的一致性,并不意味这MSBuild依赖于Visual Studio。因此我们当然可以下载MSBuild的独立安装包Microsoft Build Tools,并在一台没有Visual Studio的服务器上进行自动化构建。

再次强调,如果幸运,你可以直接运行这篇文章中的例子。但是你不要指望将这篇文章的脚本拷贝到你的工程就可以正常工作。因为部署是一个因地制宜的任务,需要具体分析。你可能会遇到各种各样的环境问题,但是我认为最重要的还是思路。

部署是什么

简单来说,部署就是 “构建(Build)” –> “拷贝” –> “配置”。那么我们就开始一个一个解决它。这一篇将着眼于构建。

编译和构建应用程序 – 思路

如何构建应用程序呢?答案是先把需要的东西都拷贝过来,然后再用工具构建。好极了,我们需要拷贝什么东西呢?当然是先把源代码拷贝过来。

┌────────────────┐│ Src of MyApp   │└────────────────┘

光源代码还不行,因为我们的程序依赖于第三方库(箭头代表依赖关系)。

┌────────────────┐│ Dependent libs │└────────────────┘        ↑┌────────────────┐ │ Src of MyApp   │└────────────────┘

例如,对于我们构建的那个简简单单的 ASP.NET MVC 5 的应用程序,我们就需要在构建之前下载它依赖的类库:

  • Microsoft.AspNet.Mvc 5.0.0
  • Microsoft.AspNet.Razor 3.0.0
  • Microsoft.AspNet.WebPages 3.0.0
  • Microsoft.Web.Infrastructure 1.0.0.0

源代码和依赖库都拷贝完了,那么接下来我们就需要将构建工具也拷贝过来:

┌────────────────┐│ Dependent libs │└────────────────┘        ↑┌────────────────┐     ┌───────────────────┐│ Src of MyApp   │────→│Tools for compiling│└────────────────┘     └───────────────────┘

对于我们来说,构建的工具只有一个:

  • MSBuild

如今工具,源代码一应俱全,我们可以开始编译了。

安装 MSBuild

如果你做实验的机器上安装了Visual Studio2013——ExPRess 版本的也是可以的——那么你可以跳过这一步,否则请下载Microsoft Build Tools并安装。

下载应用程序的代码

我们的代码是现成的,只需要从 git repository clone 下来就可以了。你也可以从这个地址 clone 到一个范例代码,并转换到相应的 commit。

git clone https://github.com/lxconan/MvcFromZero.gitgit reset --hard 340abb32433c99975bd6485f79db6ca077119477

好了,完成了,到目前为止一切都是那么的轻松愉快。

下载应用的依赖库

我们将使用 nuget 管理包的依赖。因此我们首先要下载NuGet的命令行客户端,可以从这里下载。

接下来的行为都需要明确的目录结构。为了便于说明,我们将建立如下的目录结构。

MvcFromZero |- src |   |- FromZero.App |   |- packages | |- build     |- tools

其中,src 目录存放 Solution 的源代码,而 build 目录存放自动化构建所需的各种工具和脚本。其中自动化构建需要的工具将放在 build/tools 目录下。因此我们也会将 nuget.exe 放在这个目录下。

接下来我们在 build 目录下建立 deploy.ps1 脚本,我们将在这个脚本中完成接下来的任务。我们先来下载依赖的包。NuGet 的包管理是通过package.config文件进行的。需要指出的是package.config也具有一定的层次关系。首先 Solution 级别的包信息存储在两个地方:

  • 第一个是 Solution 目录下的.nuget/package.config文件,这个文件中存储的是非特定项目使用的包(如果并没有这种类型的包,则该目录不存在,或者该目录下没有任何文件);
  • 第二个是 Solution 目录下的packages/repositories.config文件,这个文件存储了该解决方案下的每一个工程的packages.config文件的路径。

而 Solution 下的每一个 Project 的包定义存储在 Project 目录下的package.config中。

为了下载这些依赖的包是否需要人为遍历这些config文件呢?原来是,而从 nuget 2.7 开始,可以直接支持 Solution 范围内的包下载,于是额我们就可以使用如下的简单函数完成包的下载了。

Function Install-SolutionPackages() {    iex "$global_nugetPath restore $global_solutionFilePath"}

其中,$global_nugetPath是 nuget.exe 的路径,而$global_solutionFilePath是工程文件(在这里是 FromZero.App.csproj)的路径。

接下来需要确定的是构建工具的位置,我们可以使用注册表查找MSBuild的位置的,由于我们使用了 2013 版本的MSBuild(Toolset 的版本号为 12.0),因此我们的查找脚本为:

Function Get-MsBuildPath() {    $msBuildRegPath = "HKLM:/SOFTWARE/Microsoft/MSBuild/ToolsVersions/12.0"    $msBuildPathRegItem = Get-ItemProperty $msBuildRegPath -Name "MSBuildToolsPath"    $msBuildPath = $msBuildPathRegItem.MsBuildToolsPath + "msbuild.exe"    return $msBuildPath}

上述两步完成之后,就可以编译我们的工程了:

Function Compile-Project() {    iex -Command "& '$global_msBuildPath' $project_path"}

你迫不及待的试验了你的代码,但是却发现出了问题,MSBuild报告无法找到Microsoft.WebApplication.targets文件。这是怎么回事,我们已经明明在MSBuild中安装了Microsoft.WebApplication.targets了啊?这是因为为了保持和Microsoft Visual Studio2010 SP1 的工程的兼容性,Visual Studio2012/2013 的工程默认将$(VisualStudioVersion)环境变量设置为10.0。这样,target 文件的查询路径就成了:

$(MSBuildExtensionsPath32)/Microsoft/VisualStudio/v10.0

而不是:

$(MSBuildExtensionsPath32)/Microsoft/VisualStudio/v12.0

因此我们需要修正这个环境变量。请使用文本编辑器打开FromZero.App.csproj文件,找到如下的定义:

<PropertyGroup>  <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>  <VSToolsPath    Condition="'$(VSToolsPath)' == ''">    $(MSBuildExtensionsPath32)/Microsoft/VisualStudio/v$(VisualStudioVersion)  </VSToolsPath></PropertyGroup>

将其中的VisualStudioVersion节替换为:

<VisualStudioVersion>12.0</VisualStudioVersion>

再次运行:祝贺你,你已经能够成功的下载所有的依赖,并完成工程的编译了!在本文的结束,附上 deploy.ps1 到目前为止的所有代码:

$ErrorActionPreference = 'Stop'# Environment helpers ------------------------------------Function Get-MsBuildPath() {    $msBuildRegPath = "HKLM:/SOFTWARE/Microsoft/MSBuild/ToolsVersions/12.0"    $msBuildPathRegItem = Get-ItemProperty $msBuildRegPath -Name "MSBuildToolsPath"    $msBuildPath = $msBuildPathRegItem.MsBuildToolsPath + "msbuild.exe"    return $msBuildPath}# Environment variables ----------------------------------$global_buildDirPath = Get-Location$global_msBuildPath = Get-MsBuildPath$global_solutionPath = "$global_buildDirPath/../src"$global_solutionFilePath = "$global_solutionPath/src.sln"$global_nugetPath = "$global_buildDirPath/tools/nuget.exe"# Install nuget packages ---------------------------------Function Install-SolutionPackages() {    iex "$global_nugetPath restore $global_solutionFilePath"}$project_path = $global_solutionPath + '/FromZero.App/FromZero.App.csproj'Function Compile-Project() {    iex -Command "& '$global_msBuildPath' '$project_path'"}Install-SolutionPackagesCompi
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表