使用Web.Config转换的高级任务

43

有没有办法“转换”特定的值部分,而不是替换整个值或属性?

例如,我有几个appSettings条目,指定不同webservices的URL。这些条目在开发环境和生产环境中略有不同。有些比其他的更不平凡。

<!-- DEV ENTRY -->
<appSettings>
 <add key="serviceName1_WebsService_Url" value="http://wsServiceName1.dev.example.com/v1.2.3.4/entryPoint.asmx" />
 <add key="serviceName2_WebsService_Url" value="http://ma1-lab.lab1.example.com/v1.2.3.4/entryPoint.asmx" />
</appSettings>

<!-- PROD ENTRY -->
<appSettings>
 <add key="serviceName1_WebsService_Url" value="http://wsServiceName1.prod.example.com/v1.2.3.4/entryPoint.asmx" />
 <add key="serviceName2_WebsService_Url" value="http://ws.ServiceName2.example.com/v1.2.3.4/entryPoint.asmx" />
</appSettings>

请注意第一个条目的唯一区别是“.dev”替换为“.prod”。在第二个条目中,子域名不同:“ma1-lab.lab1”替换为“ws.ServiceName2” 到目前为止,我知道可以在Web.Release.Config中执行以下操作:
<add xdt:Locator="Match(key)" xdt:Transform="SetAttributes(value)" key="serviceName1_WebsService_Url" value="http://wsServiceName1.prod.example.com/v1.2.3.4/entryPoint.asmx" />
<add xdt:Locator="Match(key)" xdt:Transform="SetAttributes(value)" key="serviceName2_WebsService_Url" value="http://ws.ServiceName2.example.com/v1.2.3.4/entryPoint.asmx" />

然而,每当该Web服务的版本更新时,我都必须更新Web.Release.Config,这就违背了简化我的web.config更新的目的。
我知道我也可以将该URL拆分为不同的部分并独立更新它们,但我更愿意将它们全部放在一个键中。
我已经查看了可用的web.config转换,但似乎没有针对我想要实现的内容。
这些是我参考的网站: Vishal Joshi的博客, MSDN帮助Channel9视频
2个回答

70
事实上,您可以这样做,但并不像您想象的那么容易。您可以创建自己的配置转换。我刚刚在http://sedodream.com/2010/09/09/ExtendingXMLWebconfigConfigTransformation.aspx上写了一篇非常详细的博客文章。以下是要点:
  • 创建类库项目
  • 参考Web.Publishing.Tasks.dll(位于%Program Files (x86)%MSBuild\Microsoft\VisualStudio\v10.0\Web文件夹下)
  • 扩展Microsoft.Web.Publishing.Tasks.Transform类
  • 实现Apply()方法
  • 将程序集放置在众所周知的位置
  • 使用xdt:Import使新的转换可用
  • 使用transform

这是我创建的用于替换的类

namespace CustomTransformType
{
    using System;
    using System.Text.RegularExpressions;
    using System.Xml;
    using Microsoft.Web.Publishing.Tasks;

    public class AttributeRegexReplace : Transform
    {
        private string pattern;
        private string replacement;
        private string attributeName;

        protected string AttributeName
        {
            get
            {
                if (this.attributeName == null)
                {
                    this.attributeName = this.GetArgumentValue("Attribute");
                }
                return this.attributeName;
            }
        }
        protected string Pattern
        {
            get
            {
                if (this.pattern == null)
                {
                    this.pattern = this.GetArgumentValue("Pattern");
                }

                return pattern;
            }
        }

        protected string Replacement
        {
            get
            {
                if (this.replacement == null)
                {
                    this.replacement = this.GetArgumentValue("Replacement");
                }

                return replacement;
            }
        }

        protected string GetArgumentValue(string name)
        {
            // this extracts a value from the arguments provided
            if (string.IsNullOrWhiteSpace(name)) 
            { throw new ArgumentNullException("name"); }

            string result = null;
            if (this.Arguments != null && this.Arguments.Count > 0)
            {
                foreach (string arg in this.Arguments)
                {
                    if (!string.IsNullOrWhiteSpace(arg))
                    {
                        string trimmedArg = arg.Trim();
                        if (trimmedArg.ToUpperInvariant().StartsWith(name.ToUpperInvariant()))
                        {
                            int start = arg.IndexOf('\'');
                            int last = arg.LastIndexOf('\'');
                            if (start <= 0 || last <= 0 || last <= 0)
                            {
                                throw new ArgumentException("Expected two ['] characters");
                            }

                            string value = trimmedArg.Substring(start, last - start);
                            if (value != null)
                            {
                                // remove any leading or trailing '
                                value = value.Trim().TrimStart('\'').TrimStart('\'');
                            }
                            result = value;
                        }
                    }
                }
            }
            return result;
        }

        protected override void Apply()
        {
            foreach (XmlAttribute att in this.TargetNode.Attributes)
            {
                if (string.Compare(att.Name, this.AttributeName, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    // get current value, perform the Regex
                    att.Value = Regex.Replace(att.Value, this.Pattern, this.Replacement);
                }
            }
        }
    }
}

这是web.config文件

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="one" value="one"/>
    <add key="two" value="partial-replace-here-end"/>
    <add key="three" value="three here"/>
  </appSettings>
</configuration>

这是我的配置转换文件

<?xml version="1.0"?>

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">

  <xdt:Import path="C:\Program Files (x86)\MSBuild\Custom\CustomTransformType.dll"
              namespace="CustomTransformType" />

  <appSettings>
    <add key="one" value="one-replaced" 
         xdt:Transform="Replace" 
         xdt:Locator="Match(key)" />
    <add key="two" value="two-replaced" 
         xdt:Transform="AttributeRegexReplace(Attribute='value', Pattern='here',Replacement='REPLACED')" 
         xdt:Locator="Match(key)"/>
  </appSettings>
</configuration>

转换后的结果如下:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="one" value="one-replaced"/>
    <add key="two" value="partial-replace-REPLACED-end"/>
    <add key="three" value="three here"/>
  </appSettings>
</configuration>

Sayed,太棒了!非常感谢你抽出时间来回答我的问题,我已经开始失去希望了 :) - Diego C.
哇塞,这太棒了!非常感谢,伙计。这正是我需要的 :) - Artiom Chilaru
太糟糕了,没有更简单的方法来实现这个任务。:( 不过还是谢谢你,这很有帮助。 - Andrei Dvoynos
1
这对我帮助很大。不过,你的类没有将变换应用于所有匹配的节点。我修改了Apply方法以实现此目的:protected override void Apply() { foreach (XmlNode target in this.TargetNodes) { foreach (XmlAttribute att in target.Attributes) { if (string.Compare(att.Name, this.AttributeName, StringComparison.InvariantCultureIgnoreCase) == 0) { // get current value, perform the Regex att.Value = Regex.Replace(att.Value, this.Pattern, this.Replacement); } } } } - Brad Wilkie

3

最新更新:如果您正在使用Visual Studio 2013,应该引用%Program Files(x86)%MSBuild\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.XmlTransform.dll。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接