From d041249b2748ae6e01737d9491a79c223dc6574b Mon Sep 17 00:00:00 2001 From: NTaylorMullen Date: Thu, 25 Sep 2014 23:05:58 -0700 Subject: [PATCH] Add CreateTagHelper to RazorPage. - The CreateTagHelper method is responsible for creating and activating TagHelpers. - Added the support for requesting the ViewContext. - Added tests to validate the tag helper creation mechanism. #1104 --- src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs | 34 ++++ .../RazorPageCreateTagHelperTest.cs | 146 ++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageCreateTagHelperTest.cs diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs index a0f4e47b19..8bd4af2d9f 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.PageExecutionInstrumentation; +using Microsoft.AspNet.Razor.Runtime.TagHelpers; using Microsoft.Framework.DependencyInjection; namespace Microsoft.AspNet.Mvc.Razor @@ -24,6 +25,7 @@ namespace Microsoft.AspNet.Mvc.Razor private readonly Stack _writerScopes; private TextWriter _originalWriter; private IUrlHelper _urlHelper; + private ITypeActivator _typeActivator; private bool _renderedBody; public RazorPage() @@ -111,6 +113,38 @@ namespace Microsoft.AspNet.Mvc.Razor /// public abstract Task ExecuteAsync(); + private ITypeActivator TypeActivator + { + get + { + if(_typeActivator == null) + { + _typeActivator = ViewContext.HttpContext.RequestServices.GetService(); + } + + return _typeActivator; + } + } + + /// + /// Creates and activates a . + /// + /// A type. + /// The activated . + /// + /// If the implements the + /// method is called with . + /// + public TTagHelper CreateTagHelper() where TTagHelper : ITagHelper + { + var tagHelper = TypeActivator.CreateInstance(ViewContext.HttpContext.RequestServices); + var hasViewContext = tagHelper as ICanHasViewContext; + + hasViewContext?.Contextualize(ViewContext); + + return tagHelper; + } + /// /// Starts a new writing scope. /// diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageCreateTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageCreateTagHelperTest.cs new file mode 100644 index 0000000000..e067e62f97 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageCreateTagHelperTest.cs @@ -0,0 +1,146 @@ +// 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.IO; +using System.Threading.Tasks; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Mvc.ModelBinding; +using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Razor.Runtime.TagHelpers; +using Microsoft.AspNet.Routing; +using Microsoft.Framework.DependencyInjection; +using Moq; +using Xunit; + +namespace Microsoft.AspNet.Mvc.Razor +{ + public class RazorPageCreateTagHelperTest + { + [Fact] + public void CreateTagHelper_CreatesProvidedTagHelperType() + { + // Arrange + var instance = CreateTestRazorPage(); + + // Act + var tagHelper = instance.CreateTagHelper(); + + // Assert + Assert.NotNull(tagHelper); + } + + [Fact] + public void CreateTagHelper_ActivatesProvidedTagHelperType() + { + // Arrange + var instance = CreateTestRazorPage(); + + // Act + var tagHelper = instance.CreateTagHelper(); + + // Assert + Assert.NotNull(tagHelper.PassedInService); + } + + [Fact] + public void CreateTagHelper_ContextualizesProvidedTagHelperType() + { + // Arrange + var instance = CreateTestRazorPage(); + + // Act + var tagHelper = instance.CreateTagHelper(); + + // Assert + Assert.NotNull(tagHelper.ViewContext); + } + + [Fact] + public void CreateTagHelper_ContextualizesAndActivatesProvidedTagHelperType() + { + // Arrange + var instance = CreateTestRazorPage(); + + // Act + var tagHelper = instance.CreateTagHelper(); + + // Assert + Assert.NotNull(tagHelper.ViewContext); + Assert.NotNull(tagHelper.PassedInService); + } + + private static TestRazorPage CreateTestRazorPage() + { + var typeActivator = new TypeActivator(); + var activator = new RazorPageActivator(typeActivator); + var serviceProvider = new Mock(); + var myService = new MyService(); + serviceProvider.Setup(mock => mock.GetService(typeof(MyService))) + .Returns(myService); + serviceProvider.Setup(mock => mock.GetService(typeof(ITypeActivator))) + .Returns(typeActivator); + var httpContext = new Mock(); + httpContext.SetupGet(c => c.RequestServices) + .Returns(serviceProvider.Object); + var routeContext = new RouteContext(httpContext.Object); + var actionContext = new ActionContext(routeContext, new ActionDescriptor()); + var viewData = new ViewDataDictionary(Mock.Of()); + var viewContext = new ViewContext(actionContext, + Mock.Of(), + viewData, + TextWriter.Null); + + return new TestRazorPage + { + ViewContext = viewContext + }; + } + + private class TestRazorPage : RazorPage + { + public override Task ExecuteAsync() + { + throw new NotImplementedException(); + } + } + + private class NoServiceTagHelper : TagHelper + { + } + + private class ServiceTagHelper : TagHelper + { + public MyService PassedInService { get; set; } + + public ServiceTagHelper(MyService service) + { + PassedInService = service; + } + } + + private class ViewContextTagHelper : TagHelper, ICanHasViewContext + { + public ViewContext ViewContext { get; set; } + + public void Contextualize([NotNull]ViewContext viewContext) + { + ViewContext = viewContext; + } + } + + private class ViewContextServiceTagHelper : ViewContextTagHelper + { + public MyService PassedInService { get; set; } + + public ViewContextServiceTagHelper(MyService service) + { + PassedInService = service; + } + } + + private class MyService + { + } + } +} \ No newline at end of file