一.背景
一般如果通过包管理平台管理客户环境的应用和服务,在升级场景下一般是增量更新,不会更新应用的配置文件,如果人工更改客户环境的配置文件,成本较大。本文介绍了如何通过平台更新应用的配置文件方法。
二.原理
三.步骤
1、创建更新文件
在更新包中创建一个文件夹config_migration,文件夹中放后缀为_update.config的文件。xxxx_update.config,xxxx代表应用名称。
在推包时程序会自动检测是否存在该文件,有则进行执行。
2、如何定义更新文件
- xxxx_update.config文件内容遵循了微软标准的 xdt:Transform 语法。
- XML-Document-Transform 命名空间定义两个特性:Locator 和 Transform。
- Locator 特性指定要以某种方式更改的 Web.config 元素或一组元素。
- Transform 特性指定要对 Locator 特性所查找的元素执行哪些操作。
3、特性语法
Locator特性语法
- Condition:指定XPath表达式,该表达式会追加到当前元素的 XPath 表达式。 选择了与组合 XPath 表达式匹配的元素。
- Match:选择针对指定的一个或多个特性具有匹配值的一个或多个元素。 如果指定了多个特性名称,则将仅选择与所有指定特性匹配的元素。
- XPath:指定应用于开发Web.config文件的绝对XPath表达式。与Condition不同,所指定的表达式不追加到与当前元素对应的隐式XPath表达式
Transform特性语法
- Replace :将所选的元素替换为在转换文件中指定的元素。
- Insert:将转换文件中定义的元素作为所选的一个或多个元素的同级进行添加。 该新元素被添加到任何集合的末尾。
- InsertBefore:将转换 XML 中定义的元素直接插入到由指定 XPath 表达式选择的元素之前。 该 XPath 表达式必须是一个绝对表达式,因为它作为一个整体应用于开发 Web.config 文件,而不只是追加到当前元素的隐式 XPath 表达式中。
- InsertAfter:将转换 XML 中定义的元素直接插入到由指定 XPath 表达式选择的元素之后。 该 XPath 表达式必须是一个绝对表达式。
- Remove:移除选定元素。 如果选择了多个元素,则移除第一个元素。
- RemoveAll:移除选定的一个或多个元素。
- RemoveAttributes:从选择元素中移除指定特性。
- SetAttributes:仅设置指定元素的指定属性
4、语法示例:
Locator 特性语法示例
Condition:指定XPath表达式,该表达式会追加到当前元素的 XPath 表达式。 选择了与组合 XPath 表达式匹配的元素。
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--示例 更新 connectionStrings 下name 等于 oldname 或着 providerName 等于 oldprovider 的元素内容(连name都更新)-->
<connectionStrings>
<add name="newconnect" connectionString="newstring" providerName="newprovider" xdt:Transform="Replace" xdt:Locator="Condition(@name='oldname'or @providerName='oldprovider')" />
</connectionStrings>
</configuration>
Match:选择针对指定的一个或多个特性具有匹配值的一个或多个元素。 如果指定了多个特性名称,则将仅选择与所有指定特性匹配的元素。
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--示例 更新 connectionStrings 下name 等于 "oldconnect" 元素的内容(不更新name的值)-->
<connectionStrings>
<add name="oldconnect" connectionString="newstring" providerName="newprovider" xdt:Transform="Replace" xdt:Locator="Match(name)" />
</connectionStrings>
</configuration>
XPath:指定应用于开发Web.config文件的绝对XPath表达式。与Condition不同,所指定的表达式不追加到与当前元素对应的隐式XPath表达式
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--示例 更新 connectionStrings 下name 等于 "test" 或 providerName 等于"System.Data.SqlClient" 元素的内容(更新name的值)-->
<connectionStrings>
<add name="test" connectionString="newstring" providerName="newprovider"
xdt:Transform="Replace"
xdt:Locator="XPath(configuration/connectionStrings[@name='test'
or @providerName='System.Data.SqlClient'])" />
</connectionStrings>
</configuration>test
Transform 特性语法示例
Replace :将所选的元素替换为在转换文件中指定的元素。
Insert:将转换文件中定义的元素作为所选的一个或多个元素的同级进行添加。 该新元素被添加到任何集合的末尾。
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--示例 在appsetting中插入一个键值 -->
<appSettings>
<add key="test" value="11" xdt:Transform="Insert" />
</appSettings>
</configuration>
InsertBefore:将转换 XML 中定义的元素直接插入到由指定 XPath 表达式选择的元素之前。 该 XPath 表达式必须是一个绝对表达式,因为它作为一个整体应用于开发 Web.config 文件,而不只是追加到当前元素的隐式 XPath 表达式中。
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--示例 在authorization下的deny元素之前插入一个allow元素-->
<authorization>
<allow roles="Admins"
xdt:Transform="InsertBefore(/configuration/system.web/authorization/deny[@users='*'])" />
</authorization>
</configuration>
InsertAfter:将转换 XML 中定义的元素直接插入到由指定 XPath 表达式选择的元素之后。 该 XPath 表达式必须是一个绝对表达式。
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--示例 在authorization下的allow元素之后插入一个deny 元素-->
<authorization>
<deny users="UserName"
xdt:Transform="InsertAfter
(/configuration/system.web/authorization/allow[@roles='Admins'])" />
</authorization>
</configuration>
Remove:移除选定元素。 如果选择了多个元素,则移除第一个元素。
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--示例 删除 name等于 test的add元素-->
<connectionStrings>
<add xdt:Transform="Remove" xdt:Locator="Condition(@name='test')"/>
</connectionStrings>
</configuration>
RemoveAll:移除选定的一个或多个元素。
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--示例 删除connectionStrings 元素下所有add元素-->
<connectionStrings>
<add xdt:Transform="RemoveAll" />
</connectionStrings>
</configuration>
RemoveAttributes:从选择元素中移除指定特性
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--示例 移除connectionStrings 元素下name等于'oldname'的providerName属性 -->
<connectionStrings>
<add name="connect01" connectionString="newstring" providerName="newprovider" xdt:Transform="RemoveAttributes(providerName)" xdt:Locator="Condition(@name='oldname')" />
</connectionStrings>
</configuration>
SetAttributes:仅设置指定元素的指定属性
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--示例 将web应用的框架版本 更换成4.8-->
<system.web>
<compilation targetFramework="4.8" xdt:Transform="SetAttributes(targetFramework)" />
</system.web>
</configuration>
父元素上的 Transform 特性会影响子元素,即使没有为子元素指定任何 Transform 也是如此。例如,如果将特性 xdt:Transform="Replace" 放在 system.web 元素中,则 system.web 元素的所有子元素将替换为转换文件中的内容。
参考:用于使用 Visual Studio 部署 Web 应用程序项目的 Web.config 转换语法
5、调用方法
- 引用 Microsoft.Web.XmlTransform
- 参考代码
/// <summary>
/// 执行xml转换
/// </summary>
/// <param name="sourceFile">源配置文件</param>
/// <param name="transformFile">转换配置文件</param>
/// <param name="distinctFile">目标配置文件</param>
/// <param name="logger">日志参数</param>
public static void Execute(string sourceFile, string transformFile, string distinctFile, IXmlTransformationLogger logger)
{
if (!System.IO.File.Exists(sourceFile) && !System.IO.File.Exists(transformFile))
{
throw new FileNotFoundException("The config or transform file do not exist!");
}
using (var doc = new Microsoft.Web.XmlTransform.XmlTransformableDocument())
{
doc.Load(sourceFile);
using (var tranform = new Microsoft.Web.XmlTransform.XmlTransformation(transformFile, logger))
{
if (tranform.Apply(doc))
{
doc.Save(distinctFile);
}
else
{
throw new InvalidOperationException("XML转换失败,详情参见日志。");
}
}
}
}