Moving IViewEngine to MvcOptions

This commit is contained in:
Pranav K 2014-06-30 16:17:40 -07:00
parent 6c5b836070
commit 5194adfaf5
29 changed files with 730 additions and 35 deletions

View File

@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Mvc
public override async Task ExecuteResultAsync([NotNull] ActionContext context)
{
var viewEngine = ViewEngine ?? context.HttpContext.RequestServices.GetService<IViewEngine>();
var viewEngine = ViewEngine ?? context.HttpContext.RequestServices.GetService<ICompositeViewEngine>();
var viewName = ViewName ?? context.ActionDescriptor.Name;
var view = FindView(viewEngine, context.RouteData.Values, viewName);

View File

@ -0,0 +1,83 @@
// 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 Microsoft.AspNet.Mvc.Rendering;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// Extension methods for adding model binders to a collection.
/// </summary>
public static class ViewEngineDescriptorExtensions
{
/// <summary>
/// Adds a type representing a <see cref="IViewEngine"/> to a descriptor collection.
/// </summary>
/// <param name="descriptors">A list of ViewEngineDescriptors</param>
/// <param name="viewEngineType">Type representing an <see cref="IViewEngine"/>.</param>
/// <returns>ViewEngineDescriptor representing the added instance.</returns>
public static ViewEngineDescriptor Add([NotNull] this IList<ViewEngineDescriptor> descriptors,
[NotNull] Type viewEngineType)
{
var descriptor = new ViewEngineDescriptor(viewEngineType);
descriptors.Add(descriptor);
return descriptor;
}
/// <summary>
/// Inserts a type representing a <see cref="IViewEngine"/> to a descriptor collection.
/// </summary>
/// <param name="descriptors">A list of ViewEngineDescriptors</param>
/// <param name="viewEngineType">Type representing an <see cref="IViewEngine"/>.</param>
/// <returns>ViewEngineDescriptor representing the inserted instance.</returns>
public static ViewEngineDescriptor Insert([NotNull] this IList<ViewEngineDescriptor> descriptors,
int index,
[NotNull] Type viewEngineType)
{
if (index < 0 || index > descriptors.Count)
{
throw new ArgumentOutOfRangeException("index");
}
var descriptor = new ViewEngineDescriptor(viewEngineType);
descriptors.Insert(index, descriptor);
return descriptor;
}
/// <summary>
/// Adds an <see cref="IViewEngine"/> to a descriptor collection.
/// </summary>
/// <param name="descriptors">A list of ViewEngineDescriptors</param>
/// <param name="viewEngine">An <see cref="IViewEngine"/> instance.</param>
/// <returns>ViewEngineDescriptor representing the added instance.</returns>
public static ViewEngineDescriptor Add([NotNull] this IList<ViewEngineDescriptor> descriptors,
[NotNull] IViewEngine viewEngine)
{
var descriptor = new ViewEngineDescriptor(viewEngine);
descriptors.Add(descriptor);
return descriptor;
}
/// <summary>
/// Insert an <see cref="IViewEngine"/> to a descriptor collection.
/// </summary>
/// <param name="descriptors">A list of ViewEngineDescriptors</param>
/// <param name="viewEngine">An <see cref="IViewEngine"/> instance.</param>
/// <returns>ViewEngineDescriptor representing the added instance.</returns>
public static ViewEngineDescriptor Insert([NotNull] this IList<ViewEngineDescriptor> descriptors,
int index,
[NotNull] IViewEngine viewEngine)
{
if (index < 0 || index > descriptors.Count)
{
throw new ArgumentOutOfRangeException("index");
}
var descriptor = new ViewEngineDescriptor(viewEngine);
descriptors.Insert(index, descriptor);
return descriptor;
}
}
}

View File

