准备要部署的应用程序
在正式进入部署MVC程序到IIS之前,会介绍一些关于应用程序迁移到生产环境之前探测错误以及一旦进入生产环境最大化性能的技术。同时也会展示关于流线型部署过程的有用的功能。
检测视图错误
Razor视图会在服务器需要的时候编译而不是在VS里面生成项目时编译,正常情况下,探测视图编译错误的方式是系统的访问每一个action,从而让每一个view都能够呈现。这显然是非常乏味而且不会一直成功的技术,特别是在基于不同的model状态呈现不同的view的时候。
我们可以启用一个特别的项目选项来启用我们的视图并且报告任何编译错误。我们可以编辑一个.csproj的文件,设置MvcBuildViews为true,如下:
...
<PropertyGroup>
.....
<MvcBuildViews>true</MvcBuildViews>
</PropertyGroup>
...
这样保存以后,任何编译错误都会显示出来了。注意,这种方式只是检查编译错误,不能检测逻辑错误并且不能用来替代严格的测试体制。
配置动态页编译(Configuring Dynamic Page Compilation)
Web.config里面一个重要的配置是compilation节,如下:
<configuration>
<!-- other settings removed for clarity -->
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Web.Abstractions, Version=4.0 ...
...
在前面提到过,Razor视图是在运行时编译成.NET类的。这里的compilation配置节决定是在debug模式还是release模式执行,在开发过程中倾向于使用debug模式,该模式会让编译器做如下工作:
1.忽略代码优化以至于让编译器能够一行一行的进行编译。
2.编译请求的视图而不是在一个批次编译所有的视图
3.禁用请求超时,让我们可以长时间处于调试阶段
4.限制浏览器缓存的途径
这些都是在开发应用程序中非常有用的功能,但是这些功能会影响部署时的性能。解决的方法就是在部署时设置为:<compilation debug="true" targetFramework="4.0">
准备一个Bin部署(Preparing for a Bin Deployment)
可以将程序部署到任何安装了ASP.NET4的IIS服务器上,即使是MVC 3的框架没有安装也可以。我们通过执行一个bin部署的操作来实现,MVC框架需要的程序集会包含在bin文件夹里面。具体操作如:在项目名称右键——>添加可部署的依赖项——>选中ASP.NET MVC——>确定,VS会自动添加一个名为 _bin_deployableAssemblies文件夹到项目里面,这里文件夹里面包含了MVC3和Razor需要的程序集。当我们编译程序时,这些程序集会拷贝到bin目录下,部署时就拷贝到服务器上。这意味着无论MVC3程序集是否在服务器的GAC里安装,我们的程序都会运行成功。
准备转换的Web.config(Preparing the Web.config File for Transformation)
当我们部署一个应用时,通常会修改Web.config里面的部分配置节。VS提供了非常使用的功能让我们可以在不同的部署周期里生成不同版本的Web.config。在解决方案里面展开Web.config可以看到两个文件:Web.Debug.config和Web.Release.config,这两个文件对应Debug和Release两种配置。
上面的第二个转换是移除debug属性。这里我们实验一下,现在把上面的关于连接字符串的那部分注释去掉如下:
然后把解决方案配置改成Release模式,然后发布。这时打开Web.config可以看到连接字符串已经替换了,而且<compilation/>里面的debug也移除了。如下:
ps:到现在才知道Web.Release.config和Web.Debug.config是这么用的,之前都是部署了以后再去改连接字符串(太土了~~)。
下面会接着介绍应用到web.config的其他转换。
理解转换结构(Understanding the Transformation Structure)
转换文件基本结构跟Web.config相似。我们定义配置元素然后替换想转换的。转换文件的大致结构如下:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
...字符串转换部分...
</connectionStrings>
<system.web>
...编译转换部分...
</system.web>
</configuration>
对于每一个我们想要执行的转换,都定义了目标元素,必要的转换类型,以及任何转换需要的值。例如,要转换编译属性,那么就定义一个如下的转换:
<compilation xdt:Transform="RemoveAttributes(debug)" />
上面指明了我们想对Web.config里面的compilation节进行转换,使用的是RemoveAttributes转换并传入debug属性。
发布之前为<compilation debug="true" targetFramework="4.0">,发布之后为<compilation targetFramework="4.0">。下面的列表展示了支持的转换:
转换 | 描述 |
Insert | 向Web.config插入元素 |
InsertBefore InsertAfter |
在指定的元素之前或之后插入 |
Remove | 移除单个元素 |
RemoveAll | 移除所有跟包含的元素同名的元素 |
RemoveAttributes | 从包含的元素移除属性集合 |
SetAttributes | 设置一个或多个属性的值 |
Replace | 替换元素集合 |
下面对每一个转换进行介绍
插入配置元素
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings> <add name="NewConnection" connectionString="MyConnectionString" xdt:Transform="Insert"/> </connectionStrings> </configuration>
展示的结果为:
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="SportsStoreEntities" connectionString="provider connection string= "Data Source=xTITAN\SQLEXPRESS;User ID=adam;Password=adam;"" providerName="System.Data.EntityClient" /> <add name="NewConnection" connectionString="MyConnectionString"/> </connectionStrings> <system.web> <compilation debug="true" targetFramework="4.0"> <assemblies> <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral" /> <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral" /> </assemblies> </compilation> </system.web> </configuration>
还可以使用InsertBefore和InsertAfter来控制插入的位置:
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings> <add name="NewConnection" connectionString="MyConnectionString" xdt:Transform ="InsertBefore(/configuration/connectionStrings/add[@name='SportsStoreEntities'])"/> <add name="OtherConnection" connectionString="MyOtherConnectionString" xdt:Transform ="InsertAfter(/configuration/connectionStrings/add[@name='NewConnection'])"/> </connectionStrings> </configuration>
InsertBefore和InsertAfter转换需要一个参数来指明插入的相对位置。参数使用了XPath语法,点这里了解XPath语法。
展示执行结果:
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="NewConnection" connectionString="MyConnectionString"/> <add name="OtherConnection" connectionString="MyOtherConnectionString"/> <add name="SportsStoreEntities" connectionString="provider connection string= "Data Source=TITAN\SQLEXPRESS;User ID=adam;Password=adam;"" providerName="System.Data.EntityClient" /> </connectionStrings> <system.web> <compilation debug="true" targetFramework="4.0"> <assemblies> <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral" /> <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral" /> </assemblies> </compilation> </system.web> </configuration>
移除配置元素
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <system.web> <compilation> <assemblies> <add xdt:Transform="Remove"/> </assemblies> </compilation> </system.web> </configuration>
Remove转换会匹配集合区域的所有Add元素,当有一个或多个元素匹配时,仅仅第一个被移除。执行结果如下:
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="conn" connectionString="server=localhost;uid=root;pwd=***;database=sportsstore;"/> </connectionStrings> <system.web> <compilation debug="true" targetFramework="4.0"> <assemblies>
//移除的add
<!--<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral" />--> <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral" /> </assemblies> </compilation> </system.web> </configuration>
要移除多个元素,可以使用RemoveAll转换。
设置/移除属性
可以使用SetAttributes和RemoveAttributes两个转换来操作Web.config里面的属性:
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings> <add name="SportStoreEntities" xdt:Transform="SetAttributes(connectionString)" connectionString="MyNewConnection"/> </connectionStrings> <system.web> <compilation xdt:Transform="RemoveAttributes(targetFramework)" /> </system.web> </configuration>
第一个转换会改变连接字符串的值,第二个转换会移除了targetFramework属性。结果如下:
替换元素
可以使用Replace转换来替换Web.config整个节,如:
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings xdt:Transform="Replace"> <add name="MyFirstConnection" connectionString="MyConnection1"/> <add name="MySecondConnection" connectionString="MyConnection2"/> <add name="MyThirdConnection" connectionString="MyConnection2"/> </connectionStrings> </configuration>
在上面的例子里,我们替换了包含了在connectionStrings元素里面的所有元素:结果如下
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="MyFirstConnection" connectionString="MyConnection1"/> <add name="MySecondConnection" connectionString="MyConnection2"/> <add name="MyThirdConnection" connectionString="MyConnection2"/> </connectionStrings> <system.web> <compilation debug="true" targetFramework="4.0"> <assemblies> <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral" /> <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral" /> </assemblies> </compilation> </system.web> </configuration>
使用定位属性
Locator属性让我们能够更加明确我们所感兴趣的一个或多个元素。下面是一个没有使用Locator属性例子:
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <system.web> <compilation debug="true" targetFramework="4.0"> <assemblies> <add xdt:Transform="Remove"/> </assemblies> </compilation> </system.web> </configuration>
这里会从assemblies区域移除add。正如我们前面提到的,Remove转换会移除找到的第一个元素,如果使用RemoveAll又会移除所有的元素。如果我们想移除匹配的元素中的一个时,可以使用Locator属性。如:
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <system.web> <compilation debug="true" targetFramework="4.0"> <assemblies> <add xdt:Transform="Remove" xdt:Locator="Condition(contains(@assembly,'Helpers'))" /> </assemblies> </compilation> </system.web> </configuration>
这里指定Locator的值就限制了转换的元素是包含了Helpers的assembly属性。我们指定的表达式是联合了转换元素的路径,转换路径为:/configuration/compilation/assemblies/add并且有一个匹配assembly属性。Locator提供了三种模式供我们选择:
模式 | 用法 | 描述 |
Condition | xdt:Locator="Condition(相对XPath表达式)" | 联合相对的XPath表达式隐含转换元素的路径来限制元素的筛选 |
XPath | xdt:Locator="XPath(绝对XPath表达式)" | 应用绝对的XPath表达式来限制元素的筛选 |
Match | xdt:Locator="Match(属性名)" | 限制具有跟转换元素属性值匹配的元素的筛选 |
当我们使用Condition模式时,可以使用XPath运算符如contains,starts-with来创建更加复杂的搜索模式,还可以使用or和and运算符来创建复合表达式。如:
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings> <add xdt:Transform="SetAttributes(connectionString)" connectionString="MyConnection" xdt:Locator= "Condition(starts-with(@name, 'Sports') and contains(@providerName, 'Entity'))"/> </connectionStrings> </configuration>
XPath模式允许我们指定一个绝对XPath表达式,如:
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings> <add xdt:Transform="SetAttributes(connectionString)" connectionString="MyConnection" xdt:Locator= "XPath(/configuration/connectionStrings/add[starts-with(@name, 'Sports') and contains(@providerName, 'Entity')])"/> </connectionStrings> </configuration>
如果我们的目标是匹配具体的属性值,那么我们能使用Match模式,如下:
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings> <add xdt:Transform="SetAttributes(connectionString)" connectionString="MyConnection" xdt:Locator="Match(name, providerName)" name="SportsStoreEntities" providerName="System.Data.EntityClient"/> </connectionStrings> </configuration>
Match模式需要一个或多个属性名作为参数,匹配Web.config中具有同样属性名和相同路径的元素。本例中,指定name和providerName,这意味着转换会对具有路径
/configuration/connectionStrings/add,并且具有一个值为SportsStoreEntities的name属性以及具有值为System.Data.EntityClient的providerName属性执行。
准备项目的数据库部署
另一个非常出色的部署功能是把数据库部署作为项目的一部分。我们可以选择从我们开发的数据库复制架构和/或数据到生产环境。
开始,设置项目为Release模式。接着在项目右键——>Properties——>Package/Publish Web并选中Include all databases configures in Package/Publish SQL如下:
然后转向Package/Publish SQL属性页,点击Import from Web.config按钮,导入数据库连接字符串:
然后输入目标数据库连接字符串,然后选择部署什么,如下:
理解IIS基本原理
IIS是内置在Windows操作系统里的应用程序服务器,下面会介绍IIS的运行的背景。
理解Web站点
IIS能够同时寄宿多个独立的Web站点,对每一个站点必须指定根路径,这样IIS就会找到该文件下的无论是静态的还是动态的内容。为了将实际的请求导向一个实际的站点,IIS允许我们配置绑定,每一个绑定为IP地址,TCP端口映射所有的请求
理解虚拟目录
作为一个额外的配置级别,我们可以在一个web站点文件夹层级下的任何位置添加虚拟目录。每一个虚拟目录可以让IIS从一些其他的文件或网络路径获取内容并且就像这些内容是实际的在web站点的根文件夹下的虚拟目录呈现一样。如下:
每一个虚拟目录被标记为一个独立的应用,获取各自的配置和状态。相比它的父站点,它能够运行不同版本的ASP.NET.
理解应用程序池
IIS支持应用程序池的机制将运行在同一服务器的web应用程序隔离开,每一个程序启动一个独立的进程(包括具有不同的进程标识,最大内存使用,最大CPU使用,处理回收计划等等)。每一个站点被指派到应用程序池中的一个,如果其中一个应用崩溃了,其他的应用不会受到影响。由于同一台服务器可能寄宿多个站点,这就需要分派请求到正确的站点:我们可以绑定站点到一个或多个由下面三个部分构成的组合:
1.端口号(大多数都是80) 2.Hostname 3.IP地址
后续的对IIS的操作均跟之前在Webform里面的操作一样,安装部署Webform的方式就行了。所以后面的笔记略去,如果大家在实际的操作有什么问题,欢迎留言讨论!
今天特意看了第一篇笔记的时间2011-11-30,整个笔记到今天为止近7个月的时间,现在告于段落。感谢园友的支持,谢谢!接下来我打算学习nopcommerce这个开源项目来加深MVC的学习。希望已经接触了该开源项目的同学能够提供资源或学习建议,谢谢!
本文转自Rt-张雪飞博客园博客,原文链接http://www.cnblogs.com/mszhangxuefei/archive/2012/06/20/mvcnotes_35.html如需转载请自行联系原作者
张雪飞