diff --git a/Mvc.NoFun.sln b/Mvc.NoFun.sln index 20b8af7e44..91891e20d0 100644 --- a/Mvc.NoFun.sln +++ b/Mvc.NoFun.sln @@ -44,6 +44,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.WebApi EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TestConfiguration", "test\WebSites\Microsoft.AspNet.Mvc.TestConfiguration\Microsoft.AspNet.Mvc.TestConfiguration.kproj", "{680D75ED-601F-4D86-B01B-1072D0C31B8C}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TagHelpers", "src\Microsoft.AspNet.Mvc.TagHelpers\Microsoft.AspNet.Mvc.TagHelpers.kproj", "{B2347320-308E-4D2B-AEC8-005DFA68B0C9}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TagHelperSample.Web", "samples\TagHelperSample.Web\TagHelperSample.Web.kproj", "{2223120F-D675-40DA-8CD8-11DC14A0B2C7}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TagHelpers.Test", "test\Microsoft.AspNet.Mvc.TagHelpers.Test\Microsoft.AspNet.Mvc.TagHelpers.Test.kproj", "{860119ED-3DB1-424D-8D0A-30132A8A7D96}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -206,6 +212,42 @@ Global {680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Mixed Platforms.Build.0 = Release|Any CPU {680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|x86.ActiveCfg = Release|Any CPU {680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|x86.Build.0 = Release|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Debug|x86.ActiveCfg = Debug|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Debug|x86.Build.0 = Debug|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|Any CPU.Build.0 = Release|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|x86.ActiveCfg = Release|Any CPU + {B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|x86.Build.0 = Release|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|x86.ActiveCfg = Debug|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|x86.Build.0 = Debug|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|Any CPU.Build.0 = Release|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|x86.ActiveCfg = Release|Any CPU + {2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Release|x86.Build.0 = Release|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|x86.ActiveCfg = Debug|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|x86.Build.0 = Debug|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Any CPU.Build.0 = Release|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|x86.ActiveCfg = Release|Any CPU + {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -226,5 +268,8 @@ Global {23D30B8C-04B1-4577-A604-ED27EA1E4A0E} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} {5DE8E4D9-AACD-4B5F-819F-F091383FB996} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} {680D75ED-601F-4D86-B01B-1072D0C31B8C} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} + {B2347320-308E-4D2B-AEC8-005DFA68B0C9} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {2223120F-D675-40DA-8CD8-11DC14A0B2C7} = {DAAE4C74-D06F-4874-A166-33305D2643CE} + {860119ED-3DB1-424D-8D0A-30132A8A7D96} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} EndGlobalSection EndGlobal diff --git a/samples/TagHelperSample.Web/Views/Home/Index.cshtml b/samples/TagHelperSample.Web/Views/Home/Index.cshtml index c4ea763579..17b3f00d1b 100644 --- a/samples/TagHelperSample.Web/Views/Home/Index.cshtml +++ b/samples/TagHelperSample.Web/Views/Home/Index.cshtml @@ -2,6 +2,10 @@ @using TagHelperSample.Web.Models @model IList + + Hello, you're in Development + +

Index

@if (Model != null && Model.Count() != 0) { diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/EnvironmentTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/EnvironmentTagHelper.cs new file mode 100644 index 0000000000..3e3473115f --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/EnvironmentTagHelper.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Open Technologies, Inc. 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.Linq; +using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.Razor.Runtime.TagHelpers; + +namespace Microsoft.AspNet.Mvc.TagHelpers +{ + /// + /// implementation targeting <environment> elements that conditionally renders + /// content based on the current value of . + /// + public class EnvironmentTagHelper : TagHelper + { + private static readonly char[] NameSeparator = new[] { ',' }; + + /// + /// A comma separated list of environment names in which the content should be rendered. + /// + /// + /// The specified environment names are compared case insensitively to the current value of + /// . + /// + public string Names { get; set; } + + // Protected to ensure subclasses are correctly activated. Internal for ease of use when testing. + [Activate] + protected internal IHostingEnvironment HostingEnvironment { get; set; } + + /// + public override void Process(TagHelperContext context, TagHelperOutput output) + { + // Always strip the outer tag name as we never want to render + output.TagName = null; + + if (string.IsNullOrWhiteSpace(Names)) + { + // No names specified, do nothing + return; + } + + var environments = Names.Split(NameSeparator, StringSplitOptions.RemoveEmptyEntries) + .Where(name => !string.IsNullOrWhiteSpace(name)); + + if (!environments.Any()) + { + // Names contains only commas or empty entries, do nothing + return; + } + + var currentEnvironmentName = HostingEnvironment.EnvironmentName?.Trim(); + + if (string.IsNullOrWhiteSpace(currentEnvironmentName)) + { + // No current environment name, do nothing + return; + } + + if (environments.Any(name => + string.Equals(name.Trim(), currentEnvironmentName, StringComparison.OrdinalIgnoreCase))) + { + // Matching environment name found, do nothing + return; + } + + // No matching environment name found, suppress all output + output.SuppressOutput(); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/Compiler/Resources/MvcTagHelpersWebSite.MvcTagHelper_Home.Environment.html b/test/Microsoft.AspNet.Mvc.FunctionalTests/Compiler/Resources/MvcTagHelpersWebSite.MvcTagHelper_Home.Environment.html new file mode 100644 index 0000000000..26a24d1408 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/Compiler/Resources/MvcTagHelpersWebSite.MvcTagHelper_Home.Environment.html @@ -0,0 +1,44 @@ + + + + + + Environment + + + +

Environment Tag Helper Test

+ +
    + +
  • This will show
  • + + +
  • This will show
  • + + +
  • This will show
  • + + +
  • This will show
  • + + +
  • This will show
  • + + +
  • This will show
  • + + +
  • This will show
  • + + +
  • This will show
  • + + +
  • This will show
  • + + + +
+ + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/MvcTagHelpersTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/MvcTagHelpersTests.cs index fc975bae58..6a3bcac8d2 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/MvcTagHelpersTests.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/MvcTagHelpersTests.cs @@ -33,7 +33,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests // Testing SelectTagHelper with Html.BeginForm [InlineData("CreateWarehouse", null)] // Testing the HTML helpers with FormTagHelper - [InlineData("EditWarehouse", null)] + [InlineData("EditWarehouse", null)] + // Testing the EnvironmentTagHelper + [InlineData("Environment", null)] public async Task MvcTagHelpers_GeneratesExpectedResults(string action, string antiForgeryPath) { // Arrange diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/EnvironmentTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/EnvironmentTagHelperTest.cs new file mode 100644 index 0000000000..455928c5c7 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/EnvironmentTagHelperTest.cs @@ -0,0 +1,147 @@ +// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.Razor.Runtime.TagHelpers; +using Moq; +using Xunit; + +namespace Microsoft.AspNet.Mvc.TagHelpers.Test +{ + public class EnvironmentTagHelperTest + { + [Theory] + [InlineData("Development", "Development")] + [InlineData("development", "Development")] + [InlineData("DEVELOPMENT", "Development")] + [InlineData(" development", "Development")] + [InlineData("development ", "Development")] + [InlineData(" development ", "Development")] + [InlineData("Development,Production", "Development")] + [InlineData("Production,Development", "Development")] + [InlineData("Development , Production", "Development")] + [InlineData(" Development,Production ", "Development")] + [InlineData("Development , Production", "Development")] + [InlineData("Development\t,Production", "Development")] + [InlineData("Development,\tProduction", "Development")] + [InlineData(" Development,Production ", "Development")] + [InlineData("Development,Staging,Production", "Development")] + [InlineData("Staging,Development,Production", "Development")] + [InlineData("Staging,Production,Development", "Development")] + [InlineData("Test", "Test")] + [InlineData("Test,Staging", "Test")] + public void ShowsContentWhenCurrentEnvironmentIsSpecified(string namesAttribute, string environmentName) + { + ShouldShowContent(namesAttribute, environmentName); + } + + [Theory] + [InlineData("", "Development")] + [InlineData(null, "Development")] + [InlineData(" ", "Development")] + [InlineData(", ", "Development")] + [InlineData(" , ", "Development")] + [InlineData("\t,\t", "Development")] + [InlineData(",", "Development")] + [InlineData(",,", "Development")] + [InlineData(",,,", "Development")] + [InlineData(",,, ", "Development")] + public void ShowsContentWhenNoEnvironmentIsSpecified(string namesAttribute, string environmentName) + { + ShouldShowContent(namesAttribute, environmentName); + } + + [Theory] + [InlineData("Development", null)] + [InlineData("Development", "")] + [InlineData("Development", " ")] + [InlineData("Development", " ")] + [InlineData("Development", "\t")] + [InlineData("Test", null)] + public void ShowsContentWhenCurrentEnvironmentIsNotSet(string namesAttribute, string environmentName) + { + ShouldShowContent(namesAttribute, environmentName); + } + + [Theory] + [InlineData("NotDevelopment", "Development")] + [InlineData("NOTDEVELOPMENT", "Development")] + [InlineData("NotDevelopment,AlsoNotDevelopment", "Development")] + [InlineData("Doesn'tMatchAtAll", "Development")] + [InlineData("Development and a space", "Development")] + [InlineData("Development and a space,SomethingElse", "Development")] + public void DoesNotShowContentWhenCurrentEnvironmentIsNotSpecified( + string namesAttribute, + string environmentName) + { + // Arrange + var content = "content"; + var context = MakeTagHelperContext( + attributes: new Dictionary { { "names", namesAttribute } }, + content: content); + var output = MakeTagHelperOutput("environment"); + var hostingEnvironment = new Mock(); + hostingEnvironment.SetupProperty(h => h.EnvironmentName); + hostingEnvironment.Object.EnvironmentName = environmentName; + + // Act + var helper = new EnvironmentTagHelper + { + HostingEnvironment = hostingEnvironment.Object, + Names = namesAttribute + }; + helper.Process(context, output); + + // Assert + Assert.Null(output.TagName); + Assert.Null(output.PreContent); + Assert.Null(output.Content); + Assert.Null(output.PostContent); + Assert.True(output.ContentSet); + } + + private void ShouldShowContent(string namesAttribute, string environmentName) + { + // Arrange + var content = "content"; + var context = MakeTagHelperContext( + attributes: new Dictionary { { "names", namesAttribute } }, + content: content); + var output = MakeTagHelperOutput("environment"); + var hostingEnvironment = new Mock(); + hostingEnvironment.SetupProperty(h => h.EnvironmentName); + hostingEnvironment.Object.EnvironmentName = environmentName; + + // Act + var helper = new EnvironmentTagHelper + { + HostingEnvironment = hostingEnvironment.Object, + Names = namesAttribute + }; + helper.Process(context, output); + + // Assert + Assert.Null(output.TagName); + Assert.False(output.ContentSet); + } + + private TagHelperContext MakeTagHelperContext( + IDictionary attributes = null, + string content = null) + { + attributes = attributes ?? new Dictionary(); + + return new TagHelperContext(attributes, Guid.NewGuid().ToString("N"), () => Task.FromResult(content)); + } + + private TagHelperOutput MakeTagHelperOutput(string tagName, IDictionary attributes = null) + { + attributes = attributes ?? new Dictionary(); + + return new TagHelperOutput(tagName, attributes); + } + } +} \ No newline at end of file diff --git a/test/WebSites/MvcTagHelpersWebSite/Controllers/MvcTagHelper_HomeController.cs b/test/WebSites/MvcTagHelpersWebSite/Controllers/MvcTagHelper_HomeController.cs index e40e39a30f..a3f52e1098 100644 --- a/test/WebSites/MvcTagHelpersWebSite/Controllers/MvcTagHelper_HomeController.cs +++ b/test/WebSites/MvcTagHelpersWebSite/Controllers/MvcTagHelper_HomeController.cs @@ -136,5 +136,10 @@ namespace MvcTagHelpersWebSite.Controllers }; return View(warehouse); } + + public IActionResult Environment() + { + return View(); + } } } diff --git a/test/WebSites/MvcTagHelpersWebSite/Views/MvcTagHelper_Home/Environment.cshtml b/test/WebSites/MvcTagHelpersWebSite/Views/MvcTagHelper_Home/Environment.cshtml new file mode 100644 index 0000000000..06dd4e84bc --- /dev/null +++ b/test/WebSites/MvcTagHelpersWebSite/Views/MvcTagHelper_Home/Environment.cshtml @@ -0,0 +1,49 @@ +@addtaghelper "Microsoft.AspNet.Mvc.TagHelpers" + + + + + + Environment + + + +

Environment Tag Helper Test

+ +
    + +
  • This will show
  • +
    + +
  • This will show
  • +
    + +
  • This will show
  • +
    + +
  • This will show
  • +
    + +
  • This will show
  • +
    + +
  • This will show
  • +
    + +
  • This will show
  • +
    + +
  • This will show
  • +
    + +
  • This will show
  • +
    + +
  • FAIL: This should NOT show
  • +
    + +
  • FAIL: This should NOT show
  • +
    +
+ + \ No newline at end of file