@ -27,6 +27,7 @@
<Compile Include="ActionDescriptor.cs" />
<Compile Include="ActionDescriptorProviderContext.cs" />
<Compile Include="ActionDescriptorsCollection.cs" />
<Compile Include="Extensions\ViewEngineDescriptorExtensions.cs" />
<Compile Include="ReflectedActionDescriptor.cs" />
<Compile Include="ReflectedActionDescriptorProvider.cs" />
<Compile Include="ReflectedModelBuilder\IReflectedApplicationModelConvention.cs" />
@ -157,6 +158,8 @@
<Compile Include="ReflectedActionInvoker.cs" />
<Compile Include="ReflectedActionInvokerProvider.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedParameterModel.cs" />
<Compile Include="Rendering\CompositeViewEngine.cs" />
<Compile Include="Rendering\DefaultViewEngineProvider.cs" />
<Compile Include="Rendering\DynamicViewData.cs" />
<Compile Include="Rendering\Expressions\CachedExpressionCompiler.cs" />
<Compile Include="Rendering\Expressions\ExpressionHelper.cs" />
@ -192,16 +195,19 @@
<Compile Include="Rendering\Html\TemplateRenderer.cs" />
<Compile Include="Rendering\Html\ValidationHelpers.cs" />
<Compile Include="Rendering\ICanHasViewContext.cs" />
<Compile Include="Rendering\ICompositeViewEngine.cs" />
<Compile Include="Rendering\IHtmlHelper.cs" />
<Compile Include="Rendering\IHtmlHelperOfT.cs" />
<Compile Include="Rendering\IView.cs" />
<Compile Include="Rendering\IViewEngine.cs" />
<Compile Include="Rendering\IViewEngineProvider.cs" />
<Compile Include="Rendering\MultiSelectList.cs" />
<Compile Include="Rendering\MvcForm.cs" />
<Compile Include="Rendering\SelectList.cs" />
<Compile Include="Rendering\SelectListGroup.cs" />
<Compile Include="Rendering\SelectListItem.cs" />
<Compile Include="Rendering\UnobtrusiveValidationAttributesGenerator.cs" />
<Compile Include="Rendering\ViewEngineDescriptor.cs" />
<Compile Include="Rendering\ViewEngineResult.cs" />
<Compile Include="RouteAttribute.cs" />
<Compile Include="RouteConstraintAttribute.cs" />

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ReflectedModelBuilder;
using Microsoft.AspNet.Mvc.Rendering;
namespace Microsoft.AspNet.Mvc
{
@ -24,6 +25,8 @@ namespace Microsoft.AspNet.Mvc
new ModelBinderDescriptor(new MutableObjectModelBinder()),
new ModelBinderDescriptor(new ComplexModelDtoModelBinder()),
};
ViewEngines = new List<ViewEngineDescriptor>();
}
public AntiForgeryOptions AntiForgeryOptions
@ -48,6 +51,11 @@ namespace Microsoft.AspNet.Mvc
public List<ModelBinderDescriptor> ModelBinders { get; private set; }
/// <summary>
/// Gets a list of descriptors that represent <see cref="IViewEngine"/> used by this application.
/// </summary>
public List<ViewEngineDescriptor> ViewEngines { get; private set; }
public List<IReflectedApplicationModelConvention> ApplicationModelConventions { get; private set; }
}
}

View File

@ -1034,6 +1034,22 @@ namespace Microsoft.AspNet.Mvc.Core
return string.Format(CultureInfo.CurrentCulture, GetString("ValueTypesCannotBeActivated"), p0);
}
/// <summary>
/// The type '{0}' must derive from '{1}'.
/// </summary>
internal static string TypeMustDeriveFromType
{
get { return GetString("TypeMustDeriveFromType"); }
}
/// <summary>
/// The type '{0}' must derive from '{1}'.
/// </summary>
internal static string FormatTypeMustDeriveFromType(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("TypeMustDeriveFromType"), p0, p1);
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);

View File

@ -0,0 +1,57 @@
// 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.Linq;
namespace Microsoft.AspNet.Mvc.Rendering
{
/// <inheritdoc />
public class CompositeViewEngine : ICompositeViewEngine
{
public CompositeViewEngine(IViewEngineProvider viewEngineProvider)
{
ViewEngines = viewEngineProvider.ViewEngines;
}
/// <summary>
/// Gets the list of ViewEngines the CompositeViewEngine delegates to.
/// </summary>
public IReadOnlyList<IViewEngine> ViewEngines { get; private set; }
/// <inheritdoc />
public ViewEngineResult FindPartialView([NotNull] IDictionary<string, object> context,
[NotNull] string partialViewName)
{
return FindView(context, partialViewName, partial: true);
}
/// <inheritdoc />
public ViewEngineResult FindView([NotNull] IDictionary<string, object> context,
[NotNull] string viewName)
{
return FindView(context, viewName, partial: false);
}
private ViewEngineResult FindView(IDictionary<string, object> context,
string viewName,
bool partial)
{
var searchedLocations = Enumerable.Empty<string>();
foreach (var engine in ViewEngines)
{
var result = partial ? engine.FindPartialView(context, viewName) :
engine.FindView(context, viewName);
if (result.Success)
{
return result;
}
searchedLocations = searchedLocations.Concat(result.SearchedLocations);
}
return ViewEngineResult.NotFound(viewName, searchedLocations);
}
}
}

View File

@ -0,0 +1,50 @@
// 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 Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Mvc.Rendering
{
/// <inheritdoc />
public class DefaultViewEngineProvider : IViewEngineProvider
{
private readonly IList<ViewEngineDescriptor> _descriptors;
private readonly ITypeActivator _typeActivator;
private readonly IServiceProvider _serviceProvider;
public DefaultViewEngineProvider(
ITypeActivator typeActivator,
IServiceProvider serviceProvider,
IOptionsAccessor<MvcOptions> options)
{
_typeActivator = typeActivator;
_serviceProvider = serviceProvider;
_descriptors = options.Options.ViewEngines;
}
/// <inheritdoc />
public IReadOnlyList<IViewEngine> ViewEngines
{
get
{
var viewEngines = new List<IViewEngine>(_descriptors.Count);
foreach (var descriptor in _descriptors)
{
var viewEngine = descriptor.ViewEngine;
if (viewEngine == null)
{
viewEngine = (IViewEngine)_typeActivator.CreateInstance(_serviceProvider,
descriptor.ViewEngineType);
}
viewEngines.Add(viewEngine);
}
return viewEngines;
}
}
}
}

View File

@ -125,7 +125,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
var metadataProvider = serviceProvider.GetService<IModelMetadataProvider>();
var viewEngine = serviceProvider.GetService<IViewEngine>();
var viewEngine = serviceProvider.GetService<ICompositeViewEngine>();
var index = 0;
foreach (var item in collection)
@ -213,7 +213,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
var viewEngine = serviceProvider.GetService<IViewEngine>();
var viewEngine = serviceProvider.GetService<ICompositeViewEngine>();
foreach (var propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo)))
{

View File

@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
var metadataProvider = serviceProvider.GetService<IModelMetadataProvider>();
var viewEngine = serviceProvider.GetService<IViewEngine>();
var viewEngine = serviceProvider.GetService<ICompositeViewEngine>();
var index = 0;
foreach (var item in collection)
@ -214,7 +214,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
var viewEngine = serviceProvider.GetService<IViewEngine>();
var viewEngine = serviceProvider.GetService<ICompositeViewEngine>();
foreach (var propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo)))
{

View File

@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
private const string HiddenListItem = @"<li style=""display:none""></li>";
private readonly IUrlHelper _urlHelper;
private readonly IViewEngine _viewEngine;
private readonly ICompositeViewEngine _viewEngine;
private readonly AntiForgery _antiForgeryInstance;
private readonly IActionBindingContextProvider _actionBindingContextProvider;
@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// Initializes a new instance of the <see cref="HtmlHelper"/> class.
/// </summary>
public HtmlHelper(
[NotNull] IViewEngine viewEngine,
[NotNull] ICompositeViewEngine viewEngine,
[NotNull] IModelMetadataProvider metadataProvider,
[NotNull] IUrlHelper urlHelper,
[NotNull] AntiForgery antiForgeryInstance,

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// Initializes a new instance of the <see cref="HtmlHelper{TModel}"/> class.
/// </summary>
public HtmlHelper(
[NotNull] IViewEngine viewEngine,
[NotNull] ICompositeViewEngine viewEngine,
[NotNull] IModelMetadataProvider metadataProvider,
[NotNull] IUrlHelper urlHelper,
[NotNull] AntiForgery antiForgeryInstance,

View File

@ -1,8 +1,6 @@
// 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.Globalization;
using Microsoft.AspNet.Mvc.ModelBinding;

View File

@ -0,0 +1,12 @@
// 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.Rendering
{
/// <summary>
/// Represents an <see cref="IViewEngine"/> that delegates to one of a collection of view engines.
/// </summary>
public interface ICompositeViewEngine : IViewEngine
{
}
}

View File

@ -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.
using System.Collections.Generic;
namespace Microsoft.AspNet.Mvc.Rendering
{
/// <summary>
/// Provides an activated collection of <see cref="IViewEngine"/> instances.
/// </summary>
public interface IViewEngineProvider
{
/// <summary>
/// Gets a collection of activated IViewEngine instances.
/// </summary>
IReadOnlyList<IViewEngine> ViewEngines { get; }
}
}

View File

@ -0,0 +1,58 @@
// 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 Microsoft.AspNet.Mvc.Core;
namespace Microsoft.AspNet.Mvc.Rendering
{
/// <summary>
/// Encapsulates information that describes an <see cref="IViewEngine"/>.
/// </summary>
public class ViewEngineDescriptor
{
/// <summary>
/// Creates a new instance of <see cref="ViewEngineDescriptor"/>.
/// </summary>
/// <param name="type">The <see cref="IViewEngine/> type that the descriptor represents.</param>
public ViewEngineDescriptor([NotNull] Type type)
{
var viewEngineType = typeof(IViewEngine);
if (!viewEngineType.IsAssignableFrom(type))
{
var message = Resources.FormatTypeMustDeriveFromType(type.FullName, viewEngineType.FullName);
throw new ArgumentException(message, "type");
}
ViewEngineType = type;
}
/// <summary>
/// Creates a new instance of <see cref="ViewEngineDescriptor"/>.
/// </summary>
/// <param name="viewEngine">An instance of <see cref="IViewEngine"/> that the descriptor represents.</param>
public ViewEngineDescriptor([NotNull] IViewEngine viewEngine)
{
ViewEngine = viewEngine;
ViewEngineType = viewEngine.GetType();
}
/// <summary>
/// Gets the type of the <see cref="IViewEngine"/>.
/// </summary>
public Type ViewEngineType
{
get;
private set;
}
/// <summary>
/// Gets the instance of the <see cref="IViewEngine"/>.
/// </summary>
public IViewEngine ViewEngine
{
get;
private set;
}
}
}

View File

@ -309,4 +309,7 @@
<data name="ValueTypesCannotBeActivated" xml:space="preserve">
<value>Value types cannot be activated by '{0}'.</value>
</data>
<data name="TypeMustDeriveFromType" xml:space="preserve">
<value>The type '{0}' must derive from '{1}'.</value>
</data>
</root>

View File

@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Mvc
public abstract class ViewComponent
{
private dynamic _viewBag;
private IViewEngine _viewEngine;
private ICompositeViewEngine _viewEngine;
public HttpContext Context
{
@ -39,7 +39,7 @@ namespace Microsoft.AspNet.Mvc
return new ContentViewComponentResult(content);
}
public void Initialize(IViewEngine viewEngine)
public void Initialize(ICompositeViewEngine viewEngine)
{
_viewEngine = viewEngine;
}

View File

@ -21,6 +21,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BuilderExtensions.cs" />
<Compile Include="MvcOptionsSetup.cs" />
<Compile Include="MvcServiceCollectionExtensions.cs" />
<Compile Include="MvcServices.cs" />
</ItemGroup>

View File

@ -0,0 +1,26 @@
// 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 Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// Sets up default options for <see cref="MvcOptions"/>.
/// </summary>
public class MvcOptionsSetup : IOptionsSetup<MvcOptions>
{
/// <inheritdoc />
public int Order
{
get { return 1; }
}
/// <inheritdoc />
public void Setup(MvcOptions options)
{
options.ViewEngines.Add(typeof(RazorViewEngine));
}
}
}

View File

@ -11,6 +11,7 @@ using Microsoft.AspNet.Security;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.NestedProviders;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Mvc
{
@ -25,6 +26,8 @@ namespace Microsoft.AspNet.Mvc
{
var describe = new ServiceDescriber(configuration);
yield return describe.Transient<IOptionsSetup<MvcOptions>, MvcOptionsSetup>();
yield return describe.Transient<IControllerFactory, DefaultControllerFactory>();
yield return describe.Singleton<IControllerActivator, DefaultControllerActivator>();
yield return describe.Scoped<IActionSelector, DefaultActionSelector>();
@ -36,9 +39,10 @@ namespace Microsoft.AspNet.Mvc
yield return describe.Transient<ICompilationService, RoslynCompilationService>();
yield return describe.Singleton<IViewEngineProvider, DefaultViewEngineProvider>();
yield return describe.Scoped<ICompositeViewEngine, CompositeViewEngine>();
yield return describe.Transient<IRazorCompilationService, RazorCompilationService>();
yield return describe.Transient<IVirtualPathViewFactory, VirtualPathViewFactory>();
yield return describe.Scoped<IViewEngine, RazorViewEngine>();
yield return describe.Transient<INestedProvider<ActionDescriptorProviderContext>,
ReflectedActionDescriptorProvider>();

View File

@ -0,0 +1,79 @@
// 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.Collections.Generic;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Rendering
{
public class ViewEngineDescriptorExtensionTest
{
[Theory]
[InlineData(-1)]
[InlineData(5)]
public void Insert_WithType_ThrowsIfIndexIsOutOfBounds(int index)
{
// Arrange
var collection = new List<ViewEngineDescriptor>
{
new ViewEngineDescriptor(Mock.Of<IViewEngine>()),
new ViewEngineDescriptor(Mock.Of<IViewEngine>())
};
// Act & Assert
Assert.Throws<ArgumentOutOfRangeException>("index", () => collection.Insert(index, typeof(IViewEngine)));
}
[Theory]
[InlineData(-2)]
[InlineData(3)]
public void Insert_WithInstance_ThrowsIfIndexIsOutOfBounds(int index)
{
// Arrange
var collection = new List<ViewEngineDescriptor>
{
new ViewEngineDescriptor(Mock.Of<IViewEngine>()),
new ViewEngineDescriptor(Mock.Of<IViewEngine>())
};
var viewEngine = Mock.Of<IViewEngine>();
// Act & Assert
Assert.Throws<ArgumentOutOfRangeException>("index", () => collection.Insert(index, viewEngine));
}
[InlineData]
public void ViewEngineDescriptors_AddsTypesAndInstances()
{
// Arrange
var viewEngine = Mock.Of<IViewEngine>();
var type = typeof(TestViewEngine);
var collection = new List<ViewEngineDescriptor>();
// Act
collection.Add(viewEngine);
collection.Insert(0, type);
// Assert
Assert.Equal(2, collection.Count);
Assert.IsType<TestViewEngine>(collection[0].ViewEngine);
Assert.Same(viewEngine, collection[0].ViewEngine);
}
private class TestViewEngine : IViewEngine
{
public ViewEngineResult FindPartialView([NotNull]IDictionary<string, object> context, [NotNull]string partialViewName)
{
throw new NotImplementedException();
}
public ViewEngineResult FindView([NotNull]IDictionary<string, object> context, [NotNull]string viewName)
{
throw new NotImplementedException();
}
}
}
}
#endif

View File

@ -30,6 +30,7 @@
<Compile Include="ActionResults\RedirectResultTest.cs" />
<Compile Include="ActionSelectionConventionTests.cs" />
<Compile Include="AntiXsrf\AntiForgeryOptionsTests.cs" />
<Compile Include="Extensions\ViewEngineDscriptorExtensionsTest.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedParameterModelTests.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedActionModelTests.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedControllerModelTests.cs" />
@ -60,6 +61,7 @@
<Compile Include="PropertyHelperTest.cs" />
<Compile Include="ReflectedActionDescriptorProviderTests.cs" />
<Compile Include="ReflectedActionInvokerTest.cs" />
<Compile Include="Rendering\CompositeViewEngineTest.cs" />
<Compile Include="Rendering\DefaultTemplatesUtilities.cs" />
<Compile Include="Rendering\DefaultDisplayTemplatesTests.cs" />
<Compile Include="Rendering\DefaultEditorTemplatesTests.cs" />
@ -67,6 +69,8 @@
<Compile Include="Rendering\ViewContextTests.cs" />
<Compile Include="Rendering\ViewDataOfTTest.cs" />
<Compile Include="KnownRouteValueConstraintTests.cs" />
<Compile Include="Rendering\ViewEngineDescriptorTest.cs" />
<Compile Include="Rendering\DefaultViewEngineProviderTest.cs" />
<Compile Include="Routing\AttributeRoutePrecedenceTests.cs" />
<Compile Include="Routing\AttributeRouteTemplateTests.cs" />
<Compile Include="TestController.cs" />

View File

@ -0,0 +1,131 @@
// 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.Collections.Generic;
using System.Linq;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Rendering
{
public class CompositeViewEngineTest
{
[Fact]
public void FindView_ReturnsViewFromFirstViewEngineWithFoundResult()
{
// Arrange
var viewName = "foo";
var engine1 = new Mock<IViewEngine>();
var engine2 = new Mock<IViewEngine>();
var engine3 = new Mock<IViewEngine>();
var view2 = Mock.Of<IView>();
var view3 = Mock.Of<IView>();
engine1.Setup(e => e.FindView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound(viewName, Enumerable.Empty<string>()));
engine2.Setup(e => e.FindView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.Found(viewName, view2));
engine3.Setup(e => e.FindView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.Found(viewName, view3));
var provider = new Mock<IViewEngineProvider>();
provider.SetupGet(p => p.ViewEngines)
.Returns(new[] { engine1.Object, engine2.Object, engine3.Object });
var compositeViewEngine = new CompositeViewEngine(provider.Object);
// Act
var result = compositeViewEngine.FindView(new Dictionary<string, object>(), viewName);
// Assert
Assert.True(result.Success);
Assert.Same(view2, result.View);
Assert.Equal(viewName, result.ViewName);
}
[Fact]
public void FindView_ReturnsNotFound_IfAllViewEnginesReturnNotFound()
{
// Arrange
var viewName = "foo";
var engine1 = new Mock<IViewEngine>();
var engine2 = new Mock<IViewEngine>();
var engine3 = new Mock<IViewEngine>();
engine1.Setup(e => e.FindView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "1", "2" }));
engine2.Setup(e => e.FindView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "3" }));
engine3.Setup(e => e.FindView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "4", "5" }));
var provider = new Mock<IViewEngineProvider>();
provider.SetupGet(p => p.ViewEngines)
.Returns(new[] { engine1.Object, engine2.Object, engine3.Object });
var compositeViewEngine = new CompositeViewEngine(provider.Object);
// Act
var result = compositeViewEngine.FindView(new Dictionary<string, object>(), viewName);
// Assert
Assert.False(result.Success);
Assert.Equal(new[] { "1", "2", "3", "4", "5" }, result.SearchedLocations);
}
[Fact]
public void FindPartialView_ReturnsViewFromFirstViewEngineWithFoundResult()
{
// Arrange
var viewName = "bar";
var engine1 = new Mock<IViewEngine>();
var engine2 = new Mock<IViewEngine>();
var engine3 = new Mock<IViewEngine>();
var view2 = Mock.Of<IView>();
var view3 = Mock.Of<IView>();
engine1.Setup(e => e.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound(viewName, Enumerable.Empty<string>()));
engine2.Setup(e => e.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.Found(viewName, view2));
engine3.Setup(e => e.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.Found(viewName, view3));
var provider = new Mock<IViewEngineProvider>();
provider.SetupGet(p => p.ViewEngines)
.Returns(new[] { engine1.Object, engine2.Object, engine3.Object });
var compositeViewEngine = new CompositeViewEngine(provider.Object);
// Act
var result = compositeViewEngine.FindPartialView(new Dictionary<string, object>(), viewName);
// Assert
Assert.True(result.Success);
Assert.Same(view2, result.View);
Assert.Equal(viewName, result.ViewName);
}
[Fact]
public void FindPartialView_ReturnsNotFound_IfAllViewEnginesReturnNotFound()
{
// Arrange
var viewName = "foo";
var engine1 = new Mock<IViewEngine>();
var engine2 = new Mock<IViewEngine>();
var engine3 = new Mock<IViewEngine>();
engine1.Setup(e => e.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "1", "2" }));
engine2.Setup(e => e.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "3" }));
engine3.Setup(e => e.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "4", "5" }));
var provider = new Mock<IViewEngineProvider>();
provider.SetupGet(p => p.ViewEngines)
.Returns(new[] { engine1.Object, engine2.Object, engine3.Object });
var compositeViewEngine = new CompositeViewEngine(provider.Object);
// Act
var result = compositeViewEngine.FindPartialView(new Dictionary<string, object>(), viewName);
// Assert
Assert.False(result.Success);
Assert.Equal(new[] { "1", "2", "3", "4", "5" }, result.SearchedLocations);
}
}
}

View File

@ -85,7 +85,7 @@ namespace Microsoft.AspNet.Mvc.Core
<div class=""display-field""></div>
";
var model = new DefaultTemplatesUtilities.ObjectWithScaffoldColumn();
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine.Setup(v => v.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound("", Enumerable.Empty<string>()));
var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.Core
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" };
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine
.Setup(v => v.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound("", Enumerable.Empty<string>()));
@ -121,7 +121,7 @@ namespace Microsoft.AspNet.Mvc.Core
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" };
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine
.Setup(v => v.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound("", Enumerable.Empty<string>()));
@ -140,7 +140,7 @@ namespace Microsoft.AspNet.Mvc.Core
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" };
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine
.Setup(v => v.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound("", Enumerable.Empty<string>()));
@ -160,7 +160,7 @@ namespace Microsoft.AspNet.Mvc.Core
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = propertyValue, };
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine
.Setup(v => v.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound("", Enumerable.Empty<string>()));

View File

@ -93,7 +93,7 @@ Environment.NewLine +
Environment.NewLine;
var model = new DefaultTemplatesUtilities.ObjectWithScaffoldColumn();
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine.Setup(v => v.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound("", Enumerable.Empty<string>()));
var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
@ -110,7 +110,7 @@ Environment.NewLine;
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" };
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine
.Setup(v => v.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound("", Enumerable.Empty<string>()));
@ -131,7 +131,7 @@ Environment.NewLine;
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" };
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine
.Setup(v => v.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound("", Enumerable.Empty<string>()));
@ -152,7 +152,7 @@ Environment.NewLine;
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Model string" };
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine
.Setup(v => v.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound("", Enumerable.Empty<string>()));
@ -174,7 +174,7 @@ Environment.NewLine;
{
// Arrange
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = propertyValue, };
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine
.Setup(v => v.FindPartialView(It.IsAny<IDictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.NotFound("", Enumerable.Empty<string>()));

View File

@ -63,14 +63,14 @@ namespace Microsoft.AspNet.Mvc.Core
return GetHtmlHelper(model, CreateViewEngine(), provider);
}
public static HtmlHelper<TModel> GetHtmlHelper<TModel>(TModel model, IViewEngine viewEngine)
public static HtmlHelper<TModel> GetHtmlHelper<TModel>(TModel model, ICompositeViewEngine viewEngine)
{
return GetHtmlHelper(model, viewEngine, new DataAnnotationsModelMetadataProvider());
}
public static HtmlHelper<TModel> GetHtmlHelper<TModel>(
TModel model,
IViewEngine viewEngine,
ICompositeViewEngine viewEngine,
IModelMetadataProvider provider)
{
var viewData = new ViewDataDictionary<TModel>(provider);
@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.Core
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider
.Setup(s => s.GetService(typeof(IViewEngine)))
.Setup(s => s.GetService(typeof(ICompositeViewEngine)))
.Returns(viewEngine);
serviceProvider
.Setup(s => s.GetService(typeof(IUrlHelper)))
@ -110,7 +110,7 @@ namespace Microsoft.AspNet.Mvc.Core
serviceProvider
.Setup(s => s.GetService(typeof(IViewComponentHelper)))
.Returns(new Mock<IViewComponentHelper>().Object);
httpContext
.Setup(o => o.RequestServices)
.Returns(serviceProvider.Object);
@ -138,7 +138,7 @@ namespace Microsoft.AspNet.Mvc.Core
return htmlHelper;
}
private static IViewEngine CreateViewEngine()
private static ICompositeViewEngine CreateViewEngine()
{
var view = new Mock<IView>();
view
@ -149,10 +149,11 @@ namespace Microsoft.AspNet.Mvc.Core
})
.Returns(Task.FromResult(0));
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine
.Setup(v => v.FindPartialView(It.IsAny<Dictionary<string, object>>(), It.IsAny<string>()))
.Returns(ViewEngineResult.Found("MyView", view.Object));
return viewEngine.Object;
}

View File

@ -0,0 +1,70 @@
// 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.Collections.Generic;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Rendering
{
public class DefaultViewEngineProviderTest
{
[Fact]
public void ViewEngine_ReturnsInstantiatedListOfViewEngines()
{
// Arrange
var service = Mock.Of<ITestService>();
var viewEngine = Mock.Of<IViewEngine>();
var type = typeof(TestViewEngine);
var typeActivator = new TypeActivator();
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(p => p.GetService(typeof(ITestService)))
.Returns(service);
var options = new MvcOptions();
options.ViewEngines.Add(viewEngine);
options.ViewEngines.Add(type);
var accessor = new Mock<IOptionsAccessor<MvcOptions>>();
accessor.SetupGet(a => a.Options)
.Returns(options);
var provider = new DefaultViewEngineProvider(typeActivator, serviceProvider.Object, accessor.Object);
// Act
var result = provider.ViewEngines;
// Assert
Assert.Equal(2, result.Count);
Assert.Same(viewEngine, result[0]);
var testViewEngine = Assert.IsType<TestViewEngine>(result[1]);
Assert.Same(service, testViewEngine.Service);
}
private class TestViewEngine : IViewEngine
{
public TestViewEngine(ITestService service)
{
Service = service;
}
public ITestService Service { get; private set; }
public ViewEngineResult FindPartialView([NotNull]IDictionary<string, object> context, [NotNull]string partialViewName)
{
throw new NotImplementedException();
}
public ViewEngineResult FindView([NotNull]IDictionary<string, object> context, [NotNull]string viewName)
{
throw new NotImplementedException();
}
}
public interface ITestService
{
}
}
}
#endif

View File

@ -0,0 +1,67 @@
// 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 Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Mvc.Rendering
{
public class ViewEngineDescriptorTest
{
[Fact]
public void ConstructorThrows_IfTypeIsNotViewEngine()
{
// Arrange
var viewEngineType = typeof(IViewEngine).FullName;
var type = typeof(string);
var expected = string.Format("The type '{0}' must derive from '{1}'.",
type.FullName, viewEngineType);
// Act & Assert
ExceptionAssert.ThrowsArgument(() => new ViewEngineDescriptor(type), "type", expected);
}
[Fact]
public void ConstructorSetsViewEngineType()
{
// Arrange
var type = typeof(TestViewEngine);
// Act
var descriptor = new ViewEngineDescriptor(type);
// Assert
Assert.Equal(type, descriptor.ViewEngineType);
Assert.Null(descriptor.ViewEngine);
}
[Fact]
public void ConstructorSetsViewEngineAndViewEngineType()
{
// Arrange
var viewEngine = new TestViewEngine();
// Act
var descriptor = new ViewEngineDescriptor(viewEngine);
// Assert
Assert.Same(viewEngine, descriptor.ViewEngine);
Assert.Equal(viewEngine.GetType(), descriptor.ViewEngineType);
}
private class TestViewEngine : IViewEngine
{
public ViewEngineResult FindPartialView(IDictionary<string, object> context, string partialViewName)
{
throw new NotImplementedException();
}
public ViewEngineResult FindView(IDictionary<string, object> context, string viewName)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -34,12 +34,13 @@ namespace Microsoft.AspNet.Mvc.Core.Test
var routeDictionary = new Dictionary<string, object>();
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine.Setup(v => v.FindView(routeDictionary, It.IsAny<string>()))
.Returns(ViewEngineResult.Found("MyView", view.Object));
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(sp => sp.GetService(typeof(IViewEngine))).Returns(viewEngine.Object);
serviceProvider.Setup(sp => sp.GetService(typeof(ICompositeViewEngine)))
.Returns(viewEngine.Object);
var memoryStream = new MemoryStream();
var response = new Mock<HttpResponse>();
@ -86,10 +87,11 @@ namespace Microsoft.AspNet.Mvc.Core.Test
goodViewEngine.Setup(v => v.FindView(routeDictionary, It.IsAny<string>()))
.Returns(ViewEngineResult.Found("MyView", view.Object));
var badViewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
var badViewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(sp => sp.GetService(typeof(IViewEngine))).Returns(badViewEngine.Object);
serviceProvider.Setup(sp => sp.GetService(typeof(ICompositeViewEngine)))
.Returns(badViewEngine.Object);
var memoryStream = new MemoryStream();
var response = new Mock<HttpResponse>();
@ -138,12 +140,13 @@ namespace Microsoft.AspNet.Mvc.Core.Test
throw new Exception();
});
var viewEngine = new Mock<IViewEngine>();
var viewEngine = new Mock<ICompositeViewEngine>();
viewEngine.Setup(v => v.FindView(routeDictionary, It.IsAny<string>()))
.Returns(ViewEngineResult.Found("MyView", view.Object));
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(sp => sp.GetService(typeof(IViewEngine))).Returns(viewEngine.Object);
serviceProvider.Setup(sp => sp.GetService(typeof(ICompositeViewEngine)))
.Returns(viewEngine.Object);
var memoryStream = new MemoryStream();
var response = new Mock<HttpResponse>();