Improve `SearchLocations` handling
- do not blindly use `FindPage()` / `FindView()` result in `Exception.Message` or returned results - failure scenarios involve new `Any()` calls but rarely additional `List<string>()` allocations - change `ViewEngine_ViewNotFound` resource to be consistent with similar errors - remove trailing period at end of searched locations list nit: remove remaining `null` checks of `SearchedLocations` in not found cases; never `null` then
This commit is contained in:
parent
08dd77d8c7
commit
d1fe824b5d
|
|
@ -245,6 +245,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
private IRazorPage GetLayoutPage(ViewContext context, string executingFilePath, string layoutPath)
|
||||
{
|
||||
var layoutPageResult = _viewEngine.GetPage(executingFilePath, layoutPath, isPartial: true);
|
||||
var originalLocations = layoutPageResult.SearchedLocations;
|
||||
if (layoutPageResult.Page == null)
|
||||
{
|
||||
layoutPageResult = _viewEngine.FindPage(context, layoutPath, isPartial: true);
|
||||
|
|
@ -252,8 +253,18 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
if (layoutPageResult.Page == null)
|
||||
{
|
||||
var locations =
|
||||
Environment.NewLine + string.Join(Environment.NewLine, layoutPageResult.SearchedLocations);
|
||||
var locations = string.Empty;
|
||||
if (originalLocations.Any())
|
||||
{
|
||||
locations = Environment.NewLine + string.Join(Environment.NewLine, originalLocations);
|
||||
}
|
||||
|
||||
if (layoutPageResult.SearchedLocations.Any())
|
||||
{
|
||||
locations +=
|
||||
Environment.NewLine + string.Join(Environment.NewLine, layoutPageResult.SearchedLocations);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(Resources.FormatLayoutCannotBeLocated(layoutPath, locations));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var executor = services.GetRequiredService<PartialViewResultExecutor>();
|
||||
|
||||
var result = executor.FindView(context, this);
|
||||
result.EnsureSuccessful();
|
||||
result.EnsureSuccessful(originalLocations: null);
|
||||
|
||||
var view = result.View;
|
||||
using (view as IDisposable)
|
||||
|
|
|
|||
|
|
@ -507,7 +507,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The view '{0}' was not found. The following locations were searched:{1}.
|
||||
/// The view '{0}' was not found. The following locations were searched:{1}
|
||||
/// </summary>
|
||||
internal static string ViewEngine_ViewNotFound
|
||||
{
|
||||
|
|
@ -515,7 +515,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The view '{0}' was not found. The following locations were searched:{1}.
|
||||
/// The view '{0}' was not found. The following locations were searched:{1}
|
||||
/// </summary>
|
||||
internal static string FormatViewEngine_ViewNotFound(object p0, object p1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
|
|
@ -26,36 +26,36 @@
|
|||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
|
|
@ -212,7 +212,7 @@
|
|||
<value>The partial view '{0}' was not found. The following locations were searched:{1}</value>
|
||||
</data>
|
||||
<data name="ViewEngine_ViewNotFound" xml:space="preserve">
|
||||
<value>The view '{0}' was not found. The following locations were searched:{1}.</value>
|
||||
<value>The view '{0}' was not found. The following locations were searched:{1}</value>
|
||||
</data>
|
||||
<data name="HtmlHelper_TextAreaParameterOutOfRange" xml:space="preserve">
|
||||
<value>The value must be greater than or equal to zero.</value>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// 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.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -82,10 +83,12 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
var isNullOrEmptyViewName = string.IsNullOrEmpty(ViewName);
|
||||
|
||||
ViewEngineResult result = null;
|
||||
IEnumerable<string> originalLocations = null;
|
||||
if (!isNullOrEmptyViewName)
|
||||
{
|
||||
// If view name was passed in is already a path, the view engine will handle this.
|
||||
result = viewEngine.GetView(viewContext.ExecutingFilePath, ViewName, isPartial: true);
|
||||
originalLocations = result.SearchedLocations;
|
||||
}
|
||||
|
||||
if (result == null || !result.Success)
|
||||
|
|
@ -111,7 +114,7 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
result = viewEngine.FindView(viewContext, qualifiedViewName, isPartial: true);
|
||||
}
|
||||
|
||||
var view = result.EnsureSuccessful().View;
|
||||
var view = result.EnsureSuccessful(originalLocations).View;
|
||||
using (view as IDisposable)
|
||||
{
|
||||
if (_diagnosticSource == null)
|
||||
|
|
@ -121,7 +124,11 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
|
||||
_diagnosticSource.ViewComponentBeforeViewExecute(context, view);
|
||||
|
||||
var childViewContext = new ViewContext(viewContext, view, ViewData ?? context.ViewData, context.Writer);
|
||||
var childViewContext = new ViewContext(
|
||||
viewContext,
|
||||
view,
|
||||
ViewData ?? context.ViewData,
|
||||
context.Writer);
|
||||
await view.RenderAsync(childViewContext);
|
||||
|
||||
_diagnosticSource.ViewComponentAfterViewExecute(context, view);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewEngines
|
||||
|
|
@ -64,14 +65,30 @@ namespace Microsoft.AspNet.Mvc.ViewEngines
|
|||
};
|
||||
}
|
||||
|
||||
public ViewEngineResult EnsureSuccessful()
|
||||
/// <summary>
|
||||
/// Ensure this <see cref="ViewEngineResult"/> was successful.
|
||||
/// </summary>
|
||||
/// <param name="originalLocations">
|
||||
/// Additional <see cref="SearchedLocations"/> to include in the thrown <see cref="InvalidOperationException"/>
|
||||
/// if <see cref="Success"/> is <c>false</c>.
|
||||
/// </param>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if <see cref="Success"/> is <c>false</c>.
|
||||
/// </exception>
|
||||
/// <returns>This <see cref="ViewEngineResult"/> if <see cref="Success"/> is <c>true</c>.</returns>
|
||||
public ViewEngineResult EnsureSuccessful(IEnumerable<string> originalLocations)
|
||||
{
|
||||
if (!Success)
|
||||
{
|
||||
var locations = string.Empty;
|
||||
if (SearchedLocations != null)
|
||||
if (originalLocations != null && originalLocations.Any())
|
||||
{
|
||||
locations = Environment.NewLine + string.Join(Environment.NewLine, SearchedLocations);
|
||||
locations = Environment.NewLine + string.Join(Environment.NewLine, originalLocations);
|
||||
}
|
||||
|
||||
if (SearchedLocations.Any())
|
||||
{
|
||||
locations += Environment.NewLine + string.Join(Environment.NewLine, SearchedLocations);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(Resources.FormatViewEngine_ViewNotFound(ViewName, locations));
|
||||
|
|
|
|||
|
|
@ -544,6 +544,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
ViewContext.ExecutingFilePath,
|
||||
partialViewName,
|
||||
isPartial: true);
|
||||
var originalLocations = viewEngineResult.SearchedLocations;
|
||||
if (!viewEngineResult.Success)
|
||||
{
|
||||
viewEngineResult = _viewEngine.FindView(ViewContext, partialViewName, isPartial: true);
|
||||
|
|
@ -552,10 +553,15 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
if (!viewEngineResult.Success)
|
||||
{
|
||||
var locations = string.Empty;
|
||||
if (viewEngineResult.SearchedLocations != null)
|
||||
if (originalLocations.Any())
|
||||
{
|
||||
locations = Environment.NewLine +
|
||||
string.Join(Environment.NewLine, viewEngineResult.SearchedLocations);
|
||||
locations = Environment.NewLine + string.Join(Environment.NewLine, originalLocations);
|
||||
}
|
||||
|
||||
if (viewEngineResult.SearchedLocations.Any())
|
||||
{
|
||||
locations +=
|
||||
Environment.NewLine + string.Join(Environment.NewLine, viewEngineResult.SearchedLocations);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
// 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.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Diagnostics;
|
||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||
|
|
@ -70,11 +72,31 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
var viewName = viewResult.ViewName ?? actionContext.ActionDescriptor.Name;
|
||||
|
||||
var result = viewEngine.GetView(executingFilePath: null, viewPath: viewName, isPartial: true);
|
||||
var originalResult = result;
|
||||
if (!result.Success)
|
||||
{
|
||||
result = viewEngine.FindView(actionContext, viewName, isPartial: true);
|
||||
}
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
if (originalResult.SearchedLocations.Any())
|
||||
{
|
||||
if (result.SearchedLocations.Any())
|
||||
{
|
||||
// Return a new ViewEngineResult listing all searched locations.
|
||||
var locations = new List<string>(originalResult.SearchedLocations);
|
||||
locations.AddRange(result.SearchedLocations);
|
||||
result = ViewEngineResult.NotFound(viewName, locations);
|
||||
}
|
||||
else
|
||||
{
|
||||
// GetView() searched locations but FindView() did not. Use first ViewEngineResult.
|
||||
result = originalResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
DiagnosticSource.ViewFound(actionContext, true, viewResult, viewName, result.View);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
// 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.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||
using Microsoft.AspNet.Mvc.Logging;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
|
||||
|
|
@ -69,11 +70,31 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
var viewName = viewResult.ViewName ?? actionContext.ActionDescriptor.Name;
|
||||
|
||||
var result = viewEngine.GetView(executingFilePath: null, viewPath: viewName, isPartial: false);
|
||||
var originalResult = result;
|
||||
if (!result.Success)
|
||||
{
|
||||
result = viewEngine.FindView(actionContext, viewName, isPartial: false);
|
||||
}
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
if (originalResult.SearchedLocations.Any())
|
||||
{
|
||||
if (result.SearchedLocations.Any())
|
||||
{
|
||||
// Return a new ViewEngineResult listing all searched locations.
|
||||
var locations = new List<string>(originalResult.SearchedLocations);
|
||||
locations.AddRange(result.SearchedLocations);
|
||||
result = ViewEngineResult.NotFound(viewName, locations);
|
||||
}
|
||||
else
|
||||
{
|
||||
// GetView() searched locations but FindView() did not. Use first ViewEngineResult.
|
||||
result = originalResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
if (DiagnosticSource.IsEnabled("Microsoft.AspNet.Mvc.ViewFound"))
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var executor = services.GetRequiredService<ViewResultExecutor>();
|
||||
|
||||
var result = executor.FindView(context, this);
|
||||
result.EnsureSuccessful();
|
||||
result.EnsureSuccessful(originalLocations: null);
|
||||
|
||||
var view = result.View;
|
||||
using (view as IDisposable)
|
||||
|
|
|
|||
|
|
@ -368,7 +368,50 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderAsync_ThrowsIfLayoutPageCannotBeFound()
|
||||
public async Task RenderAsync_ThrowsIfLayoutPageCannotBeFound_MessageUsesGetPageLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(
|
||||
Environment.NewLine,
|
||||
"The layout view 'Does-Not-Exist-Layout' could not be located. The following locations were searched:",
|
||||
"path1",
|
||||
"path2");
|
||||
|
||||
var layoutPath = "Does-Not-Exist-Layout";
|
||||
var page = new TestableRazorPage(v =>
|
||||
{
|
||||
v.Layout = layoutPath;
|
||||
});
|
||||
|
||||
var viewEngine = new Mock<IRazorViewEngine>(MockBehavior.Strict);
|
||||
var activator = new Mock<IRazorPageActivator>();
|
||||
var view = new RazorView(
|
||||
viewEngine.Object,
|
||||
Mock.Of<IRazorPageActivator>(),
|
||||
new IRazorPage[0],
|
||||
page,
|
||||
new HtmlTestEncoder(),
|
||||
isPartial: false);
|
||||
var viewContext = CreateViewContext(view);
|
||||
viewEngine
|
||||
.Setup(v => v.GetPage(/*executingFilePath*/ null, layoutPath, /*isPartial*/ true))
|
||||
.Returns(new RazorPageResult(layoutPath, new[] { "path1", "path2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindPage(viewContext, layoutPath, /*isPartial*/ true))
|
||||
.Returns(new RazorPageResult(layoutPath, Enumerable.Empty<string>()))
|
||||
.Verifiable();
|
||||
|
||||
// Act
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => view.RenderAsync(viewContext));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, ex.Message);
|
||||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderAsync_ThrowsIfLayoutPageCannotBeFound_MessageUsesFindPageLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(
|
||||
|
|
@ -410,6 +453,51 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderAsync_ThrowsIfLayoutPageCannotBeFound_MessageUsesAllLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(
|
||||
Environment.NewLine,
|
||||
"The layout view 'Does-Not-Exist-Layout' could not be located. The following locations were searched:",
|
||||
"path1",
|
||||
"path2",
|
||||
"path3",
|
||||
"path4");
|
||||
|
||||
var layoutPath = "Does-Not-Exist-Layout";
|
||||
var page = new TestableRazorPage(v =>
|
||||
{
|
||||
v.Layout = layoutPath;
|
||||
});
|
||||
|
||||
var viewEngine = new Mock<IRazorViewEngine>(MockBehavior.Strict);
|
||||
var activator = new Mock<IRazorPageActivator>();
|
||||
var view = new RazorView(
|
||||
viewEngine.Object,
|
||||
Mock.Of<IRazorPageActivator>(),
|
||||
new IRazorPage[0],
|
||||
page,
|
||||
new HtmlTestEncoder(),
|
||||
isPartial: false);
|
||||
var viewContext = CreateViewContext(view);
|
||||
viewEngine
|
||||
.Setup(v => v.GetPage(/*executingFilePath*/ null, layoutPath, /*isPartial*/ true))
|
||||
.Returns(new RazorPageResult(layoutPath, new[] { "path1", "path2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindPage(viewContext, layoutPath, /*isPartial*/ true))
|
||||
.Returns(new RazorPageResult(layoutPath, new[] { "path3", "path4" }))
|
||||
.Verifiable();
|
||||
|
||||
// Act
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => view.RenderAsync(viewContext));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, ex.Message);
|
||||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderAsync_ExecutesLayoutPages()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,14 +26,51 @@ namespace Microsoft.AspNet.Mvc
|
|||
public class PartialViewResultTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound()
|
||||
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesGetViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(
|
||||
Environment.NewLine,
|
||||
"The view 'MyView' was not found. The following locations were searched:",
|
||||
"Location1",
|
||||
"Location2.");
|
||||
"Location2");
|
||||
|
||||
var actionContext = GetActionContext();
|
||||
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, "MyView", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("MyView", new[] { "Location1", "Location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), "MyView", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("MyView", Enumerable.Empty<string>()))
|
||||
.Verifiable();
|
||||
|
||||
var viewResult = new PartialViewResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "MyView",
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act and Assert
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => viewResult.ExecuteResultAsync(actionContext));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesFindViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(
|
||||
Environment.NewLine,
|
||||
"The view 'MyView' was not found. The following locations were searched:",
|
||||
"Location1",
|
||||
"Location2");
|
||||
|
||||
var actionContext = GetActionContext();
|
||||
|
||||
|
|
@ -62,6 +99,45 @@ namespace Microsoft.AspNet.Mvc
|
|||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesAllLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(
|
||||
Environment.NewLine,
|
||||
"The view 'MyView' was not found. The following locations were searched:",
|
||||
"Location1",
|
||||
"Location2",
|
||||
"Location3",
|
||||
"Location4");
|
||||
|
||||
var actionContext = GetActionContext();
|
||||
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, "MyView", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("MyView", new[] { "Location1", "Location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), "MyView", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("MyView", new[] { "Location3", "Location4" }))
|
||||
.Verifiable();
|
||||
|
||||
var viewResult = new PartialViewResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "MyView",
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act and Assert
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => viewResult.ExecuteResultAsync(actionContext));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_FindsAndExecutesView()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@
|
|||
|
||||
#if MOCK_SUPPORT
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.TestCommon;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -188,6 +190,184 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(actual));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PartialAsync_Throws_IfViewNotFound_MessageUsesGetViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "The partial view 'test-view' was not found. The following locations were searched:" +
|
||||
Environment.NewLine +
|
||||
"location1" + Environment.NewLine +
|
||||
"location2";
|
||||
|
||||
var model = new TestModel();
|
||||
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", Enumerable.Empty<string>()))
|
||||
.Verifiable();
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
|
||||
var viewData = helper.ViewData;
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => helper.PartialAsync("test-view", model, viewData));
|
||||
Assert.Equal(expected, exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PartialAsync_Throws_IfViewNotFound_MessageUsesFindViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "The partial view 'test-view' was not found. The following locations were searched:" +
|
||||
Environment.NewLine +
|
||||
"location1" + Environment.NewLine +
|
||||
"location2";
|
||||
|
||||
var model = new TestModel();
|
||||
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", Enumerable.Empty<string>()))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
|
||||
var viewData = helper.ViewData;
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => helper.PartialAsync("test-view", model, viewData));
|
||||
Assert.Equal(expected, exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PartialAsync_Throws_IfViewNotFound_MessageUsesAllLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "The partial view 'test-view' was not found. The following locations were searched:" +
|
||||
Environment.NewLine +
|
||||
"location1" + Environment.NewLine +
|
||||
"location2" + Environment.NewLine +
|
||||
"location3" + Environment.NewLine +
|
||||
"location4";
|
||||
|
||||
var model = new TestModel();
|
||||
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", new[] { "location3", "location4" }))
|
||||
.Verifiable();
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
|
||||
var viewData = helper.ViewData;
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => helper.PartialAsync("test-view", model, viewData));
|
||||
Assert.Equal(expected, exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderPartialAsync_Throws_IfViewNotFound_MessageUsesGetViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "The partial view 'test-view' was not found. The following locations were searched:" +
|
||||
Environment.NewLine +
|
||||
"location1" + Environment.NewLine +
|
||||
"location2";
|
||||
|
||||
var model = new TestModel();
|
||||
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", Enumerable.Empty<string>()))
|
||||
.Verifiable();
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
|
||||
var viewData = helper.ViewData;
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => helper.RenderPartialAsync("test-view", model, viewData));
|
||||
Assert.Equal(expected, exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderPartialAsync_Throws_IfViewNotFound_MessageUsesFindViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "The partial view 'test-view' was not found. The following locations were searched:" +
|
||||
Environment.NewLine +
|
||||
"location1" + Environment.NewLine +
|
||||
"location2";
|
||||
|
||||
var model = new TestModel();
|
||||
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", Enumerable.Empty<string>()))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
|
||||
var viewData = helper.ViewData;
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => helper.RenderPartialAsync("test-view", model, viewData));
|
||||
Assert.Equal(expected, exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderPartialAsync_Throws_IfViewNotFound_MessageUsesAllLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "The partial view 'test-view' was not found. The following locations were searched:" +
|
||||
Environment.NewLine +
|
||||
"location1" + Environment.NewLine +
|
||||
"location2" + Environment.NewLine +
|
||||
"location3" + Environment.NewLine +
|
||||
"location4";
|
||||
|
||||
var model = new TestModel();
|
||||
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("test-view", new[] { "location3", "location4" }))
|
||||
.Verifiable();
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
|
||||
var viewData = helper.ViewData;
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => helper.RenderPartialAsync("test-view", model, viewData));
|
||||
Assert.Equal(expected, exception.Message);
|
||||
}
|
||||
|
||||
private sealed class TestModel
|
||||
{
|
||||
public override string ToString()
|
||||
|
|
|
|||
|
|
@ -143,13 +143,51 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_ThrowsIfPartialViewCannotBeFound()
|
||||
public void Execute_ThrowsIfPartialViewCannotBeFound_MessageUsesGetViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(Environment.NewLine,
|
||||
"The view 'Components/Invoke/some-view' was not found. The following locations were searched:",
|
||||
"location1",
|
||||
"location2.");
|
||||
"location2");
|
||||
|
||||
var view = Mock.Of<IView>();
|
||||
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, "some-view", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("some-view", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), "Components/Invoke/some-view", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("Components/Invoke/some-view", Enumerable.Empty<string>()))
|
||||
.Verifiable();
|
||||
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
|
||||
var result = new ViewViewComponentResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "some-view",
|
||||
ViewData = viewData,
|
||||
TempData = _tempDataDictionary,
|
||||
};
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(view, viewData);
|
||||
|
||||
// Act and Assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => result.Execute(viewComponentContext));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_ThrowsIfPartialViewCannotBeFound_MessageUsesFindViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(Environment.NewLine,
|
||||
"The view 'Components/Invoke/some-view' was not found. The following locations were searched:",
|
||||
"location1",
|
||||
"location2");
|
||||
|
||||
var view = Mock.Of<IView>();
|
||||
|
||||
|
|
@ -180,6 +218,46 @@ namespace Microsoft.AspNet.Mvc
|
|||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_ThrowsIfPartialViewCannotBeFound_MessageUsesAllLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(Environment.NewLine,
|
||||
"The view 'Components/Invoke/some-view' was not found. The following locations were searched:",
|
||||
"location1",
|
||||
"location2",
|
||||
"location3",
|
||||
"location4");
|
||||
|
||||
var view = Mock.Of<IView>();
|
||||
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, "some-view", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("some-view", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), "Components/Invoke/some-view", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("Components/Invoke/some-view", new[] { "location3", "location4" }))
|
||||
.Verifiable();
|
||||
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
|
||||
var result = new ViewViewComponentResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "some-view",
|
||||
ViewData = viewData,
|
||||
TempData = _tempDataDictionary,
|
||||
};
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(view, viewData);
|
||||
|
||||
// Act and Assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => result.Execute(viewComponentContext));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_DoesNotWrapThrownExceptionsInAggregateExceptions()
|
||||
{
|
||||
|
|
@ -305,20 +383,22 @@ namespace Microsoft.AspNet.Mvc
|
|||
var expected = string.Join(Environment.NewLine,
|
||||
"The view 'Components/Invoke/some-view' was not found. The following locations were searched:",
|
||||
"view-location1",
|
||||
"view-location2.");
|
||||
"view-location2",
|
||||
"view-location3",
|
||||
"view-location4");
|
||||
|
||||
var view = Mock.Of<IView>();
|
||||
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(v => v.GetView(/*executingFilePath*/ null, "some-view", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("some-view", Enumerable.Empty<string>()))
|
||||
.Returns(ViewEngineResult.NotFound("some-view", new[] { "view-location1", "view-location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), "Components/Invoke/some-view", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound(
|
||||
"Components/Invoke/some-view",
|
||||
new[] { "view-location1", "view-location2" }))
|
||||
new[] { "view-location3", "view-location4" }))
|
||||
.Verifiable();
|
||||
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
|
|
@ -423,7 +503,10 @@ namespace Microsoft.AspNet.Mvc
|
|||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
private static ViewComponentContext GetViewComponentContext(IView view, ViewDataDictionary viewData, object diagnosticListener = null)
|
||||
private static ViewComponentContext GetViewComponentContext(
|
||||
IView view,
|
||||
ViewDataDictionary viewData,
|
||||
object diagnosticListener = null)
|
||||
{
|
||||
var diagnosticSource = new DiagnosticListener("Microsoft.AspNet");
|
||||
if (diagnosticListener == null)
|
||||
|
|
|
|||
|
|
@ -76,6 +76,111 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
Assert.Equal(viewName, viewEngineResult.ViewName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindView_ReturnsExpectedNotFoundResult_WithGetViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expectedLocations = new[] { "location1", "location2" };
|
||||
var context = GetActionContext();
|
||||
var executor = GetViewExecutor();
|
||||
|
||||
var viewName = "myview";
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(e => e.GetView(/*executingFilePath*/ null, "myview", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("myview", expectedLocations))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(e => e.FindView(context, "myview", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("myview", Enumerable.Empty<string>()));
|
||||
|
||||
var viewResult = new PartialViewResult
|
||||
{
|
||||
ViewName = viewName,
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = executor.FindView(context, viewResult);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Success);
|
||||
Assert.Null(result.View);
|
||||
Assert.Equal(expectedLocations, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindView_ReturnsExpectedNotFoundResult_WithFindViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expectedLocations = new[] { "location1", "location2" };
|
||||
var context = GetActionContext();
|
||||
var executor = GetViewExecutor();
|
||||
|
||||
var viewName = "myview";
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(e => e.GetView(/*executingFilePath*/ null, "myview", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("myview", Enumerable.Empty<string>()))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(e => e.FindView(context, "myview", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("myview", expectedLocations));
|
||||
|
||||
var viewResult = new PartialViewResult
|
||||
{
|
||||
ViewName = viewName,
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = executor.FindView(context, viewResult);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Success);
|
||||
Assert.Null(result.View);
|
||||
Assert.Equal(expectedLocations, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindView_ReturnsExpectedNotFoundResult_WithAllLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expectedLocations = new[] { "location1", "location2", "location3", "location4" };
|
||||
var context = GetActionContext();
|
||||
var executor = GetViewExecutor();
|
||||
|
||||
var viewName = "myview";
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(e => e.GetView(/*executingFilePath*/ null, "myview", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("myview", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(e => e.FindView(context, "myview", /*isPartial*/ true))
|
||||
.Returns(ViewEngineResult.NotFound("myview", new[] { "location3", "location4" }));
|
||||
|
||||
var viewResult = new PartialViewResult
|
||||
{
|
||||
ViewName = viewName,
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = executor.FindView(context, viewResult);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Success);
|
||||
Assert.Null(result.View);
|
||||
Assert.Equal(expectedLocations, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindView_WritesDiagnostic_ViewFound()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -76,6 +76,108 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
Assert.Equal(viewName, viewEngineResult.ViewName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindView_ReturnsExpectedNotFoundResult_WithGetViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expectedLocations = new[] { "location1", "location2" };
|
||||
var context = GetActionContext();
|
||||
var executor = GetViewExecutor();
|
||||
|
||||
var viewName = "myview";
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(e => e.GetView(/*executingFilePath*/ null, "myview", /*isPartial*/ false))
|
||||
.Returns(ViewEngineResult.NotFound("myview", expectedLocations));
|
||||
viewEngine
|
||||
.Setup(e => e.FindView(context, "myview", /*isPartial*/ false))
|
||||
.Returns(ViewEngineResult.NotFound("myview", Enumerable.Empty<string>()));
|
||||
|
||||
var viewResult = new ViewResult
|
||||
{
|
||||
ViewName = viewName,
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = executor.FindView(context, viewResult);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Success);
|
||||
Assert.Null(result.View);
|
||||
Assert.Equal(expectedLocations, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindView_ReturnsExpectedNotFoundResult_WithFindViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expectedLocations = new[] { "location1", "location2" };
|
||||
var context = GetActionContext();
|
||||
var executor = GetViewExecutor();
|
||||
|
||||
var viewName = "myview";
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(e => e.GetView(/*executingFilePath*/ null, "myview", /*isPartial*/ false))
|
||||
.Returns(ViewEngineResult.NotFound("myview", Enumerable.Empty<string>()));
|
||||
viewEngine
|
||||
.Setup(e => e.FindView(context, "myview", /*isPartial*/ false))
|
||||
.Returns(ViewEngineResult.NotFound("myview", expectedLocations));
|
||||
|
||||
var viewResult = new ViewResult
|
||||
{
|
||||
ViewName = viewName,
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = executor.FindView(context, viewResult);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Success);
|
||||
Assert.Null(result.View);
|
||||
Assert.Equal(expectedLocations, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindView_ReturnsExpectedNotFoundResult_WithAllLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expectedLocations = new[] { "location1", "location2", "location3", "location4" };
|
||||
var context = GetActionContext();
|
||||
var executor = GetViewExecutor();
|
||||
|
||||
var viewName = "myview";
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(e => e.GetView(/*executingFilePath*/ null, "myview", /*isPartial*/ false))
|
||||
.Returns(ViewEngineResult.NotFound("myview", new[] { "location1", "location2" }));
|
||||
viewEngine
|
||||
.Setup(e => e.FindView(context, "myview", /*isPartial*/ false))
|
||||
.Returns(ViewEngineResult.NotFound("myview", new[] { "location3", "location4" }));
|
||||
|
||||
var viewResult = new ViewResult
|
||||
{
|
||||
ViewName = viewName,
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = executor.FindView(context, viewResult);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Success);
|
||||
Assert.Null(result.View);
|
||||
Assert.Equal(expectedLocations, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindView_WritesDiagnostic_ViewFound()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,14 +26,51 @@ namespace Microsoft.AspNet.Mvc
|
|||
public class ViewResultTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound()
|
||||
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesGetViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(
|
||||
Environment.NewLine,
|
||||
"The view 'MyView' was not found. The following locations were searched:",
|
||||
"Location1",
|
||||
"Location2.");
|
||||
"Location2");
|
||||
|
||||
var actionContext = GetActionContext();
|
||||
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(e => e.GetView(/*executingFilePath*/ null, "MyView", /*isPartial*/ false))
|
||||
.Returns(ViewEngineResult.NotFound("MyView", new[] { "Location1", "Location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isPartial*/ false))
|
||||
.Returns(ViewEngineResult.NotFound("MyView", Enumerable.Empty<string>()))
|
||||
.Verifiable();
|
||||
|
||||
var viewResult = new ViewResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "MyView",
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act and Assert
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => viewResult.ExecuteResultAsync(actionContext));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesFindViewLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(
|
||||
Environment.NewLine,
|
||||
"The view 'MyView' was not found. The following locations were searched:",
|
||||
"Location1",
|
||||
"Location2");
|
||||
|
||||
var actionContext = GetActionContext();
|
||||
|
||||
|
|
@ -62,6 +99,45 @@ namespace Microsoft.AspNet.Mvc
|
|||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesAllLocations()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(
|
||||
Environment.NewLine,
|
||||
"The view 'MyView' was not found. The following locations were searched:",
|
||||
"Location1",
|
||||
"Location2",
|
||||
"Location3",
|
||||
"Location4");
|
||||
|
||||
var actionContext = GetActionContext();
|
||||
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine
|
||||
.Setup(e => e.GetView(/*executingFilePath*/ null, "MyView", /*isPartial*/ false))
|
||||
.Returns(ViewEngineResult.NotFound("MyView", new[] { "Location1", "Location2" }))
|
||||
.Verifiable();
|
||||
viewEngine
|
||||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isPartial*/ false))
|
||||
.Returns(ViewEngineResult.NotFound("MyView", new[] { "Location3", "Location4" }))
|
||||
.Verifiable();
|
||||
|
||||
var viewResult = new ViewResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "MyView",
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act and Assert
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => viewResult.ExecuteResultAsync(actionContext));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_FindsAndExecutesView()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue