diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionResults/ViewResult.cs b/src/Microsoft.AspNet.Mvc.Core/ActionResults/ViewResult.cs
index 4b41874026..cca67cabf4 100644
--- a/src/Microsoft.AspNet.Mvc.Core/ActionResults/ViewResult.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/ActionResults/ViewResult.cs
@@ -2,7 +2,6 @@
// 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.IO;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Core;
diff --git a/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj b/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj
index 95345dd69e..46a286d607 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj
+++ b/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj
@@ -261,12 +261,14 @@
+
+
diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentActivator.cs b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentActivator.cs
new file mode 100644
index 0000000000..9a17d44f7e
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentActivator.cs
@@ -0,0 +1,89 @@
+// 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.Concurrent;
+using System.Collections.Generic;
+using System.Reflection;
+using Microsoft.AspNet.Mvc.Rendering;
+
+namespace Microsoft.AspNet.Mvc
+{
+ ///
+ /// Represents the that is registered by default.
+ ///
+ public class DefaultViewComponentActivator : IViewComponentActivator
+ {
+ private readonly Func[]> _getPropertiesToActivate;
+ private readonly IReadOnlyDictionary> _valueAccessorLookup;
+ private readonly ConcurrentDictionary[]> _injectActions;
+
+ ///
+ /// Initializes a new instance of class.
+ ///
+ public DefaultViewComponentActivator()
+ {
+ _valueAccessorLookup = CreateValueAccessorLookup();
+ _injectActions = new ConcurrentDictionary[]>();
+ _getPropertiesToActivate = type =>
+ PropertyActivator.GetPropertiesToActivate(
+ type, typeof(ActivateAttribute), CreateActivateInfo);
+ }
+
+ ///
+ public void Activate([NotNull] object viewComponent, [NotNull] ViewContext context)
+ {
+ var propertiesToActivate = _injectActions.GetOrAdd(viewComponent.GetType(),
+ _getPropertiesToActivate);
+
+ for (var i = 0; i < propertiesToActivate.Length; i++)
+ {
+ var activateInfo = propertiesToActivate[i];
+ activateInfo.Activate(viewComponent, context);
+ }
+ }
+
+ ///
+ /// Creates a lookup dictionary for the values to be activated.
+ ///
+ /// Returns a readonly dictionary of the values corresponding to the types.
+ protected virtual IReadOnlyDictionary> CreateValueAccessorLookup()
+ {
+ return new Dictionary>
+ {
+ { typeof(ViewContext), (context) => context },
+ {
+ typeof(ViewDataDictionary),
+ (context) =>
+ {
+ return new ViewDataDictionary(context.ViewData)
+ {
+ Model = null
+ };
+ }
+ }
+ };
+ }
+
+ private PropertyActivator CreateActivateInfo(PropertyInfo property)
+ {
+ Func valueAccessor;
+ if (!_valueAccessorLookup.TryGetValue(property.PropertyType, out valueAccessor))
+ {
+ valueAccessor = (viewContext) =>
+ {
+ var serviceProvider = viewContext.HttpContext.RequestServices;
+ var service = serviceProvider.GetService(property.PropertyType);
+ if (typeof(ICanHasViewContext).IsAssignableFrom(property.PropertyType))
+ {
+ ((ICanHasViewContext)service).Contextualize(viewContext);
+ }
+
+ return service;
+ };
+ }
+
+ return new PropertyActivator(property, valueAccessor);
+ }
+ }
+}
\ 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 e2f334d218..680e59fbf4 100644
--- a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentInvoker.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentInvoker.cs
@@ -15,15 +15,18 @@ namespace Microsoft.AspNet.Mvc
{
private readonly IServiceProvider _serviceProvider;
private readonly TypeInfo _componentType;
+ private readonly IViewComponentActivator _viewComponentActivator;
private readonly object[] _args;
public DefaultViewComponentInvoker(
[NotNull] IServiceProvider serviceProvider,
+ [NotNull] IViewComponentActivator viewComponentActivator,
[NotNull] TypeInfo componentType,
object[] args)
{
_serviceProvider = serviceProvider;
_componentType = componentType;
+ _viewComponentActivator = viewComponentActivator;
_args = args ?? new object[0];
}
@@ -73,16 +76,7 @@ namespace Microsoft.AspNet.Mvc
{
var activator = _serviceProvider.GetService();
var component = activator.CreateInstance(_serviceProvider, _componentType.AsType());
-
- Injector.InjectProperty(component, "ViewContext", context);
-
- // We're flowing the viewbag across, but the concept of model doesn't really apply here
- var viewData = new ViewDataDictionary(context.ViewData);
- viewData.Model = null;
- Injector.InjectProperty(component, "ViewData", viewData);
-
- Injector.CallInitializer(component, _serviceProvider);
-
+ _viewComponentActivator.Activate(component, context);
return component;
}
@@ -148,4 +142,4 @@ namespace Microsoft.AspNet.Mvc
typeof(IViewComponentResult).Name));
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentInvokerProvider.cs b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentInvokerProvider.cs
index 2f9b583554..9f85e7a51b 100644
--- a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentInvokerProvider.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/DefaultViewComponentInvokerProvider.cs
@@ -2,16 +2,20 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.AspNet.Mvc.Core;
namespace Microsoft.AspNet.Mvc
{
public class DefaultViewComponentInvokerProvider : IViewComponentInvokerProvider
{
private readonly IServiceProvider _serviceProvider;
+ private readonly IViewComponentActivator _viewComponentActivator;
- public DefaultViewComponentInvokerProvider(IServiceProvider serviceProvider)
+ public DefaultViewComponentInvokerProvider(IServiceProvider serviceProvider,
+ IViewComponentActivator viewComponentActivator)
{
_serviceProvider = serviceProvider;
+ _viewComponentActivator = viewComponentActivator;
}
public int Order
@@ -22,7 +26,8 @@ namespace Microsoft.AspNet.Mvc
public void Invoke([NotNull] ViewComponentInvokerProviderContext context, [NotNull] Action callNext)
{
context.Result =
- new DefaultViewComponentInvoker(_serviceProvider, context.ComponentType, context.Arguments);
+ new DefaultViewComponentInvoker(
+ _serviceProvider, _viewComponentActivator, context.ComponentType, context.Arguments);
callNext();
}
}
diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/IViewComponentActivator.cs b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/IViewComponentActivator.cs
new file mode 100644
index 0000000000..e103adeabb
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/IViewComponentActivator.cs
@@ -0,0 +1,18 @@
+// 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.
+
+namespace Microsoft.AspNet.Mvc
+{
+ ///
+ /// Provides methods to activate an instantiated ViewComponent
+ ///
+ public interface IViewComponentActivator
+ {
+ ///
+ /// When implemented in a type, activates an instantiated ViewComponent.
+ ///
+ /// The ViewComponent to activate.
+ /// The for the executing .
+ void Activate(object viewComponent, ViewContext 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 0b42aaf172..5ae35e94ab 100644
--- a/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponent.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/ViewComponents/ViewComponent.cs
@@ -10,7 +10,6 @@ namespace Microsoft.AspNet.Mvc
public abstract class ViewComponent
{
private dynamic _viewBag;
- private ICompositeViewEngine _viewEngine;
public HttpContext Context
{
@@ -30,20 +29,20 @@ namespace Microsoft.AspNet.Mvc
}
}
+ [Activate]
public ViewContext ViewContext { get; set; }
+ [Activate]
public ViewDataDictionary ViewData { get; set; }
+ [Activate]
+ public ICompositeViewEngine ViewEngine { get; set; }
+
public ContentViewComponentResult Content([NotNull] string content)
{
return new ContentViewComponentResult(content);
}
- public void Initialize(ICompositeViewEngine viewEngine)
- {
- _viewEngine = viewEngine;
- }
-
public JsonViewComponentResult Json([NotNull] object value)
{
return new JsonViewComponentResult(value);
@@ -72,7 +71,7 @@ namespace Microsoft.AspNet.Mvc
viewData.Model = model;
}
- return new ViewViewComponentResult(_viewEngine, viewName, viewData);
+ return new ViewViewComponentResult(ViewEngine, viewName, viewData);
}
}
}
diff --git a/src/Microsoft.AspNet.Mvc/MvcServices.cs b/src/Microsoft.AspNet.Mvc/MvcServices.cs
index d76c0a0940..de8a7580cc 100644
--- a/src/Microsoft.AspNet.Mvc/MvcServices.cs
+++ b/src/Microsoft.AspNet.Mvc/MvcServices.cs
@@ -79,6 +79,7 @@ namespace Microsoft.AspNet.Mvc
yield return describe.Scoped();
yield return describe.Transient();
+ yield return describe.Singleton();
yield return describe.Transient();
yield return describe.Transient,
DefaultViewComponentInvokerProvider>();
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/DefaultViewComponentActivatorTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/DefaultViewComponentActivatorTests.cs
new file mode 100644
index 0000000000..5669943186
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/DefaultViewComponentActivatorTests.cs
@@ -0,0 +1,143 @@
+// 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.
+
+#if NET45
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Mvc.ModelBinding;
+using Microsoft.AspNet.Mvc.Rendering;
+using Microsoft.AspNet.PipelineCore;
+using Microsoft.AspNet.Routing;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc
+{
+ public class DefaultViewComponentActivatorTests
+ {
+ [Fact]
+ public void DefaultViewComponentActivatorSetsAllPropertiesMarkedAsActivate()
+ {
+ // Arrange
+ var activator = new DefaultViewComponentActivator();
+ var instance = new TestViewComponent();
+ var helper = Mock.Of>();
+ var serviceProvider = new Mock();
+ serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper