From b393191cff77553fdd3635ff4d38695b40318058 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Wed, 20 May 2015 20:19:45 -0700 Subject: [PATCH] Part of #2151 - Remove [Activate] from ViewComponents This change removes [Activate] from ViewComponents. Accessing context should be done through [ViewComponentContext]. Accessing services should be done though constructor injection. --- .../DefaultViewComponentActivator.cs | 70 +++-------- .../DefaultViewComponentInvoker.cs | 2 +- .../ViewComponents/IViewComponentActivator.cs | 6 +- .../ViewComponents/ViewComponent.cs | 98 ++++++++++----- .../ViewComponents/ViewComponentContext.cs | 77 ++++++++---- .../ViewComponentContextAttribute.cs | 17 +++ .../ViewComponents/ViewViewComponentResult.cs | 4 +- .../ViewComponentTests.cs | 34 ++--- .../DefaultViewComponentActivatorTests.cs | 117 +----------------- .../ActivatorTests.cs | 36 +----- .../Components/CannotBeActivatedComponent.cs | 7 +- .../Components/NumberComponent.cs | 8 +- .../Components/ValueComponent.cs | 19 --- .../Components/ViewAndValueComponent.cs | 22 ---- .../Controllers/ViewController.cs | 10 -- .../Views/View/ConsumeValueComponent.cshtml | 1 - .../View/ConsumeViewAndValueComponent.cshtml | 1 - .../Components/ProductsViewComponent.cs | 12 +- .../RequestIdViewComponent.cs | 8 +- 19 files changed, 207 insertions(+), 342 deletions(-) create mode 100644 src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponentContextAttribute.cs delete mode 100644 test/WebSites/ActivatorWebSite/Components/ValueComponent.cs delete mode 100644 test/WebSites/ActivatorWebSite/Components/ViewAndValueComponent.cs delete mode 100644 test/WebSites/ActivatorWebSite/Views/View/ConsumeValueComponent.cshtml delete mode 100644 test/WebSites/ActivatorWebSite/Views/View/ConsumeViewAndValueComponent.cshtml diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentActivator.cs b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentActivator.cs index 2d5f5eb5d4..8920bfd695 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentActivator.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentActivator.cs @@ -3,40 +3,43 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Reflection; -using Microsoft.AspNet.Mvc.Rendering; -using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ViewComponents { /// - /// Represents the that is registered by default. + /// A default implementation of . /// + /// + /// The can provide the current instance of + /// to a public property of a view component marked + /// with . + /// public class DefaultViewComponentActivator : IViewComponentActivator { - private readonly Func[]> _getPropertiesToActivate; - private readonly IDictionary> _valueAccessorLookup; - private readonly ConcurrentDictionary[]> _injectActions; + private readonly Func[]> _getPropertiesToActivate; + private readonly ConcurrentDictionary[]> _injectActions; /// /// Initializes a new instance of class. /// public DefaultViewComponentActivator() { - _valueAccessorLookup = CreateValueAccessorLookup(); - _injectActions = new ConcurrentDictionary[]>(); + _injectActions = new ConcurrentDictionary[]>(); _getPropertiesToActivate = type => - PropertyActivator.GetPropertiesToActivate( - type, typeof(ActivateAttribute), CreateActivateInfo); + PropertyActivator.GetPropertiesToActivate( + type, + typeof(ViewComponentContextAttribute), + CreateActivateInfo); } /// - public virtual void Activate([NotNull] object viewComponent, [NotNull] ViewContext context) + public virtual void Activate([NotNull] object viewComponent, [NotNull] ViewComponentContext context) { - var propertiesToActivate = _injectActions.GetOrAdd(viewComponent.GetType(), - _getPropertiesToActivate); + var propertiesToActivate = _injectActions.GetOrAdd( + viewComponent.GetType(), + _getPropertiesToActivate); for (var i = 0; i < propertiesToActivate.Length; i++) { @@ -45,44 +48,9 @@ namespace Microsoft.AspNet.Mvc.ViewComponents } } - /// - /// Creates a lookup dictionary for the values to be activated. - /// - /// Returns a readonly dictionary of the values corresponding to the types. - protected virtual IDictionary> CreateValueAccessorLookup() + private PropertyActivator CreateActivateInfo(PropertyInfo property) { - return new Dictionary> - { - { typeof(ViewContext), (context) => context }, - { - typeof(ViewDataDictionary), - (context) => - { - return new ViewDataDictionary(context.ViewData); - } - } - }; - } - - private PropertyActivator CreateActivateInfo(PropertyInfo property) - { - Func valueAccessor; - if (!_valueAccessorLookup.TryGetValue(property.PropertyType, out valueAccessor)) - { - valueAccessor = (viewContext) => - { - var serviceProvider = viewContext.HttpContext.RequestServices; - var service = serviceProvider.GetRequiredService(property.PropertyType); - if (typeof(ICanHasViewContext).IsAssignableFrom(property.PropertyType)) - { - ((ICanHasViewContext)service).Contextualize(viewContext); - } - - return service; - }; - } - - return new PropertyActivator(property, valueAccessor); + return new PropertyActivator(property, context => context); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentInvoker.cs b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentInvoker.cs index 8c6d405499..5137346e8e 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentInvoker.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentInvoker.cs @@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents var component = _typeActivatorCache.CreateInstance( _serviceProvider, context.ViewComponentDescriptor.Type); - _viewComponentActivator.Activate(component, context.ViewContext); + _viewComponentActivator.Activate(component, context); return component; } diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/IViewComponentActivator.cs b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/IViewComponentActivator.cs index 1c537faae6..bff7a808a9 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/IViewComponentActivator.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/IViewComponentActivator.cs @@ -12,7 +12,9 @@ namespace Microsoft.AspNet.Mvc.ViewComponents /// When implemented in a type, activates an instantiated ViewComponent. /// /// The ViewComponent to activate. - /// The for the executing . - void Activate(object viewComponent, ViewContext context); + /// + /// The for the executing . + /// + void Activate(object viewComponent, ViewComponentContext context); } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponent.cs b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponent.cs index 21731b2819..58555799d3 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponent.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponent.cs @@ -6,7 +6,9 @@ using System.Security.Principal; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.ViewComponents; using Microsoft.AspNet.Routing; +using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Internal; using Newtonsoft.Json; @@ -18,9 +20,10 @@ namespace Microsoft.AspNet.Mvc [ViewComponent] public abstract class ViewComponent { + private IUrlHelper _url; private dynamic _viewBag; - private ViewContext _viewContext; - private ViewDataDictionary _viewData; + private ViewComponentContext _viewComponentContext; + private ICompositeViewEngine _viewEngine; /// /// Gets the . @@ -96,62 +99,93 @@ namespace Microsoft.AspNet.Mvc /// /// Gets or sets the . /// - [Activate] - public IUrlHelper Url { get; set; } - - /// - /// Gets or sets the . - /// - [Activate] - public ViewContext ViewContext + public IUrlHelper Url { get { - if (_viewContext == null) + if (_url == null) { - // This should run only for the ViewComponent unit test scenarios - _viewContext = new ViewContext(); + // May be null in unit-testing scenarios. + var services = ViewComponentContext.ViewContext?.HttpContext?.RequestServices; + _url = services?.GetRequiredService(); } - return _viewContext; + return _url; } [param: NotNull] set { - _viewContext = value; + _url = value; + } + } + + [ViewComponentContext] + public ViewComponentContext ViewComponentContext + { + get + { + // This should run only for the ViewComponent unit test scenarios. + if (_viewComponentContext == null) + { + _viewComponentContext = new ViewComponentContext(); + } + + return _viewComponentContext; + } + + [param: NotNull] + set + { + _viewComponentContext = value; } } /// - /// Gets or sets the . + /// Gets the . + /// + public ViewContext ViewContext + { + get + { + return ViewComponentContext.ViewContext; + } + } + + /// + /// Gets the . /// - [Activate] public ViewDataDictionary ViewData { get { - if (_viewData == null) - { - // This should run only for the ViewComponent unit test scenarios - _viewData = new ViewDataDictionary(ViewContext.ViewData); - } - - return _viewData; - } - - [param: NotNull] - set - { - _viewData = value; + return ViewComponentContext.ViewData; } } /// /// Gets or sets the . /// - [Activate] - public ICompositeViewEngine ViewEngine { get; set; } + public ICompositeViewEngine ViewEngine + { + get + { + if (_viewEngine == null) + { + // May be null in unit-testing scenarios. + var services = ViewComponentContext.ViewContext?.HttpContext?.RequestServices; + _viewEngine = services?.GetRequiredService(); + } + + return _viewEngine; + } + + [param: NotNull] + set + { + _viewEngine = value; + } + } /// /// Returns a result which will render HTML encoded text. diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponentContext.cs b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponentContext.cs index 29cf146309..c42e61018b 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponentContext.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponentContext.cs @@ -12,6 +12,19 @@ namespace Microsoft.AspNet.Mvc /// public class ViewComponentContext { + /// + /// Creates a new . + /// + /// + /// The default constructor is provided for unit test purposes only. + /// + public ViewComponentContext() + { + ViewComponentDescriptor = new ViewComponentDescriptor(); + Arguments = new object[0]; + ViewContext = new ViewContext(); + } + /// /// Creates a new . /// @@ -29,32 +42,54 @@ namespace Microsoft.AspNet.Mvc { ViewComponentDescriptor = viewComponentDescriptor; Arguments = arguments; - ViewContext = viewContext; - Writer = writer; + + // We want to create a defensive copy of the VDD here so that changes done in the VC + // aren't visible in the calling view. + ViewContext = new ViewContext( + viewContext, + viewContext.View, + new ViewDataDictionary(viewContext.ViewData), + writer); } /// - /// Gets the View Component arguments. - /// - public object[] Arguments { get; } - - /// - /// Gets the for the View Component being invoked. - /// - public ViewComponentDescriptor ViewComponentDescriptor { get; } - - /// - /// Gets the . - /// - public ViewContext ViewContext { get; } - - /// - /// Gets the for writing output. + /// Gets or sets the View Component arguments. /// /// - /// or a similar overload is used to invoke the - /// View Component, then will be different than . + /// The property setter is provided for unit test purposes only. /// - public TextWriter Writer { get; } + public object[] Arguments { get; set; } + + /// + /// Gets or sets the for the View Component being invoked. + /// + /// + /// The property setter is provided for unit test purposes only. + /// + public ViewComponentDescriptor ViewComponentDescriptor { get; set; } + + /// + /// Gets or sets the . + /// + /// + /// The property setter is provided for unit test purposes only. + /// + public ViewContext ViewContext { get; set; } + + /// + /// Gets the . + /// + /// + /// This is an alias for ViewContext.ViewData. + /// + public ViewDataDictionary ViewData => ViewContext.ViewData; + + /// + /// Gets the for output. + /// + /// + /// This is an alias for ViewContext.Writer. + /// + public TextWriter Writer => ViewContext.Writer; } } diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponentContextAttribute.cs b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponentContextAttribute.cs new file mode 100644 index 0000000000..e81f955cc2 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponentContextAttribute.cs @@ -0,0 +1,17 @@ +// 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; + +namespace Microsoft.AspNet.Mvc.ViewComponents +{ + /// + /// Specifies that a controller property should be set with the current + /// when creating the view component. The property must have a public + /// set method. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class ViewComponentContextAttribute : Attribute + { + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewViewComponentResult.cs b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewViewComponentResult.cs index 7263eb0cda..c7186b0bd7 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewViewComponentResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewViewComponentResult.cs @@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Mvc public async Task ExecuteAsync([NotNull] ViewComponentContext context) { var viewEngine = ViewEngine ?? ResolveViewEngine(context); - var viewData = ViewData ?? context.ViewContext.ViewData; + var viewData = ViewData ?? context.ViewData; string qualifiedViewName; if (ViewName != null && ViewName.Length > 0 && ViewName[0] == '/') @@ -95,7 +95,7 @@ namespace Microsoft.AspNet.Mvc var childViewContext = new ViewContext( context.ViewContext, view, - ViewData ?? context.ViewContext.ViewData, + ViewData ?? context.ViewData, context.Writer); using (view as IDisposable) diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ViewComponentTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ViewComponentTests.cs index 1cc7627b18..55b8a664e8 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ViewComponentTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ViewComponentTests.cs @@ -14,10 +14,7 @@ namespace Microsoft.AspNet.Mvc public void ViewComponent_ViewBag_UsesViewData() { // Arrange - var viewComponent = new TestViewComponent() - { - ViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()), - }; + var viewComponent = new TestViewComponent(); // Act viewComponent.ViewBag.A = "Alice"; @@ -33,10 +30,7 @@ namespace Microsoft.AspNet.Mvc public void ViewComponent_ViewData_StoresDataForViewBag() { // Arrange - var viewComponent = new TestViewComponent() - { - ViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()), - }; + var viewComponent = new TestViewComponent(); // Act viewComponent.ViewData["A"] = "Alice"; @@ -84,10 +78,7 @@ namespace Microsoft.AspNet.Mvc public void ViewComponent_View_WithEmptyParameter_SetsResultViewWithDefaultViewName() { // Arrange - var viewComponent = new TestViewComponent() - { - ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), - }; + var viewComponent = new TestViewComponent(); // Act var actualResult = viewComponent.View(); @@ -104,10 +95,7 @@ namespace Microsoft.AspNet.Mvc public void ViewComponent_View_WithViewNameParameter_SetsResultViewWithCustomViewName() { // Arrange - var viewComponent = new TestViewComponent() - { - ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), - }; + var viewComponent = new TestViewComponent(); // Act var actualResult = viewComponent.View("CustomViewName"); @@ -125,10 +113,8 @@ namespace Microsoft.AspNet.Mvc public void ViewComponent_View_WithModelParameter_SetsResultViewWithDefaultViewNameAndModel() { // Arrange - var viewComponent = new TestViewComponent() - { - ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), - }; + var viewComponent = new TestViewComponent(); + var model = new object(); // Act @@ -147,10 +133,8 @@ namespace Microsoft.AspNet.Mvc public void ViewComponent_View_WithViewNameAndModelParameters_SetsResultViewWithCustomViewNameAndModel() { // Arrange - var viewComponent = new TestViewComponent() - { - ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), - }; + var viewComponent = new TestViewComponent(); + var model = new object(); // Act @@ -180,7 +164,7 @@ namespace Microsoft.AspNet.Mvc Assert.Empty(viewComponent.ViewContext.ViewData); Assert.NotNull(viewComponent.ViewData); Assert.Empty(viewComponent.ViewData); - Assert.NotSame(viewComponent.ViewData, viewComponent.ViewContext.ViewData); + Assert.Same(viewComponent.ViewData, viewComponent.ViewContext.ViewData); } private class TestViewComponent : ViewComponent diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ViewComponents/DefaultViewComponentActivatorTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ViewComponents/DefaultViewComponentActivatorTests.cs index 7236ed883d..6649c61a39 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ViewComponents/DefaultViewComponentActivatorTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ViewComponents/DefaultViewComponentActivatorTests.cs @@ -17,135 +17,28 @@ namespace Microsoft.AspNet.Mvc.ViewComponents public class DefaultViewComponentActivatorTests { [Fact] - public void DefaultViewComponentActivatorSetsAllPropertiesMarkedAsActivate() + public void DefaultViewComponentActivator_ActivatesViewComponentContext() { // Arrange var activator = new DefaultViewComponentActivator(); + + var context = new ViewComponentContext(); var instance = new TestViewComponent(); - var helper = Mock.Of>(); - var serviceProvider = new Mock(); - serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper))).Returns(helper); - serviceProvider.Setup(p => p.GetService(typeof(ICompositeViewEngine))).Returns(Mock.Of()); - serviceProvider.Setup(p => p.GetService(typeof(IUrlHelper))).Returns(Mock.Of()); - var viewContext = GetViewContext(serviceProvider.Object); // Act - activator.Activate(instance, viewContext); + activator.Activate(instance, context); // Assert - Assert.Same(helper, instance.Html); - Assert.Same(viewContext, instance.ViewContext); - Assert.IsType(instance.ViewData); - } - - [Fact] - public void DefaultViewComponentActivatorSetsModelAsNull() - { - // Arrange - var activator = new DefaultViewComponentActivator(); - var helper = Mock.Of>(); - var serviceProvider = new Mock(); - serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper))).Returns(helper); - serviceProvider.Setup(p => p.GetService(typeof(ICompositeViewEngine))).Returns(Mock.Of()); - serviceProvider.Setup(p => p.GetService(typeof(IUrlHelper))).Returns(Mock.Of()); - var viewContext = GetViewContext(serviceProvider.Object); - - // Act - activator.Activate(new TestViewComponent(), viewContext); - - // Assert - Assert.Null(viewContext.ViewData.Model); - } - - [Fact] - public void DefaultViewComponentActivatorActivatesNonBuiltInTypes() - { - // Arrange - var activator = new DefaultViewComponentActivator(); - var helper = Mock.Of>(); - var myTestService = new MyService(); - var serviceProvider = new Mock(); - serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper))).Returns(helper); - serviceProvider.Setup(p => p.GetService(typeof(MyService))).Returns(myTestService); - serviceProvider.Setup(p => p.GetService(typeof(ICompositeViewEngine))).Returns(Mock.Of()); - serviceProvider.Setup(p => p.GetService(typeof(IUrlHelper))).Returns(Mock.Of()); - var viewContext = GetViewContext(serviceProvider.Object); - var instance = new TestViewComponentWithCustomDataType(); - - // Act - activator.Activate(instance, viewContext); - - // Assert - Assert.Equal(myTestService, instance.TestMyServiceObject); - - } - - [Fact] - public void DefaulViewComponentActivatorContextualizesService() - { - // Arrange - var activator = new DefaultViewComponentActivator(); - var instance = new TestClassUsingMyService(); - var myTestService = new MyService(); - var serviceProvider = new Mock(); - serviceProvider.Setup(p => p.GetService(typeof(MyService))).Returns(myTestService); - var viewContext = GetViewContext(serviceProvider.Object); - - // Act - activator.Activate(instance, viewContext); - - // Assert - Assert.Same(myTestService, instance.MyTestService); - Assert.Same(viewContext, instance.MyTestService.ViewContext); - } - - private ViewContext GetViewContext(IServiceProvider serviceProvider) - { - var httpContext = new Mock(); - httpContext.SetupGet(c => c.RequestServices) - .Returns(serviceProvider); - - var actionContext = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor()); - return new ViewContext(actionContext, - Mock.Of(), - new ViewDataDictionary(new EmptyModelMetadataProvider()), - null, - TextWriter.Null, - new HtmlHelperOptions()); + Assert.Same(context, instance.ViewComponentContext); } private class TestViewComponent : ViewComponent { - [Activate] - public IHtmlHelper Html { get; private set; } - public Task ExecuteAsync() { throw new NotImplementedException(); } } - - private class TestViewComponentWithCustomDataType : TestViewComponent - { - [Activate] - public MyService TestMyServiceObject { get; set; } - } - - private class MyService : ICanHasViewContext - { - public ViewContext ViewContext { get; private set; } - - public void Contextualize(ViewContext viewContext) - { - ViewContext = viewContext; - } - } - - private class TestClassUsingMyService - { - [Activate] - public MyService MyTestService { get; set; } - } } } #endif diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ActivatorTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ActivatorTests.cs index d5e2f9bde5..a805193603 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ActivatorTests.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ActivatorTests.cs @@ -113,7 +113,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests } [Fact] - public async Task ViewComponentActivator_ActivatesProperties() + public async Task ViewComponentActivator_Activates() { // Arrange var server = TestHelper.CreateServer(_app, SiteName, _configureServices); @@ -127,35 +127,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests Assert.Equal(expected, body.Trim()); } - [Fact] - public async Task ViewComponentActivator_ActivatesPropertiesAndContextualizesThem() - { - // Arrange - var server = TestHelper.CreateServer(_app, SiteName, _configureServices); - var client = server.CreateClient(); - var expected = "test-value"; - - // Act - var body = await client.GetStringAsync("http://localhost/View/ConsumeValueComponent?test=test-value"); - - // Assert - Assert.Equal(expected, body.Trim()); - } - - [Fact] - public async Task ViewComponentActivator_ActivatesPropertiesAndContextualizesThem_WhenMultiplePropertiesArePresent() - { - // Arrange - var server = TestHelper.CreateServer(_app, SiteName, _configureServices); - var client = server.CreateClient(); - var expected = "Random Number:4 test-value"; - - // Act - var body = await client.GetStringAsync("http://localhost/View/ConsumeViewAndValueComponent?test=test-value"); - - // Assert - Assert.Equal(expected, body.Trim()); - } [Fact] public async Task ViewComponentThatCannotBeActivated_ThrowsWhenAttemptedToBeInvoked() @@ -163,8 +134,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests // Arrange var server = TestHelper.CreateServer(_app, SiteName, _configureServices); var client = server.CreateClient(); - var expectedMessage = "No service for type 'ActivatorWebSite.CannotBeActivatedComponent+FakeType' " + - "has been registered."; + var expectedMessage = + "Unable to resolve service for type 'ActivatorWebSite.CannotBeActivatedComponent+FakeType' " + + "while attempting to activate 'ActivatorWebSite.CannotBeActivatedComponent'."; // Act & Assert var response = await client.GetAsync("http://localhost/View/ConsumeCannotBeActivatedComponent"); diff --git a/test/WebSites/ActivatorWebSite/Components/CannotBeActivatedComponent.cs b/test/WebSites/ActivatorWebSite/Components/CannotBeActivatedComponent.cs index bff2dd05e5..16854989a5 100644 --- a/test/WebSites/ActivatorWebSite/Components/CannotBeActivatedComponent.cs +++ b/test/WebSites/ActivatorWebSite/Components/CannotBeActivatedComponent.cs @@ -8,15 +8,16 @@ namespace ActivatorWebSite [ViewComponent(Name = "CannotBeActivated")] public class CannotBeActivatedComponent : ViewComponent { - [Activate] - private FakeType Service { get; set; } + public CannotBeActivatedComponent(FakeType fakeType) + { + } public IViewComponentResult Invoke() { return Content("Test"); } - private sealed class FakeType + public sealed class FakeType { } } diff --git a/test/WebSites/ActivatorWebSite/Components/NumberComponent.cs b/test/WebSites/ActivatorWebSite/Components/NumberComponent.cs index 0f9c74fd5b..7be9b414c1 100644 --- a/test/WebSites/ActivatorWebSite/Components/NumberComponent.cs +++ b/test/WebSites/ActivatorWebSite/Components/NumberComponent.cs @@ -8,8 +8,12 @@ namespace ActivatorWebSite [ViewComponent(Name = "Number")] public class NumberComponent : ViewComponent { - [Activate] - public MyService MyTestService { get; set; } + public NumberComponent(MyService myTestService) + { + MyTestService = myTestService; + } + + private MyService MyTestService { get; } public IViewComponentResult Invoke(string content) { diff --git a/test/WebSites/ActivatorWebSite/Components/ValueComponent.cs b/test/WebSites/ActivatorWebSite/Components/ValueComponent.cs deleted file mode 100644 index f2c9142a39..0000000000 --- a/test/WebSites/ActivatorWebSite/Components/ValueComponent.cs +++ /dev/null @@ -1,19 +0,0 @@ -// 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 Microsoft.AspNet.Mvc; - -namespace ActivatorWebSite -{ - [ViewComponent(Name = "Value")] - public class ValueComponent : ViewComponent - { - [Activate] - public ViewService MyViewService { get; set; } - - public IViewComponentResult Invoke() - { - return Content(MyViewService.GetValue()); - } - } -} \ No newline at end of file diff --git a/test/WebSites/ActivatorWebSite/Components/ViewAndValueComponent.cs b/test/WebSites/ActivatorWebSite/Components/ViewAndValueComponent.cs deleted file mode 100644 index 8f2462d67f..0000000000 --- a/test/WebSites/ActivatorWebSite/Components/ViewAndValueComponent.cs +++ /dev/null @@ -1,22 +0,0 @@ -// 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 Microsoft.AspNet.Mvc; - -namespace ActivatorWebSite -{ - [ViewComponent(Name = "ViewAndValue")] - public class ViewAndValueComponent : ViewComponent - { - [Activate] - public MyService MySampleService { get; set; } - - [Activate] - public ViewService MyViewService { get; set; } - - public IViewComponentResult Invoke(string content) - { - return Content(content + ":" + MySampleService.Random + " " + MyViewService.GetValue()); - } - } -} \ No newline at end of file diff --git a/test/WebSites/ActivatorWebSite/Controllers/ViewController.cs b/test/WebSites/ActivatorWebSite/Controllers/ViewController.cs index 0014f3a219..03ff25f470 100644 --- a/test/WebSites/ActivatorWebSite/Controllers/ViewController.cs +++ b/test/WebSites/ActivatorWebSite/Controllers/ViewController.cs @@ -31,16 +31,6 @@ namespace ActivatorWebSite return View(); } - public ViewResult ConsumeValueComponent() - { - return View(); - } - - public ViewResult ConsumeViewAndValueComponent() - { - return View(); - } - public ViewResult ConsumeCannotBeActivatedComponent() { return View(); diff --git a/test/WebSites/ActivatorWebSite/Views/View/ConsumeValueComponent.cshtml b/test/WebSites/ActivatorWebSite/Views/View/ConsumeValueComponent.cshtml deleted file mode 100644 index 7faf0f4679..0000000000 --- a/test/WebSites/ActivatorWebSite/Views/View/ConsumeValueComponent.cshtml +++ /dev/null @@ -1 +0,0 @@ -@Component.Invoke("Value") \ No newline at end of file diff --git a/test/WebSites/ActivatorWebSite/Views/View/ConsumeViewAndValueComponent.cshtml b/test/WebSites/ActivatorWebSite/Views/View/ConsumeViewAndValueComponent.cshtml deleted file mode 100644 index a3edd15e7f..0000000000 --- a/test/WebSites/ActivatorWebSite/Views/View/ConsumeViewAndValueComponent.cshtml +++ /dev/null @@ -1 +0,0 @@ -@Component.Invoke("ViewAndValue", "Random Number") \ No newline at end of file diff --git a/test/WebSites/MvcTagHelpersWebSite/Components/ProductsViewComponent.cs b/test/WebSites/MvcTagHelpersWebSite/Components/ProductsViewComponent.cs index c5d44bdc77..04b3c6d10b 100644 --- a/test/WebSites/MvcTagHelpersWebSite/Components/ProductsViewComponent.cs +++ b/test/WebSites/MvcTagHelpersWebSite/Components/ProductsViewComponent.cs @@ -9,11 +9,15 @@ namespace MvcTagHelpersWebSite.Components { public class ProductsViewComponent : ViewComponent { - [Activate] - public ProductsService ProductsService { get; set; } + public ProductsViewComponent(ProductsService productsService, IMemoryCache cache) + { + ProductsService = productsService; + Cache = cache; + } - [Activate] - public IMemoryCache Cache { get; set; } + private ProductsService ProductsService { get; } + + public IMemoryCache Cache { get; } public IViewComponentResult Invoke(string category) { diff --git a/test/WebSites/RequestServicesWebSite/RequestIdViewComponent.cs b/test/WebSites/RequestServicesWebSite/RequestIdViewComponent.cs index 9bd85e8bfc..7beab6dbf5 100644 --- a/test/WebSites/RequestServicesWebSite/RequestIdViewComponent.cs +++ b/test/WebSites/RequestServicesWebSite/RequestIdViewComponent.cs @@ -7,8 +7,12 @@ namespace RequestServicesWebSite { public class RequestIdViewComponent : ViewComponent { - [Activate] - public RequestIdService RequestIdService { get; set; } + public RequestIdViewComponent(RequestIdService requestIdService) + { + RequestIdService = requestIdService; + } + + private RequestIdService RequestIdService { get; } public IViewComponentResult Invoke() {