Layout specification and discovery should follow the same behavior as
partials Fixes #1047
This commit is contained in:
parent
765f113515
commit
933f7eeb22
|
|
@ -0,0 +1,47 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>@ViewBag.Title - Ma Demande ASP.NET</title>
|
||||||
|
<link rel="stylesheet" href="~/content/bootstrap.min.css" />
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
padding-top: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@media screen and (max-width: 768px) {
|
||||||
|
body {
|
||||||
|
padding-top: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@await RenderSectionAsync("header", required: false)
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-collapse collapse">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li><a href="/">Accueil</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="container body-content">
|
||||||
|
@RenderBody()
|
||||||
|
<hr />
|
||||||
|
<footer>
|
||||||
|
<p>© @DateTime.Now.Year - Mon Application ASP.NET</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
@await RenderSectionAsync("footer", required: false)
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
@{
|
@{
|
||||||
Layout = "/Views/Shared/_Layout.cshtml";
|
Layout = "_Layout";
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
// 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.Rendering;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="IViewEngine"/> used to render pages that use the Razor syntax.
|
||||||
|
/// </summary>
|
||||||
|
public interface IRazorViewEngine : IViewEngine
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a <see cref="IRazorPage"/> using the same view discovery semantics used in
|
||||||
|
/// <see cref="IViewEngine.FindPartialView(ActionContext, string)"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The <see cref="ActionContext"/>.</param>
|
||||||
|
/// <param name="viewName">The name or full path to the view.</param>
|
||||||
|
/// <returns>A result representing the result of locating the <see cref="IRazorPage"/>.</returns>
|
||||||
|
RazorPageResult FindPage(ActionContext context, string page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,9 +13,11 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="RazorView"/> providing it with the <see cref="IRazorPage"/> to execute.
|
/// Creates a <see cref="RazorView"/> providing it with the <see cref="IRazorPage"/> to execute.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="viewEngine">The <see cref="IRazorViewEngine"/> that was used to locate Layout pages
|
||||||
|
/// that will be part of <paramref name="page"/>'s execution.</param>
|
||||||
/// <param name="page">The <see cref="IRazorPage"/> instance to execute.</param>
|
/// <param name="page">The <see cref="IRazorPage"/> instance to execute.</param>
|
||||||
/// <param name="isPartial">Determines if the view is to be executed as a partial.</param>
|
/// <param name="isPartial">Determines if the view is to be executed as a partial.</param>
|
||||||
/// <returns>A <see cref="IView"/> instance that renders the contents of the <paramref name="page"/></returns>
|
/// <returns>A <see cref="IView"/> instance that renders the contents of the <paramref name="page"/></returns>
|
||||||
IView GetView([NotNull] IRazorPage page, bool isPartial);
|
IView GetView([NotNull] IRazorViewEngine viewEngine, [NotNull] IRazorPage page, bool isPartial);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The layout view '{0}' could not be located.
|
/// The layout view '{0}' could not be located. The following locations were searched:{1}
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string LayoutCannotBeLocated
|
internal static string LayoutCannotBeLocated
|
||||||
{
|
{
|
||||||
|
|
@ -83,11 +83,11 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The layout view '{0}' could not be located.
|
/// The layout view '{0}' could not be located. The following locations were searched:{1}
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string FormatLayoutCannotBeLocated(object p0)
|
internal static string FormatLayoutCannotBeLocated(object p0, object p1)
|
||||||
{
|
{
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("LayoutCannotBeLocated"), p0);
|
return string.Format(CultureInfo.CurrentCulture, GetString("LayoutCannotBeLocated"), p0, p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
// 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.Razor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the results of locating a <see cref="IRazorPage"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class RazorPageResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="RazorPageResult"/> for a successful discovery.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the page that was located.</param>
|
||||||
|
/// <param name="page">The located <see cref="IRazorPage"/>.</param>
|
||||||
|
public RazorPageResult([NotNull] string name, [NotNull] IRazorPage page)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Page = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="RazorPageResult"/> for an unsuccessful discovery.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the page that was located.</param>
|
||||||
|
/// <param name="page">The locations that were searched.</param>
|
||||||
|
public RazorPageResult([NotNull] string name, [NotNull] IEnumerable<string> searchedLocations)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
SearchedLocations = searchedLocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the page being located.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This property maps to the <c>name</c> parameter of
|
||||||
|
/// <see cref="IRazorViewEngine.FindPage(ActionContext, string)"/>.</remarks>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="IRazorPage"/> if found.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This property is <c>null</c> if the page was not found.</remarks>
|
||||||
|
public IRazorPage Page { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the locations that were searched when <see cref="Page"/> could not be located.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This property is <c>null</c> if the page was found.</remarks>
|
||||||
|
public IEnumerable<string> SearchedLocations { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,28 +15,28 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RazorView : IView
|
public class RazorView : IView
|
||||||
{
|
{
|
||||||
private readonly IRazorPageFactory _pageFactory;
|
private readonly IRazorViewEngine _viewEngine;
|
||||||
private readonly IRazorPageActivator _pageActivator;
|
private readonly IRazorPageActivator _pageActivator;
|
||||||
private readonly IViewStartProvider _viewStartProvider;
|
private readonly IViewStartProvider _viewStartProvider;
|
||||||
private IPageExecutionListenerFeature _pageExecutionFeature;
|
private IPageExecutionListenerFeature _pageExecutionFeature;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of RazorView
|
/// Initializes a new instance of <see cref="RazorView"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageFactory">The page factory used to instantiate layout and _ViewStart pages.</param>
|
/// <param name="viewEngine">The <see cref="IRazorViewEngine"/> used to locate Layout pages.</param>
|
||||||
/// <param name="pageActivator">The <see cref="IRazorPageActivator"/> used to activate pages.</param>
|
/// <param name="pageActivator">The <see cref="IRazorPageActivator"/> used to activate pages.</param>
|
||||||
/// <param name="viewStartProvider">The <see cref="IViewStartProvider"/> used for discovery of _ViewStart
|
/// <param name="viewStartProvider">The <see cref="IViewStartProvider"/> used for discovery of _ViewStart
|
||||||
/// <param name="razorPage">The <see cref="IRazorPage"/> instance to execute.</param>
|
/// <param name="razorPage">The <see cref="IRazorPage"/> instance to execute.</param>
|
||||||
/// <param name="isPartial">Determines if the view is to be executed as a partial.</param>
|
/// <param name="isPartial">Determines if the view is to be executed as a partial.</param>
|
||||||
/// pages</param>
|
/// pages</param>
|
||||||
public RazorView(IRazorPageFactory pageFactory,
|
public RazorView(IRazorViewEngine viewEngine,
|
||||||
IRazorPageActivator pageActivator,
|
IRazorPageActivator pageActivator,
|
||||||
IViewStartProvider viewStartProvider,
|
IViewStartProvider viewStartProvider,
|
||||||
IRazorPage razorPage,
|
IRazorPage razorPage,
|
||||||
bool isPartial
|
bool isPartial
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_pageFactory = pageFactory;
|
_viewEngine = viewEngine;
|
||||||
_pageActivator = pageActivator;
|
_pageActivator = pageActivator;
|
||||||
_viewStartProvider = viewStartProvider;
|
_viewStartProvider = viewStartProvider;
|
||||||
RazorPage = razorPage;
|
RazorPage = razorPage;
|
||||||
|
|
@ -186,12 +186,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
throw new InvalidOperationException(message);
|
throw new InvalidOperationException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
var layoutPage = _pageFactory.CreateInstance(previousPage.Layout);
|
var layoutPage = GetLayoutPage(context, previousPage.Layout);
|
||||||
if (layoutPage == null)
|
|
||||||
{
|
|
||||||
var message = Resources.FormatLayoutCannotBeLocated(previousPage.Layout);
|
|
||||||
throw new InvalidOperationException(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify the previous page that any writes that are performed on it are part of sections being written
|
// Notify the previous page that any writes that are performed on it are part of sections being written
|
||||||
// in the layout.
|
// in the layout.
|
||||||
|
|
@ -212,5 +207,19 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
await bodyWriter.CopyToAsync(context.Writer);
|
await bodyWriter.CopyToAsync(context.Writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IRazorPage GetLayoutPage(ViewContext context, string layoutPath)
|
||||||
|
{
|
||||||
|
var layoutPageResult = _viewEngine.FindPage(context, layoutPath);
|
||||||
|
if (layoutPageResult.Page == null)
|
||||||
|
{
|
||||||
|
var locations = Environment.NewLine +
|
||||||
|
string.Join(Environment.NewLine, layoutPageResult.SearchedLocations);
|
||||||
|
throw new InvalidOperationException(Resources.FormatLayoutCannotBeLocated(layoutPath, locations));
|
||||||
|
}
|
||||||
|
|
||||||
|
var layoutPage = layoutPageResult.Page;
|
||||||
|
return layoutPage;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ using Microsoft.AspNet.Mvc.Rendering;
|
||||||
namespace Microsoft.AspNet.Mvc.Razor
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a view engine that is used to render a page that uses the Razor syntax.
|
/// Default implementation of <see cref="IRazorViewEngine"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RazorViewEngine : IViewEngine
|
public class RazorViewEngine : IRazorViewEngine
|
||||||
{
|
{
|
||||||
private const string ViewExtension = ".cshtml";
|
private const string ViewExtension = ".cshtml";
|
||||||
internal const string ControllerKey = "controller";
|
internal const string ControllerKey = "controller";
|
||||||
|
|
@ -78,7 +78,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(viewName));
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(viewName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateViewEngineResult(context, viewName, partial: false);
|
var pageResult = GetRazorPageResult(context, viewName);
|
||||||
|
return CreateViewEngineResult(pageResult, _viewFactory, isPartial: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -90,36 +91,49 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(partialViewName));
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(partialViewName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateViewEngineResult(context, partialViewName, partial: true);
|
var pageResult = GetRazorPageResult(context, partialViewName);
|
||||||
|
return CreateViewEngineResult(pageResult, _viewFactory, isPartial: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ViewEngineResult CreateViewEngineResult(ActionContext context,
|
/// <inheritdoc />
|
||||||
string viewName,
|
public RazorPageResult FindPage([NotNull] ActionContext context,
|
||||||
bool partial)
|
string pageName)
|
||||||
{
|
{
|
||||||
var nameRepresentsPath = IsSpecificPath(viewName);
|
if (string.IsNullOrEmpty(pageName))
|
||||||
|
|
||||||
if (nameRepresentsPath)
|
|
||||||
{
|
{
|
||||||
if (viewName.EndsWith(ViewExtension, StringComparison.OrdinalIgnoreCase))
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(pageName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetRazorPageResult(context, pageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RazorPageResult GetRazorPageResult(ActionContext context,
|
||||||
|
string pageName)
|
||||||
|
{
|
||||||
|
if (IsApplicationRelativePath(pageName))
|
||||||
|
{
|
||||||
|
var applicationRelativePath = pageName;
|
||||||
|
if (!pageName.EndsWith(ViewExtension, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var page = _pageFactory.CreateInstance(viewName);
|
applicationRelativePath += ViewExtension;
|
||||||
if (page != null)
|
|
||||||
{
|
|
||||||
return CreateFoundResult(context, page, viewName, partial);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ViewEngineResult.NotFound(viewName, new[] { viewName });
|
|
||||||
|
var page = _pageFactory.CreateInstance(applicationRelativePath);
|
||||||
|
if (page != null)
|
||||||
|
{
|
||||||
|
return new RazorPageResult(pageName, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RazorPageResult(pageName, new[] { pageName });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return LocateViewFromViewLocations(context, viewName, partial);
|
return LocatePageFromViewLocations(context, pageName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ViewEngineResult LocateViewFromViewLocations(ActionContext context,
|
private RazorPageResult LocatePageFromViewLocations(ActionContext context,
|
||||||
string viewName,
|
string pageName)
|
||||||
bool partial)
|
|
||||||
{
|
{
|
||||||
// Initialize the dictionary for the typical case of having controller and action tokens.
|
// Initialize the dictionary for the typical case of having controller and action tokens.
|
||||||
var routeValues = context.RouteData.Values;
|
var routeValues = context.RouteData.Values;
|
||||||
|
|
@ -129,7 +143,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
var viewLocations = !string.IsNullOrEmpty(areaName) ? AreaViewLocationFormats :
|
var viewLocations = !string.IsNullOrEmpty(areaName) ? AreaViewLocationFormats :
|
||||||
ViewLocationFormats;
|
ViewLocationFormats;
|
||||||
|
|
||||||
var expanderContext = new ViewLocationExpanderContext(context, viewName);
|
var expanderContext = new ViewLocationExpanderContext(context, pageName);
|
||||||
if (_viewLocationExpanders.Count > 0)
|
if (_viewLocationExpanders.Count > 0)
|
||||||
{
|
{
|
||||||
expanderContext.Values = new Dictionary<string, string>(StringComparer.Ordinal);
|
expanderContext.Values = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||||
|
|
@ -142,15 +156,15 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. With the values that we've accumumlated so far, check if we have a cached result.
|
// 2. With the values that we've accumumlated so far, check if we have a cached result.
|
||||||
var viewLocation = _viewLocationCache.Get(expanderContext);
|
var pageLocation = _viewLocationCache.Get(expanderContext);
|
||||||
if (!string.IsNullOrEmpty(viewLocation))
|
if (!string.IsNullOrEmpty(pageLocation))
|
||||||
{
|
{
|
||||||
var page = _pageFactory.CreateInstance(viewLocation);
|
var page = _pageFactory.CreateInstance(pageLocation);
|
||||||
|
|
||||||
if (page != null)
|
if (page != null)
|
||||||
{
|
{
|
||||||
// 2a. We found a IRazorPage at the cached location.
|
// 2a. We found a IRazorPage at the cached location.
|
||||||
return CreateFoundResult(context, page, viewName, partial);
|
return new RazorPageResult(pageName, page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,7 +182,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
var transformedPath = string.Format(CultureInfo.InvariantCulture,
|
var transformedPath = string.Format(CultureInfo.InvariantCulture,
|
||||||
path,
|
path,
|
||||||
viewName,
|
pageName,
|
||||||
controllerName,
|
controllerName,
|
||||||
areaName);
|
areaName);
|
||||||
var page = _pageFactory.CreateInstance(transformedPath);
|
var page = _pageFactory.CreateInstance(transformedPath);
|
||||||
|
|
@ -176,32 +190,30 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
// 3a. We found a page. Cache the set of values that produced it and return a found result.
|
// 3a. We found a page. Cache the set of values that produced it and return a found result.
|
||||||
_viewLocationCache.Set(expanderContext, transformedPath);
|
_viewLocationCache.Set(expanderContext, transformedPath);
|
||||||
return CreateFoundResult(context, page, transformedPath, partial);
|
return new RazorPageResult(pageName, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
searchedLocations.Add(transformedPath);
|
searchedLocations.Add(transformedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3b. We did not find a page for any of the paths.
|
// 3b. We did not find a page for any of the paths.
|
||||||
return ViewEngineResult.NotFound(viewName, searchedLocations);
|
return new RazorPageResult(pageName, searchedLocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ViewEngineResult CreateFoundResult(ActionContext actionContext,
|
private ViewEngineResult CreateViewEngineResult(RazorPageResult result,
|
||||||
IRazorPage page,
|
IRazorViewFactory razorViewFactory,
|
||||||
string viewName,
|
bool isPartial)
|
||||||
bool partial)
|
|
||||||
{
|
{
|
||||||
// A single request could result in creating multiple IRazorView instances (for partials, view components)
|
if (result.SearchedLocations != null)
|
||||||
// and might store state. We'll use the service container to create new instances as we require.
|
{
|
||||||
|
return ViewEngineResult.NotFound(result.Name, result.SearchedLocations);
|
||||||
|
}
|
||||||
|
|
||||||
var services = actionContext.HttpContext.RequestServices;
|
var view = razorViewFactory.GetView(this, result.Page, isPartial);
|
||||||
|
return ViewEngineResult.Found(result.Name, view);
|
||||||
var view = _viewFactory.GetView(page, partial);
|
|
||||||
|
|
||||||
return ViewEngineResult.Found(viewName, view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsSpecificPath(string name)
|
private static bool IsApplicationRelativePath(string name)
|
||||||
{
|
{
|
||||||
Debug.Assert(!string.IsNullOrEmpty(name));
|
Debug.Assert(!string.IsNullOrEmpty(name));
|
||||||
return name[0] == '~' || name[0] == '/';
|
return name[0] == '~' || name[0] == '/';
|
||||||
|
|
|
||||||
|
|
@ -12,29 +12,27 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
public class RazorViewFactory : IRazorViewFactory
|
public class RazorViewFactory : IRazorViewFactory
|
||||||
{
|
{
|
||||||
private readonly IRazorPageActivator _pageActivator;
|
private readonly IRazorPageActivator _pageActivator;
|
||||||
private readonly IRazorPageFactory _pageFactory;
|
|
||||||
private readonly IViewStartProvider _viewStartProvider;
|
private readonly IViewStartProvider _viewStartProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of RazorViewFactory
|
/// Initializes a new instance of RazorViewFactory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageFactory">The page factory used to instantiate layout and _ViewStart pages.</param>
|
|
||||||
/// <param name="pageActivator">The <see cref="IRazorPageActivator"/> used to activate pages.</param>
|
/// <param name="pageActivator">The <see cref="IRazorPageActivator"/> used to activate pages.</param>
|
||||||
/// <param name="viewStartProvider">The <see cref="IViewStartProvider"/> used for discovery of _ViewStart
|
/// <param name="viewStartProvider">The <see cref="IViewStartProvider"/> used for discovery of _ViewStart
|
||||||
/// pages</param>
|
/// pages</param>
|
||||||
public RazorViewFactory(IRazorPageFactory pageFactory,
|
public RazorViewFactory(IRazorPageActivator pageActivator,
|
||||||
IRazorPageActivator pageActivator,
|
|
||||||
IViewStartProvider viewStartProvider)
|
IViewStartProvider viewStartProvider)
|
||||||
{
|
{
|
||||||
_pageFactory = pageFactory;
|
|
||||||
_pageActivator = pageActivator;
|
_pageActivator = pageActivator;
|
||||||
_viewStartProvider = viewStartProvider;
|
_viewStartProvider = viewStartProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IView GetView([NotNull] IRazorPage page, bool isPartial)
|
public IView GetView([NotNull] IRazorViewEngine viewEngine,
|
||||||
|
[NotNull] IRazorPage page,
|
||||||
|
bool isPartial)
|
||||||
{
|
{
|
||||||
var razorView = new RazorView(_pageFactory, _pageActivator, _viewStartProvider, page, isPartial);
|
var razorView = new RazorView(viewEngine, _pageActivator, _viewStartProvider, page, isPartial);
|
||||||
return razorView;
|
return razorView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@
|
||||||
<value>The {0} returned by '{1}' must be an instance of '{2}'.</value>
|
<value>The {0} returned by '{1}' must be an instance of '{2}'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LayoutCannotBeLocated" xml:space="preserve">
|
<data name="LayoutCannotBeLocated" xml:space="preserve">
|
||||||
<value>The layout view '{0}' could not be located.</value>
|
<value>The layout view '{0}' could not be located. The following locations were searched:{1}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LayoutCannotBeRendered" xml:space="preserve">
|
<data name="LayoutCannotBeRendered" xml:space="preserve">
|
||||||
<value>A layout page cannot be rendered after '{0}' has been invoked.</value>
|
<value>A layout page cannot be rendered after '{0}' has been invoked.</value>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
// 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.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Builder;
|
||||||
|
using Microsoft.AspNet.TestHost;
|
||||||
|
using RazorWebSite;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
|
{
|
||||||
|
public class RazorViewLocationSpecificationTest
|
||||||
|
{
|
||||||
|
private const string BaseUrl = "http://localhost/ViewNameSpecification_Home/";
|
||||||
|
private readonly IServiceProvider _provider = TestHelper.CreateServices("RazorWebSite");
|
||||||
|
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("LayoutSpecifiedWithPartialPathInViewStart")]
|
||||||
|
[InlineData("LayoutSpecifiedWithPartialPathInViewStart_ForViewSpecifiedWithAppRelativePath")]
|
||||||
|
[InlineData("LayoutSpecifiedWithPartialPathInViewStart_ForViewSpecifiedWithPartialName")]
|
||||||
|
[InlineData("LayoutSpecifiedWithPartialPathInViewStart_ForViewSpecifiedWithAppRelativePathWithExtension")]
|
||||||
|
public async Task PartialLayoutPaths_SpecifiedInViewStarts_GetResolvedByViewEngine(string action)
|
||||||
|
{
|
||||||
|
var expected =
|
||||||
|
@"<layout>
|
||||||
|
_ViewStart that specifies partial Layout
|
||||||
|
</layout>";
|
||||||
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = await client.GetStringAsync(BaseUrl + action);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, body.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("LayoutSpecifiedWithPartialPathInPage")]
|
||||||
|
[InlineData("LayoutSpecifiedWithPartialPathInPageWithPartialPath")]
|
||||||
|
[InlineData("LayoutSpecifiedWithPartialPathInPageWithAppRelativePath")]
|
||||||
|
[InlineData("LayoutSpecifiedWithPartialPathInPageWithAppRelativePathWithExtension")]
|
||||||
|
public async Task PartialLayoutPaths_SpecifiedInPage_GetResolvedByViewEngine(string actionName)
|
||||||
|
{
|
||||||
|
var expected =
|
||||||
|
@"<non-shared>
|
||||||
|
Layout specified in page
|
||||||
|
</non-shared>";
|
||||||
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = await client.GetStringAsync(BaseUrl + actionName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, body.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("LayoutSpecifiedWithNonPartialPath")]
|
||||||
|
[InlineData("LayoutSpecifiedWithNonPartialPathWithExtension")]
|
||||||
|
public async Task NonPartialLayoutPaths_GetResolvedByViewEngine(string actionName)
|
||||||
|
{
|
||||||
|
var expected =
|
||||||
|
@"<non-shared>
|
||||||
|
Page With Non Partial Layout
|
||||||
|
</non-shared>";
|
||||||
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = await client.GetStringAsync(BaseUrl + actionName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, body.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("ViewWithPartial_SpecifiedWithPartialName")]
|
||||||
|
[InlineData("ViewWithPartial_SpecifiedWithAbsoluteName")]
|
||||||
|
[InlineData("ViewWithPartial_SpecifiedWithAbsoluteNameAndExtension")]
|
||||||
|
public async Task PartialsCanBeSpecifiedWithPartialPath(string actionName)
|
||||||
|
{
|
||||||
|
var expected =
|
||||||
|
@"<layout>
|
||||||
|
|
||||||
|
Non Shared Partial
|
||||||
|
|
||||||
|
</layout>";
|
||||||
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = await client.GetStringAsync(BaseUrl + actionName);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, body.Trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -216,6 +216,43 @@ component-content";
|
||||||
Assert.Equal(expected, body.Trim());
|
Assert.Equal(expected, body.Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<object[]> RazorViewEngine_UsesExpandersForLayoutsData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var expected1 =
|
||||||
|
@"<language-layout>
|
||||||
|
View With Layout
|
||||||
|
</language-layout>";
|
||||||
|
|
||||||
|
yield return new[] { "gb", expected1 };
|
||||||
|
yield return new[] { "na", expected1 };
|
||||||
|
|
||||||
|
var expected2 =
|
||||||
|
@"<fr-language-layout>
|
||||||
|
View With Layout
|
||||||
|
</fr-language-layout>";
|
||||||
|
yield return new[] { "fr", expected2 };
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(RazorViewEngine_UsesExpandersForLayoutsData))]
|
||||||
|
public async Task RazorViewEngine_UsesExpandersForLayouts(string value, string expected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = await client.GetStringAsync("http://localhost/TemplateExpander/ViewWithLayout?language-expander-value=" +
|
||||||
|
value);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, body.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
// Inheritance of chunks in _ViewStart is affected by paths being app-relative and not absolute.
|
// Inheritance of chunks in _ViewStart is affected by paths being app-relative and not absolute.
|
||||||
// This change ensures that _ViewStart files correctly inherits directives from parent _ViewStarts
|
// This change ensures that _ViewStart files correctly inherits directives from parent _ViewStarts
|
||||||
// which guarantees that paths flow correctly through MvcRazorHost.
|
// which guarantees that paths flow correctly through MvcRazorHost.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// 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.
|
// 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.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNet.Mvc.Razor.OptionDescriptors;
|
using Microsoft.AspNet.Mvc.Razor.OptionDescriptors;
|
||||||
|
|
@ -38,6 +37,33 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<object[]> ViewLocationExpanderTestData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
_controllerTestContext,
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
"/Views/{1}/{0}.cshtml",
|
||||||
|
"/Views/Shared/{0}.cshtml"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
_areaTestContext,
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
"/Areas/{2}/Views/{1}/{0}.cshtml",
|
||||||
|
"/Areas/{2}/Views/Shared/{0}.cshtml",
|
||||||
|
"/Views/Shared/{0}.cshtml"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(null)]
|
[InlineData(null)]
|
||||||
[InlineData("")]
|
[InlineData("")]
|
||||||
|
|
@ -90,11 +116,13 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var pageFactory = new Mock<IRazorPageFactory>();
|
||||||
var viewFactory = new Mock<IRazorViewFactory>();
|
var viewFactory = new Mock<IRazorViewFactory>();
|
||||||
var page = Mock.Of<IRazorPage>();
|
var page = Mock.Of<IRazorPage>();
|
||||||
|
var view = Mock.Of<IView>();
|
||||||
|
|
||||||
pageFactory.Setup(p => p.CreateInstance(It.IsAny<string>()))
|
pageFactory.Setup(p => p.CreateInstance(It.IsAny<string>()))
|
||||||
.Returns(Mock.Of<IRazorPage>());
|
.Returns(Mock.Of<IRazorPage>());
|
||||||
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorPage>(), It.IsAny<bool>()))
|
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorViewEngine>(), It.IsAny<IRazorPage>(), true))
|
||||||
.Returns(Mock.Of<IView>()).Verifiable();
|
.Returns(view)
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
var viewEngine = CreateViewEngine(pageFactory.Object, viewFactory.Object);
|
var viewEngine = CreateViewEngine(pageFactory.Object, viewFactory.Object);
|
||||||
var context = GetActionContext(_controllerTestContext);
|
var context = GetActionContext(_controllerTestContext);
|
||||||
|
|
@ -104,8 +132,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(result.Success);
|
Assert.True(result.Success);
|
||||||
Assert.IsAssignableFrom<IView>(result.View);
|
Assert.Same(view, result.View);
|
||||||
Assert.Equal("/Views/bar/test-view.cshtml", result.ViewName);
|
Assert.Equal("test-view", result.ViewName);
|
||||||
viewFactory.Verify();
|
viewFactory.Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,11 +266,13 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var pageFactory = new Mock<IRazorPageFactory>();
|
||||||
var viewFactory = new Mock<IRazorViewFactory>();
|
var viewFactory = new Mock<IRazorViewFactory>();
|
||||||
var page = Mock.Of<IRazorPage>();
|
var page = Mock.Of<IRazorPage>();
|
||||||
|
var view = Mock.Of<IView>();
|
||||||
|
|
||||||
pageFactory.Setup(p => p.CreateInstance(It.IsAny<string>()))
|
pageFactory.Setup(p => p.CreateInstance(It.IsAny<string>()))
|
||||||
.Returns(Mock.Of<IRazorPage>());
|
.Returns(Mock.Of<IRazorPage>());
|
||||||
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorPage>(), It.IsAny<bool>()))
|
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorViewEngine>(), It.IsAny<IRazorPage>(), false))
|
||||||
.Returns(Mock.Of<IView>()).Verifiable();
|
.Returns(view)
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
var viewEngine = CreateViewEngine(pageFactory.Object, viewFactory.Object);
|
var viewEngine = CreateViewEngine(pageFactory.Object, viewFactory.Object);
|
||||||
var context = GetActionContext(_controllerTestContext);
|
var context = GetActionContext(_controllerTestContext);
|
||||||
|
|
@ -252,8 +282,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(result.Success);
|
Assert.True(result.Success);
|
||||||
Assert.IsAssignableFrom<IView>(result.View);
|
Assert.Same(view, result.View);
|
||||||
Assert.Equal("/Views/bar/test-view.cshtml", result.ViewName);
|
Assert.Equal("test-view", result.ViewName);
|
||||||
viewFactory.Verify();
|
viewFactory.Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,35 +333,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
pageFactory.Verify();
|
pageFactory.Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<object[]> FindView_UsesViewLocationExpandersToLocateViewsData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
yield return new object[]
|
|
||||||
{
|
|
||||||
_controllerTestContext,
|
|
||||||
new[]
|
|
||||||
{
|
|
||||||
"/Views/{1}/{0}.cshtml",
|
|
||||||
"/Views/Shared/{0}.cshtml"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
yield return new object[]
|
|
||||||
{
|
|
||||||
_areaTestContext,
|
|
||||||
new[]
|
|
||||||
{
|
|
||||||
"/Areas/{2}/Views/{1}/{0}.cshtml",
|
|
||||||
"/Areas/{2}/Views/Shared/{0}.cshtml",
|
|
||||||
"/Views/Shared/{0}.cshtml"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(FindView_UsesViewLocationExpandersToLocateViewsData))]
|
[MemberData(nameof(ViewLocationExpanderTestData))]
|
||||||
public void FindView_UsesViewLocationExpandersToLocateViews(IDictionary<string, object> routeValues,
|
public void FindView_UsesViewLocationExpandersToLocateViews(IDictionary<string, object> routeValues,
|
||||||
IEnumerable<string> expectedSeeds)
|
IEnumerable<string> expectedSeeds)
|
||||||
{
|
{
|
||||||
|
|
@ -342,7 +345,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
||||||
var viewFactory = new Mock<IRazorViewFactory>();
|
var viewFactory = new Mock<IRazorViewFactory>();
|
||||||
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorPage>(), It.IsAny<bool>()))
|
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorViewEngine>(), It.IsAny<IRazorPage>(), It.IsAny<bool>()))
|
||||||
.Returns(Mock.Of<IView>());
|
.Returns(Mock.Of<IView>());
|
||||||
|
|
||||||
var expander1Result = new[] { "some-seed" };
|
var expander1Result = new[] { "some-seed" };
|
||||||
|
|
@ -376,7 +379,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
|
|
||||||
var viewEngine = CreateViewEngine(pageFactory.Object, viewFactory.Object,
|
var viewEngine = CreateViewEngine(pageFactory.Object, viewFactory.Object,
|
||||||
new[] { expander1.Object, expander2.Object });
|
new[] { expander1.Object, expander2.Object });
|
||||||
var context = GetActionContext(routeValues, viewFactory.Object);
|
var context = GetActionContext(routeValues);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = viewEngine.FindView(context, "test-view");
|
var result = viewEngine.FindView(context, "test-view");
|
||||||
|
|
@ -401,17 +404,17 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
||||||
var viewFactory = new Mock<IRazorViewFactory>();
|
var viewFactory = new Mock<IRazorViewFactory>();
|
||||||
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorPage>(), It.IsAny<bool>()))
|
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorViewEngine>(), It.IsAny<IRazorPage>(), false))
|
||||||
.Returns(Mock.Of<IView>());
|
.Returns(Mock.Of<IView>());
|
||||||
|
|
||||||
var cache = GetViewLocationCache();
|
var cache = GetViewLocationCache();
|
||||||
var cacheMock = Mock.Get<IViewLocationCache>(cache);
|
var cacheMock = Mock.Get(cache);
|
||||||
|
|
||||||
cacheMock.Setup(c => c.Set(It.IsAny<ViewLocationExpanderContext>(), "/Views/Shared/baz.cshtml"))
|
cacheMock.Setup(c => c.Set(It.IsAny<ViewLocationExpanderContext>(), "/Views/Shared/baz.cshtml"))
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
||||||
var viewEngine = CreateViewEngine(pageFactory.Object, viewFactory.Object, cache: cache);
|
var viewEngine = CreateViewEngine(pageFactory.Object, viewFactory.Object, cache: cache);
|
||||||
var context = GetActionContext(_controllerTestContext, viewFactory.Object);
|
var context = GetActionContext(_controllerTestContext);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = viewEngine.FindView(context, "baz");
|
var result = viewEngine.FindView(context, "baz");
|
||||||
|
|
@ -432,7 +435,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
||||||
var viewFactory = new Mock<IRazorViewFactory>();
|
var viewFactory = new Mock<IRazorViewFactory>();
|
||||||
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorPage>(), It.IsAny<bool>()))
|
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorViewEngine>(), It.IsAny<IRazorPage>(), false))
|
||||||
.Returns(Mock.Of<IView>());
|
.Returns(Mock.Of<IView>());
|
||||||
|
|
||||||
var expander = new Mock<IViewLocationExpander>(MockBehavior.Strict);
|
var expander = new Mock<IViewLocationExpander>(MockBehavior.Strict);
|
||||||
|
|
@ -472,7 +475,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
||||||
var viewFactory = new Mock<IRazorViewFactory>();
|
var viewFactory = new Mock<IRazorViewFactory>();
|
||||||
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorPage>(), It.IsAny<bool>())).Returns(Mock.Of<IView>());
|
viewFactory.Setup(p => p.GetView(It.IsAny<IRazorViewEngine>(), It.IsAny<IRazorPage>(), false))
|
||||||
|
.Returns(Mock.Of<IView>());
|
||||||
|
|
||||||
var cacheMock = new Mock<IViewLocationCache>();
|
var cacheMock = new Mock<IViewLocationCache>();
|
||||||
cacheMock.Setup(c => c.Get(It.IsAny<ViewLocationExpanderContext>()))
|
cacheMock.Setup(c => c.Get(It.IsAny<ViewLocationExpanderContext>()))
|
||||||
|
|
@ -491,7 +495,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
viewFactory.Object,
|
viewFactory.Object,
|
||||||
expanders: new[] { expander.Object },
|
expanders: new[] { expander.Object },
|
||||||
cache: cacheMock.Object);
|
cache: cacheMock.Object);
|
||||||
var context = GetActionContext(_controllerTestContext, viewFactory.Object);
|
var context = GetActionContext(_controllerTestContext);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = viewEngine.FindView(context, "baz");
|
var result = viewEngine.FindView(context, "baz");
|
||||||
|
|
@ -503,10 +507,97 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
expander.Verify();
|
expander.Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IViewEngine CreateViewEngine(IRazorPageFactory pageFactory = null,
|
[Theory]
|
||||||
IRazorViewFactory viewFactory = null,
|
[InlineData(null)]
|
||||||
IEnumerable<IViewLocationExpander> expanders = null,
|
[InlineData("")]
|
||||||
IViewLocationCache cache = null)
|
public void FindPage_ThrowsIfNameIsNullOrEmpty(string pageName)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var viewEngine = CreateViewEngine();
|
||||||
|
var context = GetActionContext(_controllerTestContext);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
ExceptionAssert.ThrowsArgumentNullOrEmpty(() => viewEngine.FindPage(context, pageName),
|
||||||
|
"pageName");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(ViewLocationExpanderTestData))]
|
||||||
|
public void FindPage_UsesViewLocationExpander_ToExpandPaths(IDictionary<string, object> routeValues,
|
||||||
|
IEnumerable<string> expectedSeeds)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var page = Mock.Of<IRazorPage>();
|
||||||
|
var pageFactory = new Mock<IRazorPageFactory>();
|
||||||
|
pageFactory.Setup(p => p.CreateInstance("expanded-path/bar-layout"))
|
||||||
|
.Returns(page)
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
|
var viewFactory = new Mock<IRazorViewFactory>(MockBehavior.Strict);
|
||||||
|
|
||||||
|
var expander = new Mock<IViewLocationExpander>();
|
||||||
|
expander.Setup(e => e.PopulateValues(It.IsAny<ViewLocationExpanderContext>()))
|
||||||
|
.Callback((ViewLocationExpanderContext c) =>
|
||||||
|
{
|
||||||
|
Assert.NotNull(c.ActionContext);
|
||||||
|
c.Values["expander-key"] = expander.ToString();
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
expander.Setup(e => e.ExpandViewLocations(It.IsAny<ViewLocationExpanderContext>(),
|
||||||
|
It.IsAny<IEnumerable<string>>()))
|
||||||
|
.Returns((ViewLocationExpanderContext c, IEnumerable<string> seeds) =>
|
||||||
|
{
|
||||||
|
Assert.NotNull(c.ActionContext);
|
||||||
|
Assert.Equal(expectedSeeds, seeds);
|
||||||
|
|
||||||
|
Assert.Equal(expander.ToString(), c.Values["expander-key"]);
|
||||||
|
|
||||||
|
return new[] { "expanded-path/bar-{0}" };
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
|
var viewEngine = CreateViewEngine(pageFactory.Object, viewFactory.Object,
|
||||||
|
new[] { expander.Object });
|
||||||
|
var context = GetActionContext(routeValues);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = viewEngine.FindPage(context, "layout");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("layout", result.Name);
|
||||||
|
Assert.Same(page, result.Page);
|
||||||
|
Assert.Null(result.SearchedLocations);
|
||||||
|
pageFactory.Verify();
|
||||||
|
expander.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindPage_ReturnsSearchedLocationsIfPageCannotBeFound()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = new[]
|
||||||
|
{
|
||||||
|
"/Views/bar/layout.cshtml",
|
||||||
|
"/Views/Shared/layout.cshtml",
|
||||||
|
};
|
||||||
|
var page = Mock.Of<IRazorPage>();
|
||||||
|
|
||||||
|
var viewEngine = CreateViewEngine();
|
||||||
|
var context = GetActionContext(_controllerTestContext);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = viewEngine.FindPage(context, "layout");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("layout", result.Name);
|
||||||
|
Assert.Null(result.Page);
|
||||||
|
Assert.Equal(expected, result.SearchedLocations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RazorViewEngine CreateViewEngine(IRazorPageFactory pageFactory = null,
|
||||||
|
IRazorViewFactory viewFactory = null,
|
||||||
|
IEnumerable<IViewLocationExpander> expanders = null,
|
||||||
|
IViewLocationCache cache = null)
|
||||||
{
|
{
|
||||||
pageFactory = pageFactory ?? Mock.Of<IRazorPageFactory>();
|
pageFactory = pageFactory ?? Mock.Of<IRazorPageFactory>();
|
||||||
viewFactory = viewFactory ?? Mock.Of<IRazorViewFactory>();
|
viewFactory = viewFactory ?? Mock.Of<IRazorViewFactory>();
|
||||||
|
|
@ -541,14 +632,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
return cacheMock.Object;
|
return cacheMock.Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionContext GetActionContext(IDictionary<string, object> routeValues,
|
private static ActionContext GetActionContext(IDictionary<string, object> routeValues)
|
||||||
IRazorViewFactory razorViewFactory = null)
|
|
||||||
{
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
var serviceProvider = new Mock<IServiceProvider>();
|
|
||||||
|
|
||||||
httpContext.RequestServices = serviceProvider.Object;
|
|
||||||
|
|
||||||
var routeData = new RouteData();
|
var routeData = new RouteData();
|
||||||
foreach (var kvp in routeValues)
|
foreach (var kvp in routeValues)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,10 @@
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor.Test
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
public class RazorViewFactoryTest
|
public class RazorViewFactoryTest
|
||||||
{
|
{
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(false)]
|
[InlineData(false)]
|
||||||
[InlineData(true)]
|
[InlineData(true)]
|
||||||
|
|
@ -16,15 +15,17 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var factory = new RazorViewFactory(
|
var factory = new RazorViewFactory(
|
||||||
Mock.Of<IRazorPageFactory>(),
|
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
Mock.Of<IViewStartProvider>());
|
Mock.Of<IViewStartProvider>());
|
||||||
|
var page = Mock.Of<IRazorPage>();
|
||||||
|
var viewEngine = Mock.Of<IRazorViewEngine>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var view = factory.GetView(Mock.Of<IRazorPage>(), isPartial);
|
var view = factory.GetView(viewEngine, page, isPartial);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var razorView = Assert.IsType<RazorView>(view);
|
var razorView = Assert.IsType<RazorView>(view);
|
||||||
|
Assert.Same(page, razorView.RazorPage);
|
||||||
Assert.Equal(razorView.IsPartial, isPartial);
|
Assert.Equal(razorView.IsPartial, isPartial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,18 +34,19 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var factory = new RazorViewFactory(
|
var factory = new RazorViewFactory(
|
||||||
Mock.Of<IRazorPageFactory>(),
|
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
Mock.Of<IViewStartProvider>());
|
Mock.Of<IViewStartProvider>());
|
||||||
|
|
||||||
var page = Mock.Of<IRazorPage>();
|
var page = Mock.Of<IRazorPage>();
|
||||||
|
var viewEngine = Mock.Of<IRazorViewEngine>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var view = factory.GetView(page, isPartial: false) as RazorView;
|
var view = factory.GetView(viewEngine, page, isPartial: false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(view);
|
Assert.NotNull(view);
|
||||||
Assert.Same(view.RazorPage, page);
|
var razorView = Assert.IsType<RazorView>(view);
|
||||||
|
Assert.Same(razorView.RazorPage, page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
actual = v.Output;
|
actual = v.Output;
|
||||||
v.Write("Hello world");
|
v.Write("Hello world");
|
||||||
});
|
});
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -55,7 +55,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
Assert.Same(viewData, v.ViewContext.ViewData);
|
Assert.Same(viewData, v.ViewContext.ViewData);
|
||||||
});
|
});
|
||||||
var activator = new Mock<IRazorPageActivator>();
|
var activator = new Mock<IRazorPageActivator>();
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
activator.Object,
|
activator.Object,
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -87,7 +87,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
var activator = new Mock<IRazorPageActivator>();
|
var activator = new Mock<IRazorPageActivator>();
|
||||||
activator.Setup(a => a.Activate(page, It.IsAny<ViewContext>()))
|
activator.Setup(a => a.Activate(page, It.IsAny<ViewContext>()))
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
activator.Object,
|
activator.Object,
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -108,9 +108,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
v.Layout = LayoutPath;
|
v.Layout = LayoutPath;
|
||||||
});
|
});
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
var viewStartProvider = CreateViewStartProvider();
|
var viewStartProvider = CreateViewStartProvider();
|
||||||
var view = new RazorView(pageFactory.Object,
|
var view = new RazorView(viewEngine.Object,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
viewStartProvider,
|
viewStartProvider,
|
||||||
page,
|
page,
|
||||||
|
|
@ -121,7 +121,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
await view.RenderAsync(viewContext);
|
await view.RenderAsync(viewContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
pageFactory.Verify(v => v.CreateInstance(It.IsAny<string>()), Times.Never());
|
viewEngine.Verify(v => v.FindPage(It.IsAny<ActionContext>(), It.IsAny<string>()),
|
||||||
|
Times.Never());
|
||||||
Mock.Get(viewStartProvider)
|
Mock.Get(viewStartProvider)
|
||||||
.Verify(v => v.GetViewStartPages(It.IsAny<string>()), Times.Never());
|
.Verify(v => v.GetViewStartPages(It.IsAny<string>()), Times.Never());
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +136,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
actual = v.Output;
|
actual = v.Output;
|
||||||
});
|
});
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -159,7 +160,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
v.WriteLiteral("Hello world");
|
v.WriteLiteral("Hello world");
|
||||||
});
|
});
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -185,7 +186,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
var activator = new Mock<IRazorPageActivator>();
|
var activator = new Mock<IRazorPageActivator>();
|
||||||
activator.Setup(a => a.Activate(page, It.IsAny<ViewContext>()))
|
activator.Setup(a => a.Activate(page, It.IsAny<ViewContext>()))
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
activator.Object,
|
activator.Object,
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -227,7 +228,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
activator.Setup(a => a.Activate(page, It.IsAny<ViewContext>()))
|
activator.Setup(a => a.Activate(page, It.IsAny<ViewContext>()))
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
activator.Object,
|
activator.Object,
|
||||||
CreateViewStartProvider(viewStart1, viewStart2),
|
CreateViewStartProvider(viewStart1, viewStart2),
|
||||||
page,
|
page,
|
||||||
|
|
@ -241,6 +242,42 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
activator.Verify();
|
activator.Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RenderAsync_ThrowsIfLayoutPageCannotBeFound()
|
||||||
|
{
|
||||||
|
// 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>();
|
||||||
|
var activator = new Mock<IRazorPageActivator>();
|
||||||
|
var view = new RazorView(viewEngine.Object,
|
||||||
|
Mock.Of<IRazorPageActivator>(),
|
||||||
|
Mock.Of<IViewStartProvider>(),
|
||||||
|
page,
|
||||||
|
isPartial: false);
|
||||||
|
var viewContext = CreateViewContext(view);
|
||||||
|
viewEngine.Setup(v => v.FindPage(viewContext, layoutPath))
|
||||||
|
.Returns(new RazorPageResult(layoutPath, new[] { "path1", "path2" }))
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => view.RenderAsync(viewContext));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, ex.Message);
|
||||||
|
viewEngine.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RenderAsync_ExecutesLayoutPages()
|
public async Task RenderAsync_ExecutesLayoutPages()
|
||||||
{
|
{
|
||||||
|
|
@ -278,16 +315,17 @@ foot-content";
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
activator.Setup(a => a.Activate(layout, It.IsAny<ViewContext>()))
|
activator.Setup(a => a.Activate(layout, It.IsAny<ViewContext>()))
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
pageFactory.Setup(p => p.CreateInstance(LayoutPath))
|
|
||||||
.Returns(layout);
|
|
||||||
|
|
||||||
var view = new RazorView(pageFactory.Object,
|
var view = new RazorView(viewEngine.Object,
|
||||||
activator.Object,
|
activator.Object,
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
isPartial: false);
|
isPartial: false);
|
||||||
var viewContext = CreateViewContext(view);
|
var viewContext = CreateViewContext(view);
|
||||||
|
viewEngine.Setup(p => p.FindPage(viewContext, LayoutPath))
|
||||||
|
.Returns(new RazorPageResult(LayoutPath, layout))
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await view.RenderAsync(viewContext);
|
await view.RenderAsync(viewContext);
|
||||||
|
|
@ -296,6 +334,7 @@ foot-content";
|
||||||
// Verify the activator was invoked for the primary page and layout page.
|
// Verify the activator was invoked for the primary page and layout page.
|
||||||
activator.Verify();
|
activator.Verify();
|
||||||
Assert.Equal(expected, viewContext.Writer.ToString());
|
Assert.Equal(expected, viewContext.Writer.ToString());
|
||||||
|
viewEngine.Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -312,11 +351,11 @@ foot-content";
|
||||||
{
|
{
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
});
|
});
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
pageFactory.Setup(p => p.CreateInstance(LayoutPath))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), LayoutPath))
|
||||||
.Returns(layout);
|
.Returns(new RazorPageResult(LayoutPath, layout));
|
||||||
|
|
||||||
var view = new RazorView(pageFactory.Object,
|
var view = new RazorView(viewEngine.Object,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -339,11 +378,11 @@ foot-content";
|
||||||
var layout = new TestableRazorPage(v =>
|
var layout = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
});
|
});
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
pageFactory.Setup(p => p.CreateInstance(LayoutPath))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), LayoutPath))
|
||||||
.Returns(layout);
|
.Returns(new RazorPageResult(LayoutPath, layout));
|
||||||
|
|
||||||
var view = new RazorView(pageFactory.Object,
|
var view = new RazorView(viewEngine.Object,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -389,13 +428,13 @@ body-content";
|
||||||
v.Write(v.RenderSection("bar"));
|
v.Write(v.RenderSection("bar"));
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
});
|
});
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
pageFactory.Setup(p => p.CreateInstance("~/Shared/Layout1.cshtml"))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "~/Shared/Layout1.cshtml"))
|
||||||
.Returns(layout1);
|
.Returns(new RazorPageResult("~/Shared/Layout1.cshtml", layout1));
|
||||||
pageFactory.Setup(p => p.CreateInstance("~/Shared/Layout2.cshtml"))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "~/Shared/Layout2.cshtml"))
|
||||||
.Returns(layout2);
|
.Returns(new RazorPageResult("~/Shared/Layout2.cshtml", layout2));
|
||||||
|
|
||||||
var view = new RazorView(pageFactory.Object,
|
var view = new RazorView(viewEngine.Object,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -438,11 +477,11 @@ section-content-2";
|
||||||
v.Write(v.RenderSection("foo"));
|
v.Write(v.RenderSection("foo"));
|
||||||
});
|
});
|
||||||
|
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
pageFactory.Setup(p => p.CreateInstance("layout-1"))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "layout-1"))
|
||||||
.Returns(layout1);
|
.Returns(new RazorPageResult("layout-1", layout1));
|
||||||
|
|
||||||
var view = new RazorView(pageFactory.Object,
|
var view = new RazorView(viewEngine.Object,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -483,11 +522,11 @@ section-content-2";
|
||||||
v.Write(v.RenderSection("foo"));
|
v.Write(v.RenderSection("foo"));
|
||||||
});
|
});
|
||||||
|
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
pageFactory.Setup(p => p.CreateInstance("layout-1"))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "layout-1"))
|
||||||
.Returns(layout1);
|
.Returns(new RazorPageResult("layout-1", layout1));
|
||||||
|
|
||||||
var view = new RazorView(pageFactory.Object,
|
var view = new RazorView(viewEngine.Object,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -514,7 +553,7 @@ section-content-2";
|
||||||
v.WriteLiteral("after-flush");
|
v.WriteLiteral("after-flush");
|
||||||
});
|
});
|
||||||
|
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -541,7 +580,7 @@ section-content-2";
|
||||||
v.Layout = "~/Shared/Layout1.cshtml";
|
v.Layout = "~/Shared/Layout1.cshtml";
|
||||||
v.WriteLiteral("body-content");
|
v.WriteLiteral("body-content");
|
||||||
});
|
});
|
||||||
var layout1 = new TestableRazorPage(v =>
|
var layoutPage = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
v.Write("layout-1" + Environment.NewLine);
|
v.Write("layout-1" + Environment.NewLine);
|
||||||
v.Write(v.RenderSection("foo"));
|
v.Write(v.RenderSection("foo"));
|
||||||
|
|
@ -549,11 +588,12 @@ section-content-2";
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
v.Layout = "~/Shared/Layout2.cshtml";
|
v.Layout = "~/Shared/Layout2.cshtml";
|
||||||
});
|
});
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
pageFactory.Setup(p => p.CreateInstance("~/Shared/Layout1.cshtml"))
|
var layoutPath = "~/Shared/Layout1.cshtml";
|
||||||
.Returns(layout1);
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), layoutPath))
|
||||||
|
.Returns(new RazorPageResult(layoutPath, layoutPage));
|
||||||
|
|
||||||
var view = new RazorView(pageFactory.Object,
|
var view = new RazorView(viewEngine.Object,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -603,7 +643,7 @@ section-content-2";
|
||||||
|
|
||||||
var page = new TestableRazorPage(v =>
|
var page = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
v.Layout = "/Layout.cshtml";
|
v.Layout = "Layout";
|
||||||
Assert.Same(pageWriter, v.Output);
|
Assert.Same(pageWriter, v.Output);
|
||||||
Assert.Same(pageContext, v.PageExecutionContext);
|
Assert.Same(pageContext, v.PageExecutionContext);
|
||||||
});
|
});
|
||||||
|
|
@ -619,14 +659,14 @@ section-content-2";
|
||||||
});
|
});
|
||||||
layout.Path = "/Layout.cshtml";
|
layout.Path = "/Layout.cshtml";
|
||||||
|
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
pageFactory.Setup(p => p.CreateInstance("/Layout.cshtml"))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "Layout"))
|
||||||
.Returns(layout);
|
.Returns(new RazorPageResult("Layout", layout));
|
||||||
var viewStartProvider = new Mock<IViewStartProvider>();
|
var viewStartProvider = new Mock<IViewStartProvider>();
|
||||||
viewStartProvider.Setup(v => v.GetViewStartPages(It.IsAny<string>()))
|
viewStartProvider.Setup(v => v.GetViewStartPages(It.IsAny<string>()))
|
||||||
.Returns(Enumerable.Empty<IRazorPage>())
|
.Returns(Enumerable.Empty<IRazorPage>())
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
var view = new RazorView(pageFactory.Object,
|
var view = new RazorView(viewEngine.Object,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
viewStartProvider.Object,
|
viewStartProvider.Object,
|
||||||
page,
|
page,
|
||||||
|
|
@ -670,7 +710,7 @@ section-content-2";
|
||||||
});
|
});
|
||||||
page.Path = "/MyPartialPage.cshtml";
|
page.Path = "/MyPartialPage.cshtml";
|
||||||
|
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
Mock.Of<IViewStartProvider>(),
|
Mock.Of<IViewStartProvider>(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -701,7 +741,7 @@ section-content-2";
|
||||||
executed = true;
|
executed = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
Mock.Of<IViewStartProvider>(),
|
Mock.Of<IViewStartProvider>(),
|
||||||
page,
|
page,
|
||||||
|
|
@ -738,9 +778,9 @@ section-content-2";
|
||||||
actualViewStart = v.Layout;
|
actualViewStart = v.Layout;
|
||||||
v.Layout = expectedPage;
|
v.Layout = expectedPage;
|
||||||
});
|
});
|
||||||
var pageFactory = Mock.Of<IRazorPageFactory>();
|
var viewEngine = Mock.Of<IRazorViewEngine>();
|
||||||
|
|
||||||
var view = new RazorView(pageFactory,
|
var view = new RazorView(viewEngine,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(viewStart1, viewStart2),
|
CreateViewStartProvider(viewStart1, viewStart2),
|
||||||
page,
|
page,
|
||||||
|
|
@ -775,9 +815,9 @@ section-content-2";
|
||||||
actual = v.Layout;
|
actual = v.Layout;
|
||||||
v.Layout = null;
|
v.Layout = null;
|
||||||
});
|
});
|
||||||
var pageFactory = Mock.Of<IRazorPageFactory>();
|
var viewEngine = Mock.Of<IRazorViewEngine>();
|
||||||
|
|
||||||
var view = new RazorView(pageFactory,
|
var view = new RazorView(viewEngine,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(viewStart1, viewStart2),
|
CreateViewStartProvider(viewStart1, viewStart2),
|
||||||
page,
|
page,
|
||||||
|
|
@ -813,11 +853,11 @@ section-content-2";
|
||||||
isPartialLayout = v.IsPartial;
|
isPartialLayout = v.IsPartial;
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
});
|
});
|
||||||
var pageFactory = new Mock<IRazorPageFactory>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
pageFactory.Setup(p => p.CreateInstance("/Layout.cshtml"))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "/Layout.cshtml"))
|
||||||
.Returns(layout);
|
.Returns(new RazorPageResult("Layout", layout));
|
||||||
|
|
||||||
var view = new RazorView(pageFactory.Object,
|
var view = new RazorView(viewEngine.Object,
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(viewStart),
|
CreateViewStartProvider(viewStart),
|
||||||
page,
|
page,
|
||||||
|
|
@ -842,7 +882,7 @@ section-content-2";
|
||||||
{
|
{
|
||||||
isPartialPage = v.IsPartial;
|
isPartialPage = v.IsPartial;
|
||||||
});
|
});
|
||||||
var view = new RazorView(Mock.Of<IRazorPageFactory>(),
|
var view = new RazorView(Mock.Of<IRazorViewEngine>(),
|
||||||
Mock.Of<IRazorPageActivator>(),
|
Mock.Of<IRazorPageActivator>(),
|
||||||
CreateViewStartProvider(),
|
CreateViewStartProvider(),
|
||||||
page,
|
page,
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,10 @@ namespace RazorWebSite.Controllers
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ViewResult ViewWithLayout()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace RazorWebSite.Controllers
|
||||||
|
{
|
||||||
|
public class ViewNameSpecification_HomeController : Controller
|
||||||
|
{
|
||||||
|
public IActionResult LayoutSpecifiedWithPartialPathInViewStart()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult LayoutSpecifiedWithPartialPathInViewStart_ForViewSpecifiedWithPartialName()
|
||||||
|
{
|
||||||
|
return View("LayoutSpecifiedWithPartialPathInViewStart");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult LayoutSpecifiedWithPartialPathInViewStart_ForViewSpecifiedWithAppRelativePath()
|
||||||
|
{
|
||||||
|
return View("~/Views/ViewNameSpecification_Home/LayoutSpecifiedWithPartialPathInViewStart");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult LayoutSpecifiedWithPartialPathInViewStart_ForViewSpecifiedWithAppRelativePathWithExtension()
|
||||||
|
{
|
||||||
|
return View("~/Views/ViewNameSpecification_Home/LayoutSpecifiedWithPartialPathInViewStart.cshtml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult LayoutSpecifiedWithPartialPathInPage()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult LayoutSpecifiedWithPartialPathInPageWithPartialPath()
|
||||||
|
{
|
||||||
|
return View("LayoutSpecifiedWithPartialPathInPage");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult LayoutSpecifiedWithPartialPathInPageWithAppRelativePath()
|
||||||
|
{
|
||||||
|
return View("~/Views/ViewNameSpecification_Home/LayoutSpecifiedWithPartialPathInPage");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult LayoutSpecifiedWithPartialPathInPageWithAppRelativePathWithExtension()
|
||||||
|
{
|
||||||
|
return View("~/Views/ViewNameSpecification_Home/LayoutSpecifiedWithPartialPathInPage.cshtml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult LayoutSpecifiedWithNonPartialPath()
|
||||||
|
{
|
||||||
|
ViewData["Layout"] = "~/Views/ViewNameSpecification_Home/_NonSharedLayout";
|
||||||
|
return View("PageWithNonPartialLayoutPath");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult LayoutSpecifiedWithNonPartialPathWithExtension()
|
||||||
|
{
|
||||||
|
ViewData["Layout"] = "~/Views/ViewNameSpecification_Home/_NonSharedLayout.cshtml";
|
||||||
|
return View("PageWithNonPartialLayoutPath");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult ViewWithPartial_SpecifiedWithPartialName()
|
||||||
|
{
|
||||||
|
ViewBag.Partial = "NonSharedPartial";
|
||||||
|
return View("ViewWithPartials");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult ViewWithPartial_SpecifiedWithAbsoluteName()
|
||||||
|
{
|
||||||
|
ViewBag.Partial = "~/Views/ViewNameSpecification_Home/NonSharedPartial";
|
||||||
|
return View("ViewWithPartials");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult ViewWithPartial_SpecifiedWithAbsoluteNameAndExtension()
|
||||||
|
{
|
||||||
|
ViewBag.Partial = "~/Views/ViewNameSpecification_Home/NonSharedPartial.cshtml";
|
||||||
|
return View("ViewWithPartials");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
@{
|
||||||
|
Layout = "_LanguageLayout";
|
||||||
|
}
|
||||||
|
View With Layout
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<language-layout>@RenderBody()</language-layout>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<fr-language-layout>@RenderBody()</fr-language-layout>
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
@{
|
||||||
|
Layout = "_NonSharedLayout";
|
||||||
|
}
|
||||||
|
Layout specified in page
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
_ViewStart that specifies partial Layout
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Non Shared Partial
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
@{
|
||||||
|
Layout = (string)ViewData["Layout"];
|
||||||
|
}
|
||||||
|
Page With Non Partial Layout
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
@{
|
||||||
|
var partial = (string)ViewData["Partial"];
|
||||||
|
}
|
||||||
|
@Html.Partial(partial)
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<non-shared>@RenderBody()</non-shared>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
@{
|
||||||
|
Layout = "_Layout";
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue