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.
This commit is contained in:
parent
92dbd8923b
commit
b393191cff
|
|
@ -3,40 +3,43 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
|
||||||
using Microsoft.Framework.DependencyInjection;
|
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the <see cref="IViewComponentActivator"/> that is registered by default.
|
/// A default implementation of <see cref="IViewComponentActivator"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The <see cref="DefaultViewComponentActivator"/> can provide the current instance of
|
||||||
|
/// <see cref="ViewComponentContext"/> to a public property of a view component marked
|
||||||
|
/// with <see cref="ViewComponentContextAttribute"/>.
|
||||||
|
/// </remarks>
|
||||||
public class DefaultViewComponentActivator : IViewComponentActivator
|
public class DefaultViewComponentActivator : IViewComponentActivator
|
||||||
{
|
{
|
||||||
private readonly Func<Type, PropertyActivator<ViewContext>[]> _getPropertiesToActivate;
|
private readonly Func<Type, PropertyActivator<ViewComponentContext>[]> _getPropertiesToActivate;
|
||||||
private readonly IDictionary<Type, Func<ViewContext, object>> _valueAccessorLookup;
|
private readonly ConcurrentDictionary<Type, PropertyActivator<ViewComponentContext>[]> _injectActions;
|
||||||
private readonly ConcurrentDictionary<Type, PropertyActivator<ViewContext>[]> _injectActions;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="DefaultViewComponentActivator"/> class.
|
/// Initializes a new instance of <see cref="DefaultViewComponentActivator"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DefaultViewComponentActivator()
|
public DefaultViewComponentActivator()
|
||||||
{
|
{
|
||||||
_valueAccessorLookup = CreateValueAccessorLookup();
|
_injectActions = new ConcurrentDictionary<Type, PropertyActivator<ViewComponentContext>[]>();
|
||||||
_injectActions = new ConcurrentDictionary<Type, PropertyActivator<ViewContext>[]>();
|
|
||||||
_getPropertiesToActivate = type =>
|
_getPropertiesToActivate = type =>
|
||||||
PropertyActivator<ViewContext>.GetPropertiesToActivate(
|
PropertyActivator<ViewComponentContext>.GetPropertiesToActivate(
|
||||||
type, typeof(ActivateAttribute), CreateActivateInfo);
|
type,
|
||||||
|
typeof(ViewComponentContextAttribute),
|
||||||
|
CreateActivateInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
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(),
|
var propertiesToActivate = _injectActions.GetOrAdd(
|
||||||
_getPropertiesToActivate);
|
viewComponent.GetType(),
|
||||||
|
_getPropertiesToActivate);
|
||||||
|
|
||||||
for (var i = 0; i < propertiesToActivate.Length; i++)
|
for (var i = 0; i < propertiesToActivate.Length; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -45,44 +48,9 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private PropertyActivator<ViewComponentContext> CreateActivateInfo(PropertyInfo property)
|
||||||
/// Creates a lookup dictionary for the values to be activated.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Returns a readonly dictionary of the values corresponding to the types.</returns>
|
|
||||||
protected virtual IDictionary<Type, Func<ViewContext, object>> CreateValueAccessorLookup()
|
|
||||||
{
|
{
|
||||||
return new Dictionary<Type, Func<ViewContext, object>>
|
return new PropertyActivator<ViewComponentContext>(property, context => context);
|
||||||
{
|
|
||||||
{ typeof(ViewContext), (context) => context },
|
|
||||||
{
|
|
||||||
typeof(ViewDataDictionary),
|
|
||||||
(context) =>
|
|
||||||
{
|
|
||||||
return new ViewDataDictionary(context.ViewData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private PropertyActivator<ViewContext> CreateActivateInfo(PropertyInfo property)
|
|
||||||
{
|
|
||||||
Func<ViewContext, object> 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<ViewContext>(property, valueAccessor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
var component = _typeActivatorCache.CreateInstance<object>(
|
var component = _typeActivatorCache.CreateInstance<object>(
|
||||||
_serviceProvider,
|
_serviceProvider,
|
||||||
context.ViewComponentDescriptor.Type);
|
context.ViewComponentDescriptor.Type);
|
||||||
_viewComponentActivator.Activate(component, context.ViewContext);
|
_viewComponentActivator.Activate(component, context);
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
/// When implemented in a type, activates an instantiated ViewComponent.
|
/// When implemented in a type, activates an instantiated ViewComponent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="viewComponent">The ViewComponent to activate.</param>
|
/// <param name="viewComponent">The ViewComponent to activate.</param>
|
||||||
/// <param name="context">The <see cref="ViewContext"/> for the executing <see cref="ViewComponent"/>.</param>
|
/// <param name="context">
|
||||||
void Activate(object viewComponent, ViewContext context);
|
/// The <see cref="ViewComponentContext"/> for the executing <see cref="ViewComponent"/>.
|
||||||
|
/// </param>
|
||||||
|
void Activate(object viewComponent, ViewComponentContext context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,7 +6,9 @@ using System.Security.Principal;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
|
using Microsoft.Framework.DependencyInjection;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
|
@ -18,9 +20,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
[ViewComponent]
|
[ViewComponent]
|
||||||
public abstract class ViewComponent
|
public abstract class ViewComponent
|
||||||
{
|
{
|
||||||
|
private IUrlHelper _url;
|
||||||
private dynamic _viewBag;
|
private dynamic _viewBag;
|
||||||
private ViewContext _viewContext;
|
private ViewComponentContext _viewComponentContext;
|
||||||
private ViewDataDictionary _viewData;
|
private ICompositeViewEngine _viewEngine;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="HttpContext"/>.
|
/// Gets the <see cref="HttpContext"/>.
|
||||||
|
|
@ -96,62 +99,93 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="IUrlHelper"/>.
|
/// Gets or sets the <see cref="IUrlHelper"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Activate]
|
public IUrlHelper Url
|
||||||
public IUrlHelper Url { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the <see cref="ViewContext"/>.
|
|
||||||
/// </summary>
|
|
||||||
[Activate]
|
|
||||||
public ViewContext ViewContext
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_viewContext == null)
|
if (_url == null)
|
||||||
{
|
{
|
||||||
// This should run only for the ViewComponent unit test scenarios
|
// May be null in unit-testing scenarios.
|
||||||
_viewContext = new ViewContext();
|
var services = ViewComponentContext.ViewContext?.HttpContext?.RequestServices;
|
||||||
|
_url = services?.GetRequiredService<IUrlHelper>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _viewContext;
|
return _url;
|
||||||
}
|
}
|
||||||
|
|
||||||
[param: NotNull]
|
[param: NotNull]
|
||||||
set
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="ViewDataDictionary"/>.
|
/// Gets the <see cref="ViewContext"/>.
|
||||||
|
/// </summary>
|
||||||
|
public ViewContext ViewContext
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ViewComponentContext.ViewContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="ViewDataDictionary"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Activate]
|
|
||||||
public ViewDataDictionary ViewData
|
public ViewDataDictionary ViewData
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_viewData == null)
|
return ViewComponentContext.ViewData;
|
||||||
{
|
|
||||||
// This should run only for the ViewComponent unit test scenarios
|
|
||||||
_viewData = new ViewDataDictionary(ViewContext.ViewData);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _viewData;
|
|
||||||
}
|
|
||||||
|
|
||||||
[param: NotNull]
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_viewData = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="ICompositeViewEngine"/>.
|
/// Gets or sets the <see cref="ICompositeViewEngine"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Activate]
|
public ICompositeViewEngine ViewEngine
|
||||||
public ICompositeViewEngine ViewEngine { get; set; }
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_viewEngine == null)
|
||||||
|
{
|
||||||
|
// May be null in unit-testing scenarios.
|
||||||
|
var services = ViewComponentContext.ViewContext?.HttpContext?.RequestServices;
|
||||||
|
_viewEngine = services?.GetRequiredService<ICompositeViewEngine>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _viewEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
[param: NotNull]
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_viewEngine = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a result which will render HTML encoded text.
|
/// Returns a result which will render HTML encoded text.
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,19 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ViewComponentContext
|
public class ViewComponentContext
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="ViewComponentContext"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The default constructor is provided for unit test purposes only.
|
||||||
|
/// </remarks>
|
||||||
|
public ViewComponentContext()
|
||||||
|
{
|
||||||
|
ViewComponentDescriptor = new ViewComponentDescriptor();
|
||||||
|
Arguments = new object[0];
|
||||||
|
ViewContext = new ViewContext();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="ViewComponentContext"/>.
|
/// Creates a new <see cref="ViewComponentContext"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -29,32 +42,54 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
ViewComponentDescriptor = viewComponentDescriptor;
|
ViewComponentDescriptor = viewComponentDescriptor;
|
||||||
Arguments = arguments;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the View Component arguments.
|
/// Gets or sets the View Component arguments.
|
||||||
/// </summary>
|
|
||||||
public object[] Arguments { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="ViewComponentDescriptor"/> for the View Component being invoked.
|
|
||||||
/// </summary>
|
|
||||||
public ViewComponentDescriptor ViewComponentDescriptor { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="ViewContext"/>.
|
|
||||||
/// </summary>
|
|
||||||
public ViewContext ViewContext { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="TextWriter"/> for writing output.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <see cref="IViewComponentHelper.Invoke(string, object[])"/> or a similar overload is used to invoke the
|
/// The property setter is provided for unit test purposes only.
|
||||||
/// View Component, then <see cref="Writer"/> will be different than <see cref="ViewContext.Writer"/>.
|
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public TextWriter Writer { get; }
|
public object[] Arguments { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="ViewComponentDescriptor"/> for the View Component being invoked.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The property setter is provided for unit test purposes only.
|
||||||
|
/// </remarks>
|
||||||
|
public ViewComponentDescriptor ViewComponentDescriptor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="ViewContext"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The property setter is provided for unit test purposes only.
|
||||||
|
/// </remarks>
|
||||||
|
public ViewContext ViewContext { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="ViewDataDictionary"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is an alias for <c>ViewContext.ViewData</c>.
|
||||||
|
/// </remarks>
|
||||||
|
public ViewDataDictionary ViewData => ViewContext.ViewData;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="TextWriter"/> for output.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is an alias for <c>ViewContext.Writer</c>.
|
||||||
|
/// </remarks>
|
||||||
|
public TextWriter Writer => ViewContext.Writer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that a controller property should be set with the current
|
||||||
|
/// <see cref="ViewComponentContext"/> when creating the view component. The property must have a public
|
||||||
|
/// set method.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
||||||
|
public class ViewComponentContextAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public async Task ExecuteAsync([NotNull] ViewComponentContext context)
|
public async Task ExecuteAsync([NotNull] ViewComponentContext context)
|
||||||
{
|
{
|
||||||
var viewEngine = ViewEngine ?? ResolveViewEngine(context);
|
var viewEngine = ViewEngine ?? ResolveViewEngine(context);
|
||||||
var viewData = ViewData ?? context.ViewContext.ViewData;
|
var viewData = ViewData ?? context.ViewData;
|
||||||
|
|
||||||
string qualifiedViewName;
|
string qualifiedViewName;
|
||||||
if (ViewName != null && ViewName.Length > 0 && ViewName[0] == '/')
|
if (ViewName != null && ViewName.Length > 0 && ViewName[0] == '/')
|
||||||
|
|
@ -95,7 +95,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var childViewContext = new ViewContext(
|
var childViewContext = new ViewContext(
|
||||||
context.ViewContext,
|
context.ViewContext,
|
||||||
view,
|
view,
|
||||||
ViewData ?? context.ViewContext.ViewData,
|
ViewData ?? context.ViewData,
|
||||||
context.Writer);
|
context.Writer);
|
||||||
|
|
||||||
using (view as IDisposable)
|
using (view as IDisposable)
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public void ViewComponent_ViewBag_UsesViewData()
|
public void ViewComponent_ViewBag_UsesViewData()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var viewComponent = new TestViewComponent()
|
var viewComponent = new TestViewComponent();
|
||||||
{
|
|
||||||
ViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
viewComponent.ViewBag.A = "Alice";
|
viewComponent.ViewBag.A = "Alice";
|
||||||
|
|
@ -33,10 +30,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public void ViewComponent_ViewData_StoresDataForViewBag()
|
public void ViewComponent_ViewData_StoresDataForViewBag()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var viewComponent = new TestViewComponent()
|
var viewComponent = new TestViewComponent();
|
||||||
{
|
|
||||||
ViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
viewComponent.ViewData["A"] = "Alice";
|
viewComponent.ViewData["A"] = "Alice";
|
||||||
|
|
@ -84,10 +78,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public void ViewComponent_View_WithEmptyParameter_SetsResultViewWithDefaultViewName()
|
public void ViewComponent_View_WithEmptyParameter_SetsResultViewWithDefaultViewName()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var viewComponent = new TestViewComponent()
|
var viewComponent = new TestViewComponent();
|
||||||
{
|
|
||||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var actualResult = viewComponent.View();
|
var actualResult = viewComponent.View();
|
||||||
|
|
@ -104,10 +95,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public void ViewComponent_View_WithViewNameParameter_SetsResultViewWithCustomViewName()
|
public void ViewComponent_View_WithViewNameParameter_SetsResultViewWithCustomViewName()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var viewComponent = new TestViewComponent()
|
var viewComponent = new TestViewComponent();
|
||||||
{
|
|
||||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var actualResult = viewComponent.View("CustomViewName");
|
var actualResult = viewComponent.View("CustomViewName");
|
||||||
|
|
@ -125,10 +113,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public void ViewComponent_View_WithModelParameter_SetsResultViewWithDefaultViewNameAndModel()
|
public void ViewComponent_View_WithModelParameter_SetsResultViewWithDefaultViewNameAndModel()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var viewComponent = new TestViewComponent()
|
var viewComponent = new TestViewComponent();
|
||||||
{
|
|
||||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
|
||||||
};
|
|
||||||
var model = new object();
|
var model = new object();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -147,10 +133,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public void ViewComponent_View_WithViewNameAndModelParameters_SetsResultViewWithCustomViewNameAndModel()
|
public void ViewComponent_View_WithViewNameAndModelParameters_SetsResultViewWithCustomViewNameAndModel()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var viewComponent = new TestViewComponent()
|
var viewComponent = new TestViewComponent();
|
||||||
{
|
|
||||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
|
||||||
};
|
|
||||||
var model = new object();
|
var model = new object();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -180,7 +164,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
Assert.Empty(viewComponent.ViewContext.ViewData);
|
Assert.Empty(viewComponent.ViewContext.ViewData);
|
||||||
Assert.NotNull(viewComponent.ViewData);
|
Assert.NotNull(viewComponent.ViewData);
|
||||||
Assert.Empty(viewComponent.ViewData);
|
Assert.Empty(viewComponent.ViewData);
|
||||||
Assert.NotSame(viewComponent.ViewData, viewComponent.ViewContext.ViewData);
|
Assert.Same(viewComponent.ViewData, viewComponent.ViewContext.ViewData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestViewComponent : ViewComponent
|
private class TestViewComponent : ViewComponent
|
||||||
|
|
|
||||||
|
|
@ -17,135 +17,28 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||||
public class DefaultViewComponentActivatorTests
|
public class DefaultViewComponentActivatorTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void DefaultViewComponentActivatorSetsAllPropertiesMarkedAsActivate()
|
public void DefaultViewComponentActivator_ActivatesViewComponentContext()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var activator = new DefaultViewComponentActivator();
|
var activator = new DefaultViewComponentActivator();
|
||||||
|
|
||||||
|
var context = new ViewComponentContext();
|
||||||
var instance = new TestViewComponent();
|
var instance = new TestViewComponent();
|
||||||
var helper = Mock.Of<IHtmlHelper<object>>();
|
|
||||||
var serviceProvider = new Mock<IServiceProvider>();
|
|
||||||
serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper<object>))).Returns(helper);
|
|
||||||
serviceProvider.Setup(p => p.GetService(typeof(ICompositeViewEngine))).Returns(Mock.Of<ICompositeViewEngine>());
|
|
||||||
serviceProvider.Setup(p => p.GetService(typeof(IUrlHelper))).Returns(Mock.Of<IUrlHelper>());
|
|
||||||
var viewContext = GetViewContext(serviceProvider.Object);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
activator.Activate(instance, viewContext);
|
activator.Activate(instance, context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(helper, instance.Html);
|
Assert.Same(context, instance.ViewComponentContext);
|
||||||
Assert.Same(viewContext, instance.ViewContext);
|
|
||||||
Assert.IsType<ViewDataDictionary>(instance.ViewData);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void DefaultViewComponentActivatorSetsModelAsNull()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var activator = new DefaultViewComponentActivator();
|
|
||||||
var helper = Mock.Of<IHtmlHelper<object>>();
|
|
||||||
var serviceProvider = new Mock<IServiceProvider>();
|
|
||||||
serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper<object>))).Returns(helper);
|
|
||||||
serviceProvider.Setup(p => p.GetService(typeof(ICompositeViewEngine))).Returns(Mock.Of<ICompositeViewEngine>());
|
|
||||||
serviceProvider.Setup(p => p.GetService(typeof(IUrlHelper))).Returns(Mock.Of<IUrlHelper>());
|
|
||||||
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<IHtmlHelper<object>>();
|
|
||||||
var myTestService = new MyService();
|
|
||||||
var serviceProvider = new Mock<IServiceProvider>();
|
|
||||||
serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper<object>))).Returns(helper);
|
|
||||||
serviceProvider.Setup(p => p.GetService(typeof(MyService))).Returns(myTestService);
|
|
||||||
serviceProvider.Setup(p => p.GetService(typeof(ICompositeViewEngine))).Returns(Mock.Of<ICompositeViewEngine>());
|
|
||||||
serviceProvider.Setup(p => p.GetService(typeof(IUrlHelper))).Returns(Mock.Of<IUrlHelper>());
|
|
||||||
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<IServiceProvider>();
|
|
||||||
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<DefaultHttpContext>();
|
|
||||||
httpContext.SetupGet(c => c.RequestServices)
|
|
||||||
.Returns(serviceProvider);
|
|
||||||
|
|
||||||
var actionContext = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
|
||||||
return new ViewContext(actionContext,
|
|
||||||
Mock.Of<IView>(),
|
|
||||||
new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
|
||||||
null,
|
|
||||||
TextWriter.Null,
|
|
||||||
new HtmlHelperOptions());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestViewComponent : ViewComponent
|
private class TestViewComponent : ViewComponent
|
||||||
{
|
{
|
||||||
[Activate]
|
|
||||||
public IHtmlHelper<object> Html { get; private set; }
|
|
||||||
|
|
||||||
public Task ExecuteAsync()
|
public Task ExecuteAsync()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ViewComponentActivator_ActivatesProperties()
|
public async Task ViewComponentActivator_Activates()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||||
|
|
@ -127,35 +127,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
Assert.Equal(expected, body.Trim());
|
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]
|
[Fact]
|
||||||
public async Task ViewComponentThatCannotBeActivated_ThrowsWhenAttemptedToBeInvoked()
|
public async Task ViewComponentThatCannotBeActivated_ThrowsWhenAttemptedToBeInvoked()
|
||||||
|
|
@ -163,8 +134,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
// Arrange
|
// Arrange
|
||||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||||
var client = server.CreateClient();
|
var client = server.CreateClient();
|
||||||
var expectedMessage = "No service for type 'ActivatorWebSite.CannotBeActivatedComponent+FakeType' " +
|
var expectedMessage =
|
||||||
"has been registered.";
|
"Unable to resolve service for type 'ActivatorWebSite.CannotBeActivatedComponent+FakeType' " +
|
||||||
|
"while attempting to activate 'ActivatorWebSite.CannotBeActivatedComponent'.";
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var response = await client.GetAsync("http://localhost/View/ConsumeCannotBeActivatedComponent");
|
var response = await client.GetAsync("http://localhost/View/ConsumeCannotBeActivatedComponent");
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,16 @@ namespace ActivatorWebSite
|
||||||
[ViewComponent(Name = "CannotBeActivated")]
|
[ViewComponent(Name = "CannotBeActivated")]
|
||||||
public class CannotBeActivatedComponent : ViewComponent
|
public class CannotBeActivatedComponent : ViewComponent
|
||||||
{
|
{
|
||||||
[Activate]
|
public CannotBeActivatedComponent(FakeType fakeType)
|
||||||
private FakeType Service { get; set; }
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public IViewComponentResult Invoke()
|
public IViewComponentResult Invoke()
|
||||||
{
|
{
|
||||||
return Content("Test");
|
return Content("Test");
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class FakeType
|
public sealed class FakeType
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,12 @@ namespace ActivatorWebSite
|
||||||
[ViewComponent(Name = "Number")]
|
[ViewComponent(Name = "Number")]
|
||||||
public class NumberComponent : ViewComponent
|
public class NumberComponent : ViewComponent
|
||||||
{
|
{
|
||||||
[Activate]
|
public NumberComponent(MyService myTestService)
|
||||||
public MyService MyTestService { get; set; }
|
{
|
||||||
|
MyTestService = myTestService;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MyService MyTestService { get; }
|
||||||
|
|
||||||
public IViewComponentResult Invoke(string content)
|
public IViewComponentResult Invoke(string content)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -31,16 +31,6 @@ namespace ActivatorWebSite
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ViewResult ConsumeValueComponent()
|
|
||||||
{
|
|
||||||
return View();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ViewResult ConsumeViewAndValueComponent()
|
|
||||||
{
|
|
||||||
return View();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ViewResult ConsumeCannotBeActivatedComponent()
|
public ViewResult ConsumeCannotBeActivatedComponent()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
@Component.Invoke("Value")
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
@Component.Invoke("ViewAndValue", "Random Number")
|
|
||||||
|
|
@ -9,11 +9,15 @@ namespace MvcTagHelpersWebSite.Components
|
||||||
{
|
{
|
||||||
public class ProductsViewComponent : ViewComponent
|
public class ProductsViewComponent : ViewComponent
|
||||||
{
|
{
|
||||||
[Activate]
|
public ProductsViewComponent(ProductsService productsService, IMemoryCache cache)
|
||||||
public ProductsService ProductsService { get; set; }
|
{
|
||||||
|
ProductsService = productsService;
|
||||||
|
Cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
[Activate]
|
private ProductsService ProductsService { get; }
|
||||||
public IMemoryCache Cache { get; set; }
|
|
||||||
|
public IMemoryCache Cache { get; }
|
||||||
|
|
||||||
public IViewComponentResult Invoke(string category)
|
public IViewComponentResult Invoke(string category)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,12 @@ namespace RequestServicesWebSite
|
||||||
{
|
{
|
||||||
public class RequestIdViewComponent : ViewComponent
|
public class RequestIdViewComponent : ViewComponent
|
||||||
{
|
{
|
||||||
[Activate]
|
public RequestIdViewComponent(RequestIdService requestIdService)
|
||||||
public RequestIdService RequestIdService { get; set; }
|
{
|
||||||
|
RequestIdService = requestIdService;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RequestIdService RequestIdService { get; }
|
||||||
|
|
||||||
public IViewComponentResult Invoke()
|
public IViewComponentResult Invoke()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue