diff --git a/AzureIntegration.sln b/AzureIntegration.sln
index e67e0a1102..db46b9da9f 100644
--- a/AzureIntegration.sln
+++ b/AzureIntegration.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26814.1
+VisualStudioVersion = 15.0.27004.2002
MinimumVisualStudioVersion = 15.0.26730.03
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.AzureAppServicesIntegration", "src\Microsoft.AspNetCore.AzureAppServicesIntegration\Microsoft.AspNetCore.AzureAppServicesIntegration.csproj", "{5916BEB5-0969-469B-976C-A392E015DFAC}"
EndProject
@@ -46,6 +46,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.AzureA
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.AzureAppServices.TestBundle", "src\Microsoft.AspNetCore.AzureAppServices.TestBundle\Microsoft.AspNetCore.AzureAppServices.TestBundle.csproj", "{1EC31DA1-131D-4257-B001-BE8391E6077E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Web.Xdt.Extensions.Tests", "test\Microsoft.Web.Xdt.Extensions.Tests\Microsoft.Web.Xdt.Extensions.Tests.csproj", "{809AEE05-1B28-4E31-8959-776B249BD725}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests", "test\Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests\Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests.csproj", "{491A857A-3529-4375-985D-D748F9F01476}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -100,6 +104,14 @@ Global
{1EC31DA1-131D-4257-B001-BE8391E6077E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1EC31DA1-131D-4257-B001-BE8391E6077E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1EC31DA1-131D-4257-B001-BE8391E6077E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {809AEE05-1B28-4E31-8959-776B249BD725}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {809AEE05-1B28-4E31-8959-776B249BD725}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {809AEE05-1B28-4E31-8959-776B249BD725}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {809AEE05-1B28-4E31-8959-776B249BD725}.Release|Any CPU.Build.0 = Release|Any CPU
+ {491A857A-3529-4375-985D-D748F9F01476}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {491A857A-3529-4375-985D-D748F9F01476}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {491A857A-3529-4375-985D-D748F9F01476}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {491A857A-3529-4375-985D-D748F9F01476}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -117,6 +129,8 @@ Global
{0899A101-E451-40A4-81B0-7AA18202C25D} = {CD650B4B-81C2-4A44-AEF2-A251A877C1F0}
{2B2C37FF-9249-4EA4-9A7F-038B55A15C2C} = {CD650B4B-81C2-4A44-AEF2-A251A877C1F0}
{1EC31DA1-131D-4257-B001-BE8391E6077E} = {FF9B744E-6C59-40CC-9E41-9D2EBD292435}
+ {809AEE05-1B28-4E31-8959-776B249BD725} = {CD650B4B-81C2-4A44-AEF2-A251A877C1F0}
+ {491A857A-3529-4375-985D-D748F9F01476} = {CD650B4B-81C2-4A44-AEF2-A251A877C1F0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5743DFE7-1AA5-439D-84AE-A480EA389927}
diff --git a/build/repo.props b/build/repo.props
index 2f58b1fe66..3e28b40259 100644
--- a/build/repo.props
+++ b/build/repo.props
@@ -14,6 +14,9 @@
Condition="'$(AntaresTests)' == ''"
Include="$(FunctionalTestsProject)" />
+
+
+
diff --git a/src/Microsoft.Web.Xdt.Extensions/InsertOrAppendAttribute.cs b/src/Microsoft.Web.Xdt.Extensions/InsertOrAppendAttribute.cs
index 26cb33338d..c2e711cb93 100644
--- a/src/Microsoft.Web.Xdt.Extensions/InsertOrAppendAttribute.cs
+++ b/src/Microsoft.Web.Xdt.Extensions/InsertOrAppendAttribute.cs
@@ -107,10 +107,12 @@ namespace Microsoft.Web.Xdt.Extensions
foreach (XmlNode targetNode in TargetChildNodes)
{
+ var foundAttribute = false;
foreach (XmlAttribute att in targetNode.Attributes)
{
if (string.Equals(att.Name, AttributeName, StringComparison.OrdinalIgnoreCase))
{
+ foundAttribute = true;
if (string.IsNullOrEmpty(att.Value))
{
att.Value = transformAtt.Value;
@@ -128,6 +130,13 @@ namespace Microsoft.Web.Xdt.Extensions
}
}
}
+
+ if (!foundAttribute)
+ {
+ var attribute = targetNode.OwnerDocument.CreateAttribute(AttributeName);
+ attribute.Value = transformAtt.Value;
+ targetNode.Attributes.Append(attribute);
+ }
}
}
}
diff --git a/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests.csproj b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests.csproj
new file mode 100644
index 0000000000..9928aadbcc
--- /dev/null
+++ b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests.csproj
@@ -0,0 +1,29 @@
+
+
+
+ net461
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
diff --git a/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/TransformTest.cs b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/TransformTest.cs
new file mode 100644
index 0000000000..c8972cbf58
--- /dev/null
+++ b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/TransformTest.cs
@@ -0,0 +1,78 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Xml;
+using Microsoft.Web.XmlTransform;
+using Xunit;
+
+namespace Microsoft.AspNetCore.AzureAppServices.SiteExtension
+{
+ public class TransformTest
+ {
+ [Theory]
+ [InlineData("config_empty.xml")]
+ [InlineData("config_existingline.xml")]
+ [InlineData("config_existingEmptyValue.xml")]
+ public void Transform_EmptyConfig_Added(string configFile)
+ {
+ var doc = LoadDocAndRunTransform(configFile);
+
+ Assert.Equal(2, doc.ChildNodes.Count);
+ var envNode = doc["configuration"]?["system.webServer"]?["runtime"]?["environmentVariables"];
+
+ Assert.NotNull(envNode);
+
+ Assert.Equal(2, envNode.ChildNodes.Count);
+
+ var firstChild = envNode.FirstChild;
+ Assert.Equal("add", firstChild.Name);
+ Assert.Equal("DOTNET_ADDITIONAL_DEPS", firstChild.Attributes["name"].Value);
+ Assert.Equal(@"%ProgramFiles%\dotnet\additionalDeps\Microsoft.AspNetCore.AzureAppServices.HostingStartup\",
+ firstChild.Attributes["value"].Value);
+
+ var secondChild = firstChild.NextSibling;
+ Assert.Equal("add", secondChild.Name);
+ Assert.Equal("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", secondChild.Attributes["name"].Value);
+ Assert.Equal("Microsoft.AspNetCore.AzureAppServices.HostingStartup", secondChild.Attributes["value"].Value);
+ }
+
+ [Fact]
+ public void Transform_ExistingValue_AppendsValue()
+ {
+ var doc = LoadDocAndRunTransform("config_existingvalue.xml");
+
+ Assert.Equal(2, doc.ChildNodes.Count);
+ var envNode = doc["configuration"]?["system.webServer"]?["runtime"]?["environmentVariables"];
+
+ Assert.NotNull(envNode);
+
+ Assert.Equal(2, envNode.ChildNodes.Count);
+
+ var firstChild = envNode.FirstChild;
+ Assert.Equal("add", firstChild.Name);
+ Assert.Equal("DOTNET_ADDITIONAL_DEPS", firstChild.Attributes["name"].Value);
+ Assert.Equal(@"ExistingValue1;%ProgramFiles%\dotnet\additionalDeps\Microsoft.AspNetCore.AzureAppServices.HostingStartup\",
+ firstChild.Attributes["value"].Value);
+
+ var secondChild = firstChild.NextSibling;
+ Assert.Equal("add", secondChild.Name);
+ Assert.Equal("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", secondChild.Attributes["name"].Value);
+ Assert.Equal("ExistingValue2;Microsoft.AspNetCore.AzureAppServices.HostingStartup", secondChild.Attributes["value"].Value);
+ }
+
+ private static XmlDocument LoadDocAndRunTransform(string docName)
+ {
+ // Microsoft.Web.Hosting.Transformers.ApplicationHost.SiteExtensionDefinition.Transform
+ // (See Microsoft.Web.Hosting, Version=7.1.0.0) replaces variables for you in Azure.
+ var transformFile = File.ReadAllText("applicationHost.xdt");
+ transformFile = transformFile.Replace("%XDT_EXTENSIONPATH%", AppDomain.CurrentDomain.BaseDirectory);
+ var transform = new XmlTransformation(transformFile, isTransformAFile: false, logger: null);
+ var doc = new XmlDocument();
+ doc.Load(docName);
+ Assert.True(transform.Apply(doc));
+ return doc;
+ }
+ }
+}
diff --git a/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_empty.xml b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_empty.xml
new file mode 100644
index 0000000000..1156926c52
--- /dev/null
+++ b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_empty.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_existingemptyvalue.xml b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_existingemptyvalue.xml
new file mode 100644
index 0000000000..a127fb1b3a
--- /dev/null
+++ b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_existingemptyvalue.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_existingline.xml b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_existingline.xml
new file mode 100644
index 0000000000..f9da5a268c
--- /dev/null
+++ b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_existingline.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_existingvalue.xml b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_existingvalue.xml
new file mode 100644
index 0000000000..748662e783
--- /dev/null
+++ b/test/Microsoft.AspNetCore.AzureAppServices.SiteExtension.Tests/config_existingvalue.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.Web.Xdt.Extensions.Tests/InsertOrAppendAttributeTests.cs b/test/Microsoft.Web.Xdt.Extensions.Tests/InsertOrAppendAttributeTests.cs
new file mode 100644
index 0000000000..546631f14f
--- /dev/null
+++ b/test/Microsoft.Web.Xdt.Extensions.Tests/InsertOrAppendAttributeTests.cs
@@ -0,0 +1,109 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO;
+using System.Xml;
+using Microsoft.Web.XmlTransform;
+using Xunit;
+
+namespace Microsoft.Web.Xdt.Extensions
+{
+ public class InsertOrAppendAttributeTests
+ {
+ [Fact]
+ public void InsertOrAppend_NoExesitingLine_InsertsLine()
+ {
+ var transform = new XmlTransformation(Path.GetFullPath("transform.xdt"));
+ var doc = new XmlDocument();
+ doc.Load("config_empty.xml");
+ Assert.True(transform.Apply(doc));
+
+ Assert.Equal(2, doc.ChildNodes.Count);
+ var configurationNode = doc["configuration"];
+
+ Assert.Equal(2, configurationNode.ChildNodes.Count);
+
+ var firstChild = configurationNode.FirstChild;
+ Assert.Equal("add", firstChild.Name);
+ Assert.Equal("KeyName1", firstChild.Attributes["name"].Value);
+ Assert.Equal("InsertValue1", firstChild.Attributes["value"].Value);
+
+ var secondChild = firstChild.NextSibling;
+ Assert.Equal("add", secondChild.Name);
+ Assert.Equal("KeyName2", secondChild.Attributes["name"].Value);
+ Assert.Equal("InsertValue2", secondChild.Attributes["value"].Value);
+ }
+
+ [Fact]
+ public void InsertOrAppend_LineExistsButNoValueField_FieldInserted()
+ {
+ var transform = new XmlTransformation(Path.GetFullPath("transform.xdt"));
+ var doc = new XmlDocument();
+ doc.Load("config_existingline.xml");
+ Assert.True(transform.Apply(doc));
+
+ Assert.Equal(2, doc.ChildNodes.Count);
+ var configurationNode = doc["configuration"];
+
+ Assert.Equal(2, configurationNode.ChildNodes.Count);
+
+ var firstChild = configurationNode.FirstChild;
+ Assert.Equal("add", firstChild.Name);
+ Assert.Equal("KeyName1", firstChild.Attributes["name"].Value);
+ Assert.Equal("InsertValue1", firstChild.Attributes["value"].Value);
+
+ var secondChild = firstChild.NextSibling;
+ Assert.Equal("add", secondChild.Name);
+ Assert.Equal("KeyName2", secondChild.Attributes["name"].Value);
+ Assert.Equal("InsertValue2", secondChild.Attributes["value"].Value);
+ }
+
+ [Fact]
+ public void InsertOrAppend_ExistingEmptyValue_InsertsValue()
+ {
+ var transform = new XmlTransformation(Path.GetFullPath("transform.xdt"));
+ var doc = new XmlDocument();
+ doc.Load("config_existingemptyvalue.xml");
+ Assert.True(transform.Apply(doc));
+
+ Assert.Equal(2, doc.ChildNodes.Count);
+ var configurationNode = doc["configuration"];
+
+ Assert.Equal(2, configurationNode.ChildNodes.Count);
+
+ var firstChild = configurationNode.FirstChild;
+ Assert.Equal("add", firstChild.Name);
+ Assert.Equal("KeyName1", firstChild.Attributes["name"].Value);
+ Assert.Equal("InsertValue1", firstChild.Attributes["value"].Value);
+
+ var secondChild = firstChild.NextSibling;
+ Assert.Equal("add", secondChild.Name);
+ Assert.Equal("KeyName2", secondChild.Attributes["name"].Value);
+ Assert.Equal("InsertValue2", secondChild.Attributes["value"].Value);
+ }
+
+ [Fact]
+ public void InsertOrAppend_ExistingValue_AppendsValue()
+ {
+ var transform = new XmlTransformation(Path.GetFullPath("transform.xdt"));
+ var doc = new XmlDocument();
+ doc.Load("config_existingvalue.xml");
+ Assert.True(transform.Apply(doc));
+
+ Assert.Equal(2, doc.ChildNodes.Count);
+ var configurationNode = doc["configuration"];
+
+ Assert.Equal(2, configurationNode.ChildNodes.Count);
+
+ var firstChild = configurationNode.FirstChild;
+ Assert.Equal("add", firstChild.Name);
+ Assert.Equal("KeyName1", firstChild.Attributes["name"].Value);
+ Assert.Equal("ExistingValue1;InsertValue1", firstChild.Attributes["value"].Value);
+
+ var secondChild = firstChild.NextSibling;
+ Assert.Equal("add", secondChild.Name);
+ Assert.Equal("KeyName2", secondChild.Attributes["name"].Value);
+ Assert.Equal("ExistingValue2;InsertValue2", secondChild.Attributes["value"].Value);
+ }
+ }
+}
diff --git a/test/Microsoft.Web.Xdt.Extensions.Tests/Microsoft.Web.Xdt.Extensions.Tests.csproj b/test/Microsoft.Web.Xdt.Extensions.Tests/Microsoft.Web.Xdt.Extensions.Tests.csproj
new file mode 100644
index 0000000000..026516e0ae
--- /dev/null
+++ b/test/Microsoft.Web.Xdt.Extensions.Tests/Microsoft.Web.Xdt.Extensions.Tests.csproj
@@ -0,0 +1,33 @@
+
+
+
+ net461
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
diff --git a/test/Microsoft.Web.Xdt.Extensions.Tests/config_empty.xml b/test/Microsoft.Web.Xdt.Extensions.Tests/config_empty.xml
new file mode 100644
index 0000000000..1156926c52
--- /dev/null
+++ b/test/Microsoft.Web.Xdt.Extensions.Tests/config_empty.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingemptyvalue.xml b/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingemptyvalue.xml
new file mode 100644
index 0000000000..66299d8c9e
--- /dev/null
+++ b/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingemptyvalue.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingline.xml b/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingline.xml
new file mode 100644
index 0000000000..6a474e9808
--- /dev/null
+++ b/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingline.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingvalue.xml b/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingvalue.xml
new file mode 100644
index 0000000000..f8a5cf3533
--- /dev/null
+++ b/test/Microsoft.Web.Xdt.Extensions.Tests/config_existingvalue.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.Web.Xdt.Extensions.Tests/transform.xdt b/test/Microsoft.Web.Xdt.Extensions.Tests/transform.xdt
new file mode 100644
index 0000000000..f62924ab31
--- /dev/null
+++ b/test/Microsoft.Web.Xdt.Extensions.Tests/transform.xdt
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
\ No newline at end of